Skip to content

Commit 21c6d11

Browse files
committed
Handle overflow checks in central locations (#2697)
This removes multiple error variants and overall cleans up the codebase by moving overflow checks into two `ModelError` variants.
1 parent bfffba9 commit 21c6d11

22 files changed

+221
-224
lines changed

src/builder/create_embed.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,13 @@ impl<'a> CreateEmbed<'a> {
203203
}
204204

205205
#[cfg(feature = "http")]
206-
pub(super) fn check_length(&self) -> Result<()> {
206+
pub(super) fn get_length(&self) -> usize {
207207
let mut length = 0;
208-
if let Some(ref author) = self.author {
208+
if let Some(author) = &self.author {
209209
length += author.name.chars().count();
210210
}
211211

212-
if let Some(ref description) = self.description {
212+
if let Some(description) = &self.description {
213213
length += description.chars().count();
214214
}
215215

@@ -218,16 +218,15 @@ impl<'a> CreateEmbed<'a> {
218218
length += field.value.chars().count();
219219
}
220220

221-
if let Some(ref footer) = self.footer {
221+
if let Some(footer) = &self.footer {
222222
length += footer.text.chars().count();
223223
}
224224

225-
if let Some(ref title) = self.title {
225+
if let Some(title) = &self.title {
226226
length += title.chars().count();
227227
}
228228

229-
super::check_overflow(length, crate::constants::EMBED_MAX_LENGTH)
230-
.map_err(|overflow| Error::Model(ModelError::EmbedTooLarge(overflow)))
229+
length
231230
}
232231
}
233232

src/builder/create_interaction_response.rs

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::borrow::Cow;
22

33
#[cfg(feature = "http")]
4-
use super::{check_overflow, Builder};
4+
use super::Builder;
55
use super::{
66
CreateActionRow,
77
CreateAllowedMentions,
@@ -10,8 +10,6 @@ use super::{
1010
EditAttachments,
1111
};
1212
#[cfg(feature = "http")]
13-
use crate::constants;
14-
#[cfg(feature = "http")]
1513
use crate::http::CacheHttp;
1614
use crate::internal::prelude::*;
1715
use crate::json::{self, json};
@@ -101,26 +99,15 @@ impl serde::Serialize for CreateInteractionResponse<'_> {
10199

102100
impl CreateInteractionResponse<'_> {
103101
#[cfg(feature = "http")]
104-
fn check_length(&self) -> Result<()> {
102+
fn check_length(&self) -> Result<(), ModelError> {
105103
if let CreateInteractionResponse::Message(data)
106104
| CreateInteractionResponse::Defer(data)
107105
| CreateInteractionResponse::UpdateMessage(data) = self
108106
{
109-
if let Some(content) = &data.content {
110-
check_overflow(content.chars().count(), constants::MESSAGE_CODE_LIMIT)
111-
.map_err(|overflow| Error::Model(ModelError::MessageTooLong(overflow)))?;
112-
}
113-
114-
if let Some(embeds) = &data.embeds {
115-
check_overflow(embeds.len(), constants::EMBED_MAX_COUNT)
116-
.map_err(|_| Error::Model(ModelError::EmbedAmount))?;
117-
118-
for embed in embeds.iter() {
119-
embed.check_length()?;
120-
}
121-
}
107+
super::check_lengths(data.content.as_deref(), data.embeds.as_deref(), 0)
108+
} else {
109+
Ok(())
122110
}
123-
Ok(())
124111
}
125112
}
126113

src/builder/create_interaction_response_followup.rs

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::borrow::Cow;
22

33
#[cfg(feature = "http")]
4-
use super::{check_overflow, Builder};
4+
use super::Builder;
55
use super::{
66
CreateActionRow,
77
CreateAllowedMentions,
@@ -10,8 +10,6 @@ use super::{
1010
EditAttachments,
1111
};
1212
#[cfg(feature = "http")]
13-
use crate::constants;
14-
#[cfg(feature = "http")]
1513
use crate::http::CacheHttp;
1614
#[cfg(feature = "http")]
1715
use crate::internal::prelude::*;
@@ -44,19 +42,8 @@ impl<'a> CreateInteractionResponseFollowup<'a> {
4442
}
4543

4644
#[cfg(feature = "http")]
47-
fn check_length(&self) -> Result<()> {
48-
if let Some(content) = &self.content {
49-
check_overflow(content.chars().count(), constants::MESSAGE_CODE_LIMIT)
50-
.map_err(|overflow| Error::Model(ModelError::MessageTooLong(overflow)))?;
51-
}
52-
53-
check_overflow(self.embeds.len(), constants::EMBED_MAX_COUNT)
54-
.map_err(|_| Error::Model(ModelError::EmbedAmount))?;
55-
for embed in self.embeds.iter() {
56-
embed.check_length()?;
57-
}
58-
59-
Ok(())
45+
fn check_length(&self) -> Result<(), ModelError> {
46+
super::check_lengths(self.content.as_deref(), Some(&self.embeds), 0)
6047
}
6148

6249
/// Set the content of the message.

src/builder/create_message.rs

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::borrow::Cow;
22

33
#[cfg(feature = "http")]
4-
use super::{check_overflow, Builder};
4+
use super::Builder;
55
use super::{
66
CreateActionRow,
77
CreateAllowedMentions,
@@ -10,8 +10,6 @@ use super::{
1010
EditAttachments,
1111
};
1212
#[cfg(feature = "http")]
13-
use crate::constants;
14-
#[cfg(feature = "http")]
1513
use crate::http::CacheHttp;
1614
#[cfg(feature = "http")]
1715
use crate::internal::prelude::*;
@@ -83,22 +81,8 @@ impl<'a> CreateMessage<'a> {
8381
}
8482

8583
#[cfg(feature = "http")]
86-
fn check_length(&self) -> Result<()> {
87-
if let Some(content) = &self.content {
88-
check_overflow(content.chars().count(), constants::MESSAGE_CODE_LIMIT)
89-
.map_err(|overflow| Error::Model(ModelError::MessageTooLong(overflow)))?;
90-
}
91-
92-
check_overflow(self.embeds.len(), constants::EMBED_MAX_COUNT)
93-
.map_err(|_| Error::Model(ModelError::EmbedAmount))?;
94-
for embed in self.embeds.iter() {
95-
embed.check_length()?;
96-
}
97-
98-
check_overflow(self.sticker_ids.len(), constants::STICKER_MAX_COUNT)
99-
.map_err(|_| Error::Model(ModelError::StickerAmount))?;
100-
101-
Ok(())
84+
fn check_length(&self) -> Result<(), ModelError> {
85+
super::check_lengths(self.content.as_deref(), Some(&self.embeds), self.sticker_ids.len())
10286
}
10387

10488
/// Set the content of the message.
@@ -300,7 +284,7 @@ impl Builder for CreateMessage<'_> {
300284
///
301285
/// # Errors
302286
///
303-
/// Returns a [`ModelError::MessageTooLong`] if the message contents are over the above limits.
287+
/// Returns a [`ModelError::TooLarge`] if the message contents are over the above limits.
304288
///
305289
/// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
306290
/// lacks permission. Otherwise returns [`Error::Http`], as well as if invalid data is given.

src/builder/create_webhook.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ impl<'a> Builder for CreateWebhook<'a> {
6363
///
6464
/// # Errors
6565
///
66-
/// If the provided name is less than 2 characters, returns [`ModelError::NameTooShort`]. If it
67-
/// is more than 100 characters, returns [`ModelError::NameTooLong`].
66+
/// If the provided name is less than 2 characters, returns [`ModelError::TooSmall`]. If it
67+
/// is more than 100 characters, returns [`ModelError::TooLarge`].
6868
///
6969
/// Returns a [`Error::Http`] if the current user lacks permission, or if invalid data is
7070
/// given.
@@ -76,11 +76,8 @@ impl<'a> Builder for CreateWebhook<'a> {
7676
cache_http: impl CacheHttp,
7777
ctx: Self::Context<'_>,
7878
) -> Result<Self::Built> {
79-
if self.name.len() < 2 {
80-
return Err(Error::Model(ModelError::NameTooShort));
81-
} else if self.name.len() > 100 {
82-
return Err(Error::Model(ModelError::NameTooLong));
83-
}
79+
crate::model::error::Minimum::WebhookName.check_underflow(self.name.chars().count())?;
80+
crate::model::error::Maximum::WebhookName.check_overflow(self.name.chars().count())?;
8481

8582
cache_http.http().create_webhook(ctx, &self, self.audit_log_reason).await
8683
}

src/builder/edit_message.rs

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::borrow::Cow;
22

33
#[cfg(feature = "http")]
4-
use super::{check_overflow, Builder};
4+
use super::Builder;
55
use super::{
66
CreateActionRow,
77
CreateAllowedMentions,
@@ -10,8 +10,6 @@ use super::{
1010
EditAttachments,
1111
};
1212
#[cfg(feature = "http")]
13-
use crate::constants;
14-
#[cfg(feature = "http")]
1513
use crate::http::CacheHttp;
1614
#[cfg(feature = "http")]
1715
use crate::internal::prelude::*;
@@ -61,21 +59,8 @@ impl<'a> EditMessage<'a> {
6159
}
6260

6361
#[cfg(feature = "http")]
64-
fn check_length(&self) -> Result<()> {
65-
if let Some(content) = &self.content {
66-
check_overflow(content.chars().count(), constants::MESSAGE_CODE_LIMIT)
67-
.map_err(|overflow| Error::Model(ModelError::MessageTooLong(overflow)))?;
68-
}
69-
70-
if let Some(embeds) = &self.embeds {
71-
check_overflow(embeds.len(), constants::EMBED_MAX_COUNT)
72-
.map_err(|_| Error::Model(ModelError::EmbedAmount))?;
73-
for embed in embeds.iter() {
74-
embed.check_length()?;
75-
}
76-
}
77-
78-
Ok(())
62+
fn check_length(&self) -> Result<(), ModelError> {
63+
super::check_lengths(self.content.as_deref(), self.embeds.as_deref(), 0)
7964
}
8065

8166
/// Set the content of the message.
@@ -243,7 +228,7 @@ impl Builder for EditMessage<'_> {
243228
///
244229
/// # Errors
245230
///
246-
/// Returns a [`ModelError::MessageTooLong`] if the message contents are over the above limits.
231+
/// Returns a [`ModelError::TooLarge`] if the message contents are over the above limits.
247232
///
248233
/// Returns [`Error::Http`] if the user lacks permission, as well as if invalid data is given.
249234
///

src/builder/edit_webhook_message.rs

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::borrow::Cow;
22

33
#[cfg(feature = "http")]
4-
use super::{check_overflow, Builder};
4+
use super::Builder;
55
use super::{
66
CreateActionRow,
77
CreateAllowedMentions,
@@ -10,8 +10,6 @@ use super::{
1010
EditAttachments,
1111
};
1212
#[cfg(feature = "http")]
13-
use crate::constants;
14-
#[cfg(feature = "http")]
1513
use crate::http::CacheHttp;
1614
#[cfg(feature = "http")]
1715
use crate::internal::prelude::*;
@@ -45,21 +43,8 @@ impl<'a> EditWebhookMessage<'a> {
4543
}
4644

4745
#[cfg(feature = "http")]
48-
pub(crate) fn check_length(&self) -> Result<()> {
49-
if let Some(content) = &self.content {
50-
check_overflow(content.chars().count(), constants::MESSAGE_CODE_LIMIT)
51-
.map_err(|overflow| Error::Model(ModelError::MessageTooLong(overflow)))?;
52-
}
53-
54-
if let Some(embeds) = &self.embeds {
55-
check_overflow(embeds.len(), constants::EMBED_MAX_COUNT)
56-
.map_err(|_| Error::Model(ModelError::EmbedAmount))?;
57-
for embed in embeds.iter() {
58-
embed.check_length()?;
59-
}
60-
}
61-
62-
Ok(())
46+
pub(crate) fn check_length(&self) -> Result<(), ModelError> {
47+
super::check_lengths(self.content.as_deref(), self.embeds.as_deref(), 0)
6348
}
6449

6550
/// Set the content of the message.

src/builder/execute_webhook.rs

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::borrow::Cow;
22

33
#[cfg(feature = "http")]
4-
use super::{check_overflow, Builder};
4+
use super::Builder;
55
use super::{
66
CreateActionRow,
77
CreateAllowedMentions,
@@ -10,8 +10,6 @@ use super::{
1010
EditAttachments,
1111
};
1212
#[cfg(feature = "http")]
13-
use crate::constants;
14-
#[cfg(feature = "http")]
1513
use crate::http::CacheHttp;
1614
#[cfg(feature = "http")]
1715
use crate::internal::prelude::*;
@@ -90,19 +88,8 @@ impl<'a> ExecuteWebhook<'a> {
9088
}
9189

9290
#[cfg(feature = "http")]
93-
fn check_length(&self) -> Result<()> {
94-
if let Some(content) = &self.content {
95-
check_overflow(content.chars().count(), constants::MESSAGE_CODE_LIMIT)
96-
.map_err(|overflow| Error::Model(ModelError::MessageTooLong(overflow)))?;
97-
}
98-
99-
check_overflow(self.embeds.len(), constants::EMBED_MAX_COUNT)
100-
.map_err(|_| Error::Model(ModelError::EmbedAmount))?;
101-
for embed in self.embeds.iter() {
102-
embed.check_length()?;
103-
}
104-
105-
Ok(())
91+
fn check_length(&self) -> Result<(), ModelError> {
92+
super::check_lengths(self.content.as_deref(), Some(&self.embeds), 0)
10693
}
10794

10895
/// Override the default avatar of the webhook with an image URL.

src/builder/mod.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
use crate::http::CacheHttp;
1212
#[cfg(feature = "http")]
1313
use crate::internal::prelude::*;
14+
#[cfg(feature = "http")]
15+
use crate::model::ModelError;
1416

1517
/// Common trait for all HTTP request builders in this module.
1618
#[cfg(feature = "http")]
@@ -28,12 +30,26 @@ pub trait Builder {
2830
}
2931

3032
#[cfg(feature = "http")]
31-
pub(crate) fn check_overflow(len: usize, max: usize) -> StdResult<(), usize> {
32-
if len > max {
33-
Err(len - max)
34-
} else {
35-
Ok(())
33+
pub(crate) fn check_lengths(
34+
content: Option<&str>,
35+
embeds: Option<&[CreateEmbed<'_>]>,
36+
stickers: usize,
37+
) -> StdResult<(), ModelError> {
38+
use crate::model::error::Maximum;
39+
40+
if let Some(content) = content {
41+
Maximum::MessageLength.check_overflow(content.chars().count())?;
3642
}
43+
44+
if let Some(embeds) = embeds {
45+
Maximum::EmbedCount.check_overflow(embeds.len())?;
46+
47+
for embed in embeds {
48+
Maximum::EmbedLength.check_overflow(embed.get_length())?;
49+
}
50+
}
51+
52+
Maximum::StickerCount.check_overflow(stickers)
3753
}
3854

3955
mod add_member;

src/constants.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! A set of constants used by the library.
22
3+
use nonmax::NonMaxU16;
4+
35
/// The maximum length of the textual size of an embed.
46
pub const EMBED_MAX_LENGTH: usize = 6000;
57

@@ -19,7 +21,10 @@ pub const LARGE_THRESHOLD: u8 = 250;
1921
pub const MESSAGE_CODE_LIMIT: usize = 2000;
2022

2123
/// The maximum number of members the bot can fetch at once
22-
pub const MEMBER_FETCH_LIMIT: u64 = 1000;
24+
pub const MEMBER_FETCH_LIMIT: NonMaxU16 = match NonMaxU16::new(1000) {
25+
Some(m) => m,
26+
None => unreachable!(),
27+
};
2328

2429
/// The [UserAgent] sent along with every request.
2530
///

0 commit comments

Comments
 (0)