diff --git a/Cargo.toml b/Cargo.toml index aa803c0ec9e..bac754c9c0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ dep_time = { version = "0.3.30", package = "time", features = ["formatting", "pa base64 = { version = "0.21.5" } secrecy = { version = "0.8.0", features = ["serde"] } arrayvec = { version = "0.7.4", features = ["serde"] } +small-fixed-array = { git = "https://github.com/GnomedDev/small-fixed-array", features = ["serde", "log_using_tracing"] } # Optional dependencies fxhash = { version = "0.2.1", optional = true } simd-json = { version = "0.13.4", optional = true } @@ -48,7 +49,7 @@ mime_guess = { version = "2.0.4", optional = true } dashmap = { version = "5.5.3", features = ["serde"], optional = true } parking_lot = { version = "0.12.1", optional = true } ed25519-dalek = { version = "2.0.0", optional = true } -typesize = { version = "0.1.2", optional = true, features = ["url", "time", "serde_json", "secrecy", "dashmap", "parking_lot", "details"] } +typesize = { version = "0.1.4", optional = true, features = ["url", "time", "serde_json", "secrecy", "dashmap", "parking_lot", "details"] } # serde feature only allows for serialisation, # Serenity workspace crates command_attr = { version = "0.5.1", path = "./command_attr", optional = true } @@ -124,6 +125,8 @@ simd_json = ["simd-json", "typesize?/simd_json"] # Enables temporary caching in functions that retrieve data via the HTTP API. temp_cache = ["cache", "mini-moka", "typesize?/mini_moka"] +typesize = ["dep:typesize", "small-fixed-array/typesize"] + # Removed feature (https://github.com/serenity-rs/serenity/pull/2246) absolute_ratelimits = [] diff --git a/examples/e04_message_builder/src/main.rs b/examples/e04_message_builder/src/main.rs index e5fd8ce3b0c..0f3005cc966 100644 --- a/examples/e04_message_builder/src/main.rs +++ b/examples/e04_message_builder/src/main.rs @@ -26,7 +26,7 @@ impl EventHandler for Handler { // emojis, and more. let response = MessageBuilder::new() .push("User ") - .push_bold_safe(&msg.author.name) + .push_bold_safe(msg.author.name.into_string()) .push(" used the 'ping' command in the ") .mention(&channel) .push(" channel") diff --git a/src/builder/create_command.rs b/src/builder/create_command.rs index aa659b5919a..0af98c50479 100644 --- a/src/builder/create_command.rs +++ b/src/builder/create_command.rs @@ -26,9 +26,9 @@ impl CreateCommandOption { ) -> Self { Self(CommandOption { kind, - name: name.into(), + name: name.into().into(), name_localizations: None, - description: description.into(), + description: description.into().into(), description_localizations: None, required: false, autocomplete: false, @@ -37,7 +37,7 @@ impl CreateCommandOption { min_length: None, max_length: None, - channel_types: Vec::new(), + channel_types: FixedArray::default(), choices: Vec::new(), options: Vec::new(), }) @@ -53,7 +53,7 @@ impl CreateCommandOption { /// /// **Note**: Must be between 1 and 32 lowercase characters, matching `r"^[\w-]{1,32}$"`. pub fn name(mut self, name: impl Into) -> Self { - self.0.name = name.into(); + self.0.name = name.into().into(); self } @@ -77,7 +77,7 @@ impl CreateCommandOption { /// /// **Note**: Must be between 1 and 100 characters. pub fn description(mut self, description: impl Into) -> Self { - self.0.description = description.into(); + self.0.description = description.into().into(); self } /// Specifies a localized description of the option. @@ -114,7 +114,7 @@ impl CreateCommandOption { /// characters. Value must be between -2^53 and 2^53. pub fn add_int_choice(self, name: impl Into, value: i32) -> Self { self.add_choice(CommandOptionChoice { - name: name.into(), + name: name.into().into(), value: Value::from(value), name_localizations: None, }) @@ -128,7 +128,7 @@ impl CreateCommandOption { locales: impl IntoIterator, impl Into)>, ) -> Self { self.add_choice(CommandOptionChoice { - name: name.into(), + name: name.into().into(), value: Value::from(value), name_localizations: Some( locales.into_iter().map(|(l, n)| (l.into(), n.into())).collect(), @@ -142,7 +142,7 @@ impl CreateCommandOption { /// characters. Value must be up to 100 characters. pub fn add_string_choice(self, name: impl Into, value: impl Into) -> Self { self.add_choice(CommandOptionChoice { - name: name.into(), + name: name.into().into(), value: Value::String(value.into()), name_localizations: None, }) @@ -156,7 +156,7 @@ impl CreateCommandOption { locales: impl IntoIterator, impl Into)>, ) -> Self { self.add_choice(CommandOptionChoice { - name: name.into(), + name: name.into().into(), value: Value::String(value.into()), name_localizations: Some( locales.into_iter().map(|(l, n)| (l.into(), n.into())).collect(), @@ -170,7 +170,7 @@ impl CreateCommandOption { /// characters. Value must be between -2^53 and 2^53. pub fn add_number_choice(self, name: impl Into, value: f64) -> Self { self.add_choice(CommandOptionChoice { - name: name.into(), + name: name.into().into(), value: Value::from(value), name_localizations: None, }) @@ -184,7 +184,7 @@ impl CreateCommandOption { locales: impl IntoIterator, impl Into)>, ) -> Self { self.add_choice(CommandOptionChoice { - name: name.into(), + name: name.into().into(), value: Value::from(value), name_localizations: Some( locales.into_iter().map(|(l, n)| (l.into(), n.into())).collect(), @@ -241,7 +241,7 @@ impl CreateCommandOption { /// /// [`Channel`]: crate::model::application::CommandOptionType::Channel pub fn channel_types(mut self, channel_types: Vec) -> Self { - self.0.channel_types = channel_types; + self.0.channel_types = channel_types.into(); self } @@ -300,7 +300,7 @@ impl CreateCommandOption { #[derive(Clone, Debug, Serialize)] #[must_use] pub struct CreateCommand { - name: String, + name: FixedString, name_localizations: HashMap, #[serde(skip_serializing_if = "Option::is_none")] description: Option, @@ -322,7 +322,7 @@ impl CreateCommand { Self { kind: None, - name: name.into(), + name: name.into().into(), name_localizations: HashMap::new(), description: None, description_localizations: HashMap::new(), @@ -341,7 +341,7 @@ impl CreateCommand { /// global commands of the same app cannot have the same name. Two guild-specific commands of /// the same app cannot have the same name. pub fn name(mut self, name: impl Into) -> Self { - self.name = name.into(); + self.name = name.into().into(); self } diff --git a/src/builder/create_components.rs b/src/builder/create_components.rs index c662c178558..35f3f505096 100644 --- a/src/builder/create_components.rs +++ b/src/builder/create_components.rs @@ -45,7 +45,7 @@ impl CreateButton { Self(Button { kind: ComponentType::Button, data: ButtonKind::Link { - url: url.into(), + url: url.into().into(), }, label: None, emoji: None, @@ -60,7 +60,7 @@ impl CreateButton { kind: ComponentType::Button, data: ButtonKind::NonLink { style: ButtonStyle::Primary, - custom_id: custom_id.into(), + custom_id: custom_id.into().into(), }, label: None, emoji: None, @@ -77,7 +77,7 @@ impl CreateButton { custom_id, .. } = &mut self.0.data { - *custom_id = id.into(); + *custom_id = id.into().into(); } self } @@ -97,7 +97,7 @@ impl CreateButton { /// Sets label of the button. pub fn label(mut self, label: impl Into) -> Self { - self.0.label = Some(label.into()); + self.0.label = Some(label.into().into()); self } @@ -338,8 +338,8 @@ impl CreateInputText { ) -> Self { Self(InputText { style: Some(style), - label: Some(label.into()), - custom_id: custom_id.into(), + label: Some(label.into().into()), + custom_id: custom_id.into().into(), placeholder: None, min_length: None, @@ -359,20 +359,20 @@ impl CreateInputText { /// Sets the label of this input text. Replaces the current value as set in [`Self::new`]. pub fn label(mut self, label: impl Into) -> Self { - self.0.label = Some(label.into()); + self.0.label = Some(label.into().into()); self } /// Sets the custom id of the input text, a developer-defined identifier. Replaces the current /// value as set in [`Self::new`]. pub fn custom_id(mut self, id: impl Into) -> Self { - self.0.custom_id = id.into(); + self.0.custom_id = id.into().into(); self } /// Sets the placeholder of this input text. pub fn placeholder(mut self, label: impl Into) -> Self { - self.0.placeholder = Some(label.into()); + self.0.placeholder = Some(label.into().into()); self } @@ -390,7 +390,7 @@ impl CreateInputText { /// Sets the value of this input text. pub fn value(mut self, value: impl Into) -> Self { - self.0.value = Some(value.into()); + self.0.value = Some(value.into().into()); self } diff --git a/src/builder/create_embed.rs b/src/builder/create_embed.rs index 010cbe6c7f4..856b7ce35d1 100644 --- a/src/builder/create_embed.rs +++ b/src/builder/create_embed.rs @@ -59,7 +59,7 @@ impl CreateEmbed { /// **Note**: This can't be longer than 4096 characters. #[inline] pub fn description(mut self, description: impl Into) -> Self { - self.0.description = Some(description.into()); + self.0.description = Some(description.into().into()); self } @@ -104,7 +104,7 @@ impl CreateEmbed { #[inline] pub fn image(mut self, url: impl Into) -> Self { self.0.image = Some(EmbedImage { - url: url.into(), + url: url.into().into(), proxy_url: None, height: None, width: None, @@ -116,7 +116,7 @@ impl CreateEmbed { #[inline] pub fn thumbnail(mut self, url: impl Into) -> Self { self.0.thumbnail = Some(EmbedThumbnail { - url: url.into(), + url: url.into().into(), proxy_url: None, height: None, width: None, @@ -147,14 +147,14 @@ impl CreateEmbed { /// Set the title of the embed. #[inline] pub fn title(mut self, title: impl Into) -> Self { - self.0.title = Some(title.into()); + self.0.title = Some(title.into().into()); self } /// Set the URL to direct to when clicking on the title. #[inline] pub fn url(mut self, url: impl Into) -> Self { - self.0.url = Some(url.into()); + self.0.url = Some(url.into().into()); self } @@ -208,7 +208,7 @@ impl Default for CreateEmbed { description: None, thumbnail: None, timestamp: None, - kind: Some("rich".into()), + kind: Some("rich".to_string().into()), author: None, colour: None, footer: None, @@ -236,7 +236,7 @@ impl CreateEmbedAuthor { /// Creates an author object with the given name, leaving all other fields empty. pub fn new(name: impl Into) -> Self { Self(EmbedAuthor { - name: name.into(), + name: name.into().into(), icon_url: None, url: None, // Has no builder method because I think this field is only relevant when receiving (?) @@ -246,19 +246,19 @@ impl CreateEmbedAuthor { /// Set the author's name, replacing the current value as set in [`Self::new`]. pub fn name(mut self, name: impl Into) -> Self { - self.0.name = name.into(); + self.0.name = name.into().into(); self } /// Set the URL of the author's icon. pub fn icon_url(mut self, icon_url: impl Into) -> Self { - self.0.icon_url = Some(icon_url.into()); + self.0.icon_url = Some(icon_url.into().into()); self } /// Set the author's URL. pub fn url(mut self, url: impl Into) -> Self { - self.0.url = Some(url.into()); + self.0.url = Some(url.into().into()); self } } @@ -278,7 +278,7 @@ impl CreateEmbedFooter { /// Creates a new footer object with the given text, leaving all other fields empty. pub fn new(text: impl Into) -> Self { Self(EmbedFooter { - text: text.into(), + text: text.into().into(), icon_url: None, // Has no builder method because I think this field is only relevant when receiving (?) proxy_icon_url: None, @@ -287,13 +287,13 @@ impl CreateEmbedFooter { /// Set the footer's text, replacing the current value as set in [`Self::new`]. pub fn text(mut self, text: impl Into) -> Self { - self.0.text = text.into(); + self.0.text = text.into().into(); self } /// Set the icon URL's value. This only supports HTTP(S). pub fn icon_url(mut self, icon_url: impl Into) -> Self { - self.0.icon_url = Some(icon_url.into()); + self.0.icon_url = Some(icon_url.into().into()); self } } diff --git a/src/builder/create_forum_tag.rs b/src/builder/create_forum_tag.rs index 31db70451d5..d616b3e2481 100644 --- a/src/builder/create_forum_tag.rs +++ b/src/builder/create_forum_tag.rs @@ -1,3 +1,4 @@ +use crate::internal::prelude::*; use crate::model::prelude::*; /// [Discord docs](https://discord.com/developers/docs/resources/channel#forum-tag-object-forum-tag-structure) @@ -6,16 +7,16 @@ use crate::model::prelude::*; #[must_use] #[derive(Clone, Debug, Serialize)] pub struct CreateForumTag { - name: String, + name: FixedString, moderated: bool, emoji_id: Option, - emoji_name: Option, + emoji_name: Option, } impl CreateForumTag { pub fn new(name: impl Into) -> Self { Self { - name: name.into(), + name: name.into().into(), moderated: false, emoji_id: None, emoji_name: None, diff --git a/src/builder/create_interaction_response.rs b/src/builder/create_interaction_response.rs index b3a137d0eb8..57aa8db7a50 100644 --- a/src/builder/create_interaction_response.rs +++ b/src/builder/create_interaction_response.rs @@ -298,7 +298,7 @@ pub struct AutocompleteChoice(CommandOptionChoice); impl AutocompleteChoice { pub fn new(name: impl Into, value: impl Into) -> Self { Self(CommandOptionChoice { - name: name.into(), + name: name.into().into(), name_localizations: None, value: value.into(), }) diff --git a/src/builder/create_scheduled_event.rs b/src/builder/create_scheduled_event.rs index 4b88aa52e10..938952588db 100644 --- a/src/builder/create_scheduled_event.rs +++ b/src/builder/create_scheduled_event.rs @@ -104,7 +104,7 @@ impl<'a> CreateScheduledEvent<'a> { /// [`External`]: ScheduledEventType::External pub fn location(mut self, location: impl Into) -> Self { self.entity_metadata = Some(ScheduledEventMetadata { - location: Some(location.into()), + location: Some(location.into().into()), }); self } diff --git a/src/builder/edit_guild_welcome_screen.rs b/src/builder/edit_guild_welcome_screen.rs index 8d7b7c4d1af..ccb481d485d 100644 --- a/src/builder/edit_guild_welcome_screen.rs +++ b/src/builder/edit_guild_welcome_screen.rs @@ -94,8 +94,8 @@ impl CreateGuildWelcomeChannel { pub fn new(channel_id: ChannelId, description: String) -> Self { Self(GuildWelcomeChannel { channel_id, - description, emoji: None, + description: description.into(), }) } @@ -107,7 +107,7 @@ impl CreateGuildWelcomeChannel { /// The description shown for the channel. pub fn description(mut self, description: impl Into) -> Self { - self.0.description = description.into(); + self.0.description = description.into().into(); self } diff --git a/src/builder/edit_role.rs b/src/builder/edit_role.rs index d7db7c05847..c57c6ba3439 100644 --- a/src/builder/edit_role.rs +++ b/src/builder/edit_role.rs @@ -3,7 +3,6 @@ use super::Builder; use super::CreateAttachment; #[cfg(feature = "http")] use crate::http::CacheHttp; -#[cfg(feature = "http")] use crate::internal::prelude::*; use crate::model::prelude::*; @@ -47,7 +46,7 @@ use crate::model::prelude::*; #[must_use] pub struct EditRole<'a> { #[serde(skip_serializing_if = "Option::is_none")] - name: Option, + name: Option, #[serde(skip_serializing_if = "Option::is_none")] permissions: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -56,9 +55,9 @@ pub struct EditRole<'a> { #[serde(skip_serializing_if = "Option::is_none")] hoist: Option, #[serde(skip_serializing_if = "Option::is_none")] - icon: Option>, + icon: Option>, #[serde(skip_serializing_if = "Option::is_none")] - unicode_emoji: Option>, + unicode_emoji: Option>, #[serde(skip_serializing_if = "Option::is_none")] mentionable: Option, @@ -112,7 +111,7 @@ impl<'a> EditRole<'a> { /// Set the role's name. pub fn name(mut self, name: impl Into) -> Self { - self.name = Some(name.into()); + self.name = Some(name.into().into()); self } @@ -131,14 +130,14 @@ impl<'a> EditRole<'a> { /// Set the role icon to a unicode emoji. pub fn unicode_emoji(mut self, unicode_emoji: Option) -> Self { - self.unicode_emoji = Some(unicode_emoji); + self.unicode_emoji = Some(unicode_emoji.map(Into::into)); self.icon = Some(None); self } /// Set the role icon to a custom image. pub fn icon(mut self, icon: Option<&CreateAttachment>) -> Self { - self.icon = Some(icon.map(CreateAttachment::to_base64)); + self.icon = Some(icon.map(CreateAttachment::to_base64).map(Into::into)); self.unicode_emoji = Some(None); self } diff --git a/src/builder/edit_scheduled_event.rs b/src/builder/edit_scheduled_event.rs index 77b94fd0921..7e19132917f 100644 --- a/src/builder/edit_scheduled_event.rs +++ b/src/builder/edit_scheduled_event.rs @@ -148,7 +148,7 @@ impl<'a> EditScheduledEvent<'a> { /// [`External`]: ScheduledEventType::External pub fn location(mut self, location: impl Into) -> Self { self.entity_metadata = Some(Some(ScheduledEventMetadata { - location: Some(location.into()), + location: Some(location.into().into()), })); self } diff --git a/src/cache/event.rs b/src/cache/event.rs index fad086722cd..c22f0dd623d 100644 --- a/src/cache/event.rs +++ b/src/cache/event.rs @@ -2,6 +2,7 @@ use std::collections::HashSet; use std::num::NonZeroU16; use super::{Cache, CacheUpdate}; +use crate::internal::prelude::*; use crate::model::channel::{GuildChannel, Message}; use crate::model::event::{ ChannelCreateEvent, @@ -444,7 +445,7 @@ impl CacheUpdate for PresenceUpdateEvent { mute: false, nick: None, user, - roles: vec![], + roles: FixedArray::default(), pending: false, premium_since: None, permissions: None, @@ -477,9 +478,7 @@ impl CacheUpdate for ReadyEvent { type Output = (); fn update(&mut self, cache: &Cache) -> Option<()> { - let ready = self.ready.clone(); - - for unavailable in ready.guilds { + for unavailable in &self.ready.guilds { cache.guilds.remove(&unavailable.id); cache.unavailable_guilds.insert(unavailable.id, ()); } @@ -511,7 +510,7 @@ impl CacheUpdate for ReadyEvent { cached_shard_data.total = shard_data.total; cached_shard_data.connected.insert(shard_data.id); } - *cache.user.write() = ready.user; + cache.user.write().clone_from(&self.ready.user); None } @@ -527,7 +526,11 @@ impl CacheUpdate for ThreadCreateEvent { if let Some(i) = g.threads.iter().position(|e| e.id == thread_id) { Some(std::mem::replace(&mut g.threads[i], self.thread.clone())) } else { - g.threads.push(self.thread.clone()); + // This is a rare enough occurence to realloc. + let mut threads = std::mem::take(&mut g.threads).into_vec(); + threads.push(self.thread.clone()); + g.threads = threads.into(); + None } }) @@ -544,7 +547,11 @@ impl CacheUpdate for ThreadUpdateEvent { if let Some(i) = g.threads.iter().position(|e| e.id == thread_id) { Some(std::mem::replace(&mut g.threads[i], self.thread.clone())) } else { - g.threads.push(self.thread.clone()); + // This is a rare enough occurence to realloc. + let mut threads = std::mem::take(&mut g.threads).into_vec(); + threads.push(self.thread.clone()); + g.threads = threads.into(); + None } }) @@ -558,7 +565,13 @@ impl CacheUpdate for ThreadDeleteEvent { let (guild_id, thread_id) = (self.thread.guild_id, self.thread.id); cache.guilds.get_mut(&guild_id).and_then(|mut g| { - g.threads.iter().position(|e| e.id == thread_id).map(|i| g.threads.remove(i)) + g.threads.iter().position(|e| e.id == thread_id).map(|i| { + let mut threads = std::mem::take(&mut g.threads).into_vec(); + let thread = threads.remove(i); + g.threads = threads.into(); + + thread + }) }) } } @@ -599,7 +612,7 @@ impl CacheUpdate for VoiceStateUpdateEvent { } impl CacheUpdate for VoiceChannelStatusUpdateEvent { - type Output = String; + type Output = FixedString; fn update(&mut self, cache: &Cache) -> Option { if let Some(mut channel) = cache.channel_mut(self.id) { diff --git a/src/client/dispatch.rs b/src/client/dispatch.rs index 5851139fe6c..f6e2f5ad235 100644 --- a/src/client/dispatch.rs +++ b/src/client/dispatch.rs @@ -9,6 +9,7 @@ use super::{Context, FullEvent}; use crate::cache::{Cache, CacheUpdate}; #[cfg(feature = "framework")] use crate::framework::Framework; +use crate::internal::prelude::*; use crate::internal::tokio::spawn_named; use crate::model::channel::ChannelType; use crate::model::event::Event; @@ -297,7 +298,7 @@ fn update_cache_with_event( }, Event::MessageDeleteBulk(event) => FullEvent::MessageDeleteBulk { channel_id: event.channel_id, - multiple_deleted_messages_ids: event.ids, + multiple_deleted_messages_ids: event.ids.into_vec(), guild_id: event.guild_id, }, Event::MessageDelete(event) => FullEvent::MessageDelete { @@ -319,7 +320,7 @@ fn update_cache_with_event( update_cache!(cache, event); FullEvent::PresenceReplace { - presences: event.presences, + presences: event.presences.into_vec(), } }, Event::PresenceUpdate(mut event) => { @@ -392,11 +393,11 @@ fn update_cache_with_event( } }, Event::VoiceChannelStatusUpdate(mut event) => { - let old = if_cache!(event.update(cache)); + let old = if_cache!(event.update(cache).map(FixedString::into_string)); FullEvent::VoiceChannelStatusUpdate { old, - status: event.status, + status: event.status.map(FixedString::into_string), id: event.id, guild_id: event.guild_id, } diff --git a/src/client/event_handler.rs b/src/client/event_handler.rs index 11791ffe3ec..acb25448a3a 100644 --- a/src/client/event_handler.rs +++ b/src/client/event_handler.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "cache")] use std::num::NonZeroU16; use async_trait::async_trait; diff --git a/src/collector.rs b/src/collector.rs index a57f9c1fccc..d757cc64ec8 100644 --- a/src/collector.rs +++ b/src/collector.rs @@ -2,6 +2,7 @@ use futures::future::pending; use futures::{Stream, StreamExt as _}; use crate::gateway::{CollectorCallback, ShardMessenger}; +use crate::internal::prelude::*; use crate::model::prelude::*; /// Fundamental collector function. All collector types in this module are just wrappers around @@ -85,7 +86,7 @@ macro_rules! make_specific_collector { } $( - #[doc = concat!("Filters [`", stringify!($item_type), "`]'s by a specific [`", stringify!($filter_type), "`].")] + #[doc = concat!("Filters [`", stringify!($item_type), "`]'s by a specific [`type@", stringify!($filter_type), "`].")] pub fn $filter_name(mut self, $filter_name: $filter_type) -> Self { self.$filter_name = Some($filter_name); self @@ -158,7 +159,7 @@ make_specific_collector!( channel_id: ChannelId => interaction.channel_id == *channel_id, guild_id: GuildId => interaction.guild_id.map_or(true, |x| x == *guild_id), message_id: MessageId => interaction.message.id == *message_id, - custom_ids: Vec => custom_ids.contains(&interaction.data.custom_id), + custom_ids: FixedArray => custom_ids.contains(&interaction.data.custom_id), ); make_specific_collector!( ModalInteractionCollector, ModalInteraction, @@ -169,7 +170,7 @@ make_specific_collector!( channel_id: ChannelId => interaction.channel_id == *channel_id, guild_id: GuildId => interaction.guild_id.map_or(true, |g| g == *guild_id), message_id: MessageId => interaction.message.as_ref().map_or(true, |m| m.id == *message_id), - custom_ids: Vec => custom_ids.contains(&interaction.data.custom_id), + custom_ids: Vec => custom_ids.contains(&interaction.data.custom_id), ); make_specific_collector!( ReactionCollector, Reaction, diff --git a/src/framework/standard/parse/mod.rs b/src/framework/standard/parse/mod.rs index 158ebee9038..bd02a80963a 100644 --- a/src/framework/standard/parse/mod.rs +++ b/src/framework/standard/parse/mod.rs @@ -55,7 +55,7 @@ fn permissions_in( } if let Some(channel) = guild.and_then(|guild| guild.channels.get(&channel_id).cloned()) { - let mut data = Vec::with_capacity(member.roles.len()); + let mut data = Vec::with_capacity(member.roles.len() as usize); for overwrite in &channel.permission_overwrites { if let PermissionOverwriteType::Role(role) = overwrite.kind { diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index d2ed1022b92..d747907d92f 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -55,7 +55,6 @@ pub use self::bridge::*; pub use self::error::Error as GatewayError; pub use self::shard::Shard; pub use self::ws::WsClient; -#[cfg(feature = "http")] use crate::internal::prelude::*; use crate::model::gateway::{Activity, ActivityType}; use crate::model::id::UserId; @@ -74,12 +73,12 @@ pub struct PresenceData { #[derive(Clone, Debug, Serialize)] pub struct ActivityData { /// The name of the activity - pub name: String, + pub name: FixedString, /// The type of the activity #[serde(rename = "type")] pub kind: ActivityType, /// The state of the activity, if the type is [`ActivityType::Custom`] - pub state: Option, + pub state: Option, /// The url of the activity, if the type is [`ActivityType::Streaming`] pub url: Option, } @@ -89,7 +88,7 @@ impl ActivityData { #[must_use] pub fn playing(name: impl Into) -> Self { Self { - name: name.into(), + name: name.into().into(), kind: ActivityType::Playing, state: None, url: None, @@ -104,7 +103,7 @@ impl ActivityData { #[cfg(feature = "http")] pub fn streaming(name: impl Into, url: impl IntoUrl) -> Result { Ok(Self { - name: name.into(), + name: name.into().into(), kind: ActivityType::Streaming, state: None, url: Some(url.into_url()?), @@ -115,7 +114,7 @@ impl ActivityData { #[must_use] pub fn listening(name: impl Into) -> Self { Self { - name: name.into(), + name: name.into().into(), kind: ActivityType::Listening, state: None, url: None, @@ -126,7 +125,7 @@ impl ActivityData { #[must_use] pub fn watching(name: impl Into) -> Self { Self { - name: name.into(), + name: name.into().into(), kind: ActivityType::Watching, state: None, url: None, @@ -137,7 +136,7 @@ impl ActivityData { #[must_use] pub fn competing(name: impl Into) -> Self { Self { - name: name.into(), + name: name.into().into(), kind: ActivityType::Competing, state: None, url: None, @@ -150,9 +149,9 @@ impl ActivityData { Self { // discord seems to require a name for custom activities // even though it's not displayed - name: "~".to_string(), + name: "~".to_string().into(), kind: ActivityType::Custom, - state: Some(state.into()), + state: Some(state.into().into()), url: None, } } diff --git a/src/gateway/shard.rs b/src/gateway/shard.rs index a0a582afdeb..760dedc1033 100644 --- a/src/gateway/shard.rs +++ b/src/gateway/shard.rs @@ -64,7 +64,7 @@ pub struct Shard { // This must be set to `true` in `Shard::handle_event`'s `Ok(GatewayEvent::HeartbeatAck)` arm. last_heartbeat_acknowledged: bool, seq: u64, - session_id: Option, + session_id: Option, shard_info: ShardInfo, stage: ConnectionStage, /// Instant of when the shard was started. @@ -234,8 +234,8 @@ impl Shard { } #[inline] - pub fn session_id(&self) -> Option<&String> { - self.session_id.as_ref() + pub fn session_id(&self) -> Option<&str> { + self.session_id.as_deref() } #[inline] diff --git a/src/http/client.rs b/src/http/client.rs index 439465d09e7..c9fe7fb93fa 100644 --- a/src/http/client.rs +++ b/src/http/client.rs @@ -909,7 +909,7 @@ impl Http { route: Route::Entitlements { application_id: self.try_application_id()?, }, - params: None, + params: [].into(), }) .await } @@ -1402,7 +1402,7 @@ impl Http { application_id: self.try_application_id()?, entitlement_id, }, - params: None, + params: [].into(), }) .await } @@ -3156,7 +3156,8 @@ impl Http { guild_id: Option, exclude_ended: Option, ) -> Result> { - let mut params = vec![]; + let mut params = ArrayVec::<_, 7>::new(); + if let Some(user_id) = user_id { params.push(("user_id", user_id.to_string())); } @@ -3190,7 +3191,7 @@ impl Http { route: Route::Entitlements { application_id: self.try_application_id()?, }, - params: Some(params), + params, }) .await } @@ -4059,7 +4060,7 @@ impl Http { route: Route::Skus { application_id: self.try_application_id()?, }, - params: None, + params: [].into(), }) .await } diff --git a/src/internal/prelude.rs b/src/internal/prelude.rs index df676dad5cb..7a1e846f11d 100644 --- a/src/internal/prelude.rs +++ b/src/internal/prelude.rs @@ -4,5 +4,7 @@ pub use std::result::Result as StdResult; +pub use small_fixed_array::{FixedArray, FixedString}; + pub use crate::error::{Error, Result}; pub use crate::json::{JsonMap, Value}; diff --git a/src/model/application/command.rs b/src/model/application/command.rs index 146adb19c4b..e7499f00848 100644 --- a/src/model/application/command.rs +++ b/src/model/application/command.rs @@ -38,13 +38,13 @@ pub struct Command { /// **Note**: It may only be present if it is received through the gateway. pub guild_id: Option, /// The command name. - pub name: String, + pub name: FixedString, /// The localized command name of the selected locale. /// /// If the name is localized, either this field or [`Self::name_localizations`] is set, /// depending on which endpoint this data was retrieved from /// ([source](https://discord.com/developers/docs/interactions/application-commands#retrieving-localized-commands)). - pub name_localized: Option, + pub name_localized: Option>, /// All localized command names. /// /// If the name is localized, either this field or [`Self::name_localized`] is set, depending @@ -52,13 +52,13 @@ pub struct Command { /// ([source](https://discord.com/developers/docs/interactions/application-commands#retrieving-localized-commands)). pub name_localizations: Option>, /// The command description. - pub description: String, + pub description: FixedString, /// The localized command description of the selected locale. /// /// If the description is localized, either this field or [`Self::description_localizations`] /// is set, depending on which endpoint this data was retrieved from /// ([source](https://discord.com/developers/docs/interactions/application-commands#retrieving-localized-commands)). - pub description_localized: Option, + pub description_localized: Option>, /// All localized command descriptions. /// /// If the description is localized, either this field or [`Self::description_localized`] is @@ -67,7 +67,7 @@ pub struct Command { pub description_localizations: Option>, /// The parameters for the command. #[serde(default)] - pub options: Vec, + pub options: FixedArray, /// The default permissions required to execute the command. pub default_member_permissions: Option, /// Indicates whether the command is available in DMs with the app, only for globally-scoped @@ -243,12 +243,12 @@ pub struct CommandOption { #[serde(rename = "type")] pub kind: CommandOptionType, /// The option name. - pub name: String, + pub name: FixedString, /// Localizations of the option name with locale as the key #[serde(skip_serializing_if = "Option::is_none")] pub name_localizations: Option>, /// The option description. - pub description: String, + pub description: FixedString, /// Localizations of the option description with locale as the key #[serde(skip_serializing_if = "Option::is_none")] pub description_localizations: Option>, @@ -275,7 +275,7 @@ pub struct CommandOption { /// /// [`Channel`]: CommandOptionType::Channel #[serde(default)] - pub channel_types: Vec, + pub channel_types: FixedArray, /// Minimum permitted value for Integer or Number options #[serde(default)] pub min_value: Option, @@ -324,7 +324,7 @@ enum_number! { #[non_exhaustive] pub struct CommandOptionChoice { /// The choice name. - pub name: String, + pub name: FixedString, /// Localizations of the choice name, with locale as key #[serde(skip_serializing_if = "Option::is_none")] pub name_localizations: Option>, @@ -346,7 +346,7 @@ pub struct CommandPermissions { /// The id of the guild. pub guild_id: GuildId, /// The permissions for the command in the guild. - pub permissions: Vec, + pub permissions: FixedArray, } /// The [`CommandPermission`] data. diff --git a/src/model/application/command_interaction.rs b/src/model/application/command_interaction.rs index 266412a2d0b..423cec1138a 100644 --- a/src/model/application/command_interaction.rs +++ b/src/model/application/command_interaction.rs @@ -70,15 +70,15 @@ pub struct CommandInteraction { #[serde(default)] pub user: User, /// A continuation token for responding to the interaction. - pub token: String, + pub token: FixedString, /// Always `1`. pub version: u8, /// Permissions the app or bot has within the channel the interaction was sent from. pub app_permissions: Option, /// The selected language of the invoking user. - pub locale: String, + pub locale: FixedString, /// The guild's preferred locale. - pub guild_locale: Option, + pub guild_locale: Option, /// For monetized applications, any entitlements of the invoking user. pub entitlements: Vec, } @@ -276,7 +276,7 @@ pub struct CommandData { /// The Id of the invoked command. pub id: CommandId, /// The name of the invoked command. - pub name: String, + pub name: FixedString, /// The application command type of the triggered application command. #[serde(rename = "type")] pub kind: CommandType, @@ -284,7 +284,7 @@ pub struct CommandData { #[serde(default)] pub resolved: CommandDataResolved, #[serde(default)] - pub options: Vec, + pub options: FixedArray, /// The Id of the guild the command is registered to. #[serde(skip_serializing_if = "Option::is_none")] pub guild_id: Option, @@ -519,7 +519,7 @@ pub struct CommandDataResolved { #[non_exhaustive] pub struct CommandDataOption { /// The name of the parameter. - pub name: String, + pub name: FixedString, /// The given value. pub value: CommandDataOptionValue, } @@ -533,7 +533,7 @@ impl CommandDataOption { #[derive(Deserialize, Serialize)] struct RawCommandDataOption { - name: String, + name: FixedString, #[serde(rename = "type")] kind: CommandOptionType, #[serde(skip_serializing_if = "Option::is_none")] @@ -643,13 +643,13 @@ impl Serialize for CommandDataOption { #[derive(Clone, Debug, PartialEq)] #[non_exhaustive] pub enum CommandDataOptionValue { - Autocomplete { kind: CommandOptionType, value: String }, + Autocomplete { kind: CommandOptionType, value: FixedString }, Boolean(bool), Integer(i64), Number(f64), - String(String), - SubCommand(Vec), - SubCommandGroup(Vec), + String(FixedString), + SubCommand(FixedArray), + SubCommandGroup(FixedArray), Attachment(AttachmentId), Channel(ChannelId), Mentionable(GenericId), @@ -811,14 +811,20 @@ mod tests { #[test] fn nested_options() { let value = CommandDataOption { - name: "subcommand_group".into(), - value: CommandDataOptionValue::SubCommandGroup(vec![CommandDataOption { - name: "subcommand".into(), - value: CommandDataOptionValue::SubCommand(vec![CommandDataOption { - name: "channel".into(), - value: CommandDataOptionValue::Channel(ChannelId::new(3)), - }]), - }]), + name: "subcommand_group".to_string().into(), + value: CommandDataOptionValue::SubCommandGroup( + vec![CommandDataOption { + name: "subcommand".to_string().into(), + value: CommandDataOptionValue::SubCommand( + vec![CommandDataOption { + name: "channel".to_string().into(), + value: CommandDataOptionValue::Channel(ChannelId::new(3)), + }] + .into(), + ), + }] + .into(), + ), }; assert_json( @@ -839,30 +845,30 @@ mod tests { fn mixed_options() { let value = vec![ CommandDataOption { - name: "boolean".into(), + name: "boolean".to_string().into(), value: CommandDataOptionValue::Boolean(true), }, CommandDataOption { - name: "integer".into(), + name: "integer".to_string().into(), value: CommandDataOptionValue::Integer(1), }, CommandDataOption { - name: "number".into(), + name: "number".to_string().into(), value: CommandDataOptionValue::Number(2.0), }, CommandDataOption { - name: "string".into(), - value: CommandDataOptionValue::String("foobar".into()), + name: "string".to_string().into(), + value: CommandDataOptionValue::String("foobar".to_string().into()), }, CommandDataOption { - name: "empty_subcommand".into(), - value: CommandDataOptionValue::SubCommand(vec![]), + name: "empty_subcommand".to_string().into(), + value: CommandDataOptionValue::SubCommand(FixedArray::default()), }, CommandDataOption { - name: "autocomplete".into(), + name: "autocomplete".to_string().into(), value: CommandDataOptionValue::Autocomplete { kind: CommandOptionType::Integer, - value: "not an integer".into(), + value: "not an integer".to_string().into(), }, }, ]; diff --git a/src/model/application/component.rs b/src/model/application/component.rs index 3f45b8ecea3..91a1d9e297e 100644 --- a/src/model/application/component.rs +++ b/src/model/application/component.rs @@ -37,7 +37,7 @@ pub struct ActionRow { pub kind: ComponentType, /// The components of this ActionRow. #[serde(default)] - pub components: Vec, + pub components: FixedArray, } /// A component which can be inside of an [`ActionRow`]. @@ -104,8 +104,8 @@ impl From for ActionRowComponent { #[derive(Clone, Debug, Deserialize, PartialEq, Eq)] #[serde(untagged)] pub enum ButtonKind { - Link { url: String }, - NonLink { custom_id: String, style: ButtonStyle }, + Link { url: FixedString }, + NonLink { custom_id: FixedString, style: ButtonStyle }, } impl Serialize for ButtonKind { @@ -158,7 +158,7 @@ pub struct Button { pub data: ButtonKind, /// The text which appears on the button. #[serde(skip_serializing_if = "Option::is_none")] - pub label: Option, + pub label: Option, /// The emoji of this button, if there is one. #[serde(skip_serializing_if = "Option::is_none")] pub emoji: Option, @@ -196,17 +196,17 @@ pub struct SelectMenu { #[serde(rename = "type")] pub kind: ComponentType, /// An identifier defined by the developer for the select menu. - pub custom_id: Option, + pub custom_id: Option, /// The options of this select menu. /// /// Required for [`ComponentType::StringSelect`] and unavailable for all others. #[serde(default)] - pub options: Vec, + pub options: FixedArray, /// List of channel types to include in the [`ComponentType::ChannelSelect`]. #[serde(default)] - pub channel_types: Vec, + pub channel_types: FixedArray, /// The placeholder shown when nothing is selected. - pub placeholder: Option, + pub placeholder: Option, /// The minimum number of selections allowed. pub min_values: Option, /// The maximum number of selections allowed. @@ -224,11 +224,11 @@ pub struct SelectMenu { #[non_exhaustive] pub struct SelectMenuOption { /// The text displayed on this option. - pub label: String, + pub label: FixedString, /// The value to be sent for this option. - pub value: String, + pub value: FixedString, /// The description shown for this option. - pub description: Option, + pub description: Option, /// The emoji displayed on this option. pub emoji: Option, /// Render this option as the default selection. @@ -247,7 +247,7 @@ pub struct InputText { #[serde(rename = "type")] pub kind: ComponentType, /// Developer-defined identifier for the input; max 100 characters - pub custom_id: String, + pub custom_id: FixedString, /// The [`InputTextStyle`]. Required when sending modal data. /// /// Discord docs are wrong here; it says the field is always sent in modal submit interactions @@ -259,7 +259,7 @@ pub struct InputText { /// Discord docs are wrong here; it says the field is always sent in modal submit interactions /// but it's not. It's only required when _sending_ modal data to Discord. /// - pub label: Option, + pub label: Option>, /// Minimum input length for a text input; min 0, max 4000 #[serde(skip_serializing_if = "Option::is_none")] pub min_length: Option, @@ -273,10 +273,10 @@ pub struct InputText { /// /// When receiving: The input from the user (always Some) #[serde(skip_serializing_if = "Option::is_none")] - pub value: Option, + pub value: Option>, /// Custom placeholder text if the input is empty; max 100 characters #[serde(skip_serializing_if = "Option::is_none")] - pub placeholder: Option, + pub placeholder: Option>, } enum_number! { @@ -304,10 +304,10 @@ mod tests { let mut button = Button { kind: ComponentType::Button, data: ButtonKind::NonLink { - custom_id: "hello".into(), + custom_id: "hello".to_string().into(), style: ButtonStyle::Danger, }, - label: Some("a".into()), + label: Some("a".to_string().into()), emoji: None, disabled: false, }; @@ -317,7 +317,7 @@ mod tests { ); button.data = ButtonKind::Link { - url: "https://google.com".into(), + url: "https://google.com".to_string().into(), }; assert_json( &button, diff --git a/src/model/application/component_interaction.rs b/src/model/application/component_interaction.rs index a701f67b145..b0fd0a543eb 100644 --- a/src/model/application/component_interaction.rs +++ b/src/model/application/component_interaction.rs @@ -49,7 +49,7 @@ pub struct ComponentInteraction { #[serde(default)] pub user: User, /// A continuation token for responding to the interaction. - pub token: String, + pub token: FixedString, /// Always `1`. pub version: u8, /// The message this interaction was triggered by, if it is a component. @@ -57,9 +57,9 @@ pub struct ComponentInteraction { /// Permissions the app or bot has within the channel the interaction was sent from. pub app_permissions: Option, /// The selected language of the invoking user. - pub locale: String, + pub locale: FixedString, /// The guild's preferred locale. - pub guild_locale: Option, + pub guild_locale: Option, /// For monetized applications, any entitlements of the invoking user. pub entitlements: Vec, } @@ -247,11 +247,11 @@ impl Serialize for ComponentInteraction { #[derive(Clone, Debug)] pub enum ComponentInteractionDataKind { Button, - StringSelect { values: Vec }, - UserSelect { values: Vec }, - RoleSelect { values: Vec }, - MentionableSelect { values: Vec }, - ChannelSelect { values: Vec }, + StringSelect { values: FixedArray }, + UserSelect { values: FixedArray }, + RoleSelect { values: FixedArray }, + MentionableSelect { values: FixedArray }, + ChannelSelect { values: FixedArray }, Unknown(u8), } @@ -332,7 +332,7 @@ impl Serialize for ComponentInteractionDataKind { #[non_exhaustive] pub struct ComponentInteractionData { /// The custom id of the component. - pub custom_id: String, + pub custom_id: FixedString, /// Type and type-specific data of this component interaction. #[serde(flatten)] pub kind: ComponentInteractionDataKind, diff --git a/src/model/application/interaction.rs b/src/model/application/interaction.rs index 30ef9432e2b..f9f197795fe 100644 --- a/src/model/application/interaction.rs +++ b/src/model/application/interaction.rs @@ -304,7 +304,7 @@ pub struct MessageInteraction { /// The name of the [`Command`]. /// /// [`Command`]: crate::model::application::Command - pub name: String, + pub name: FixedString, /// The user who invoked the interaction. pub user: User, /// The member who invoked the interaction in the guild. diff --git a/src/model/application/mod.rs b/src/model/application/mod.rs index beba0955749..500fac94c15 100644 --- a/src/model/application/mod.rs +++ b/src/model/application/mod.rs @@ -21,6 +21,7 @@ use super::id::{ApplicationId, GenericId, GuildId, SkuId, UserId}; use super::misc::ImageHash; use super::user::User; use super::Permissions; +use crate::internal::prelude::*; /// Partial information about the given application. /// @@ -42,29 +43,29 @@ pub struct PartialCurrentApplicationInfo { #[non_exhaustive] pub struct CurrentApplicationInfo { pub id: ApplicationId, - pub name: String, + pub name: FixedString, pub icon: Option, - pub description: String, + pub description: FixedString, #[serde(default)] - pub rpc_origins: Vec, + pub rpc_origins: FixedArray, pub bot_public: bool, pub bot_require_code_grant: bool, #[serde(default)] - pub terms_of_service_url: Option, + pub terms_of_service_url: Option, #[serde(default)] - pub privacy_policy_url: Option, + pub privacy_policy_url: Option, pub owner: Option, // omitted `summary` because it deprecated - pub verify_key: String, + pub verify_key: FixedString, pub team: Option, #[serde(default)] pub guild_id: Option, #[serde(default)] pub primary_sku_id: Option, #[serde(default)] - pub slug: Option, + pub slug: Option, #[serde(default)] - pub cover_image: Option, + pub cover_image: Option, #[serde(default)] pub flags: Option, #[serde(default)] @@ -72,10 +73,10 @@ pub struct CurrentApplicationInfo { #[serde(default)] pub install_params: Option, #[serde(default)] - pub custom_install_url: Option, + pub custom_install_url: Option, /// The application's role connection verification entry point, which when configured will /// render the app as a verification method in the guild role verification configuration. - pub role_connections_verification_url: Option, + pub role_connections_verification_url: Option, } /// Information about the Team group of the application. @@ -89,9 +90,9 @@ pub struct Team { /// The snowflake ID of the team. pub id: GenericId, /// The name of the team. - pub name: String, + pub name: FixedString, /// The members of the team - pub members: Vec, + pub members: FixedArray, /// The user id of the team owner. pub owner_user_id: UserId, } @@ -107,7 +108,7 @@ pub struct TeamMember { /// The list of permissions of the member on the team. /// /// NOTE: Will always be ["*"] for now. - pub permissions: Vec, + pub permissions: FixedArray, /// The ID of the team they are a member of. pub team_id: GenericId, /// The user type of the team member. @@ -168,6 +169,6 @@ bitflags! { #[derive(Debug, Clone, Serialize, Deserialize)] #[non_exhaustive] pub struct InstallParams { - pub scopes: Vec, + pub scopes: FixedArray, pub permissions: Permissions, } diff --git a/src/model/application/modal_interaction.rs b/src/model/application/modal_interaction.rs index fcb04db26b1..e5091706363 100644 --- a/src/model/application/modal_interaction.rs +++ b/src/model/application/modal_interaction.rs @@ -43,7 +43,7 @@ pub struct ModalInteraction { #[serde(default)] pub user: User, /// A continuation token for responding to the interaction. - pub token: String, + pub token: FixedString, /// Always `1`. pub version: u8, /// The message this interaction was triggered by @@ -55,9 +55,9 @@ pub struct ModalInteraction { /// Permissions the app or bot has within the channel the interaction was sent from. pub app_permissions: Option, /// The selected language of the invoking user. - pub locale: String, + pub locale: FixedString, /// The guild's preferred locale. - pub guild_locale: Option, + pub guild_locale: Option, /// For monetized applications, any entitlements of the invoking user. pub entitlements: Vec, } @@ -219,7 +219,7 @@ impl Serialize for ModalInteraction { #[non_exhaustive] pub struct ModalInteractionData { /// The custom id of the modal - pub custom_id: String, + pub custom_id: FixedString, /// The components. - pub components: Vec, + pub components: FixedArray, } diff --git a/src/model/application/ping_interaction.rs b/src/model/application/ping_interaction.rs index 269f377a0c8..c8bd3b14930 100644 --- a/src/model/application/ping_interaction.rs +++ b/src/model/application/ping_interaction.rs @@ -1,5 +1,6 @@ use serde::{Deserialize, Serialize}; +use crate::internal::prelude::*; use crate::model::id::{ApplicationId, InteractionId}; /// A ping interaction, which can only be received through an endpoint url. @@ -14,7 +15,7 @@ pub struct PingInteraction { /// Id of the application this interaction is for. pub application_id: ApplicationId, /// A continuation token for responding to the interaction. - pub token: String, + pub token: FixedString, /// Always `1`. pub version: u8, } diff --git a/src/model/channel/attachment.rs b/src/model/channel/attachment.rs index 08e7d5956e6..9b294a5ce21 100644 --- a/src/model/channel/attachment.rs +++ b/src/model/channel/attachment.rs @@ -1,7 +1,6 @@ #[cfg(feature = "model")] use reqwest::Client as ReqwestClient; -#[cfg(feature = "model")] use crate::internal::prelude::*; use crate::model::prelude::*; use crate::model::utils::{is_false, CowStr}; @@ -36,23 +35,23 @@ pub struct Attachment { pub id: AttachmentId, /// The filename of the file that was uploaded. This is equivalent to what the uploader had /// their file named. - pub filename: String, + pub filename: FixedString, /// Sescription for the file (max 1024 characters). - pub description: Option, + pub description: Option>, /// If the attachment is an image, then the height of the image is provided. pub height: Option, /// The proxy URL. - pub proxy_url: String, + pub proxy_url: FixedString, /// The size of the file in bytes. pub size: u32, /// The URL of the uploaded attachment. - pub url: String, + pub url: FixedString, /// If the attachment is an image, then the width of the image is provided. pub width: Option, /// The attachment's [media type]. /// /// [media type]: https://en.wikipedia.org/wiki/Media_type - pub content_type: Option, + pub content_type: Option, /// Whether this attachment is ephemeral. /// /// Ephemeral attachments will automatically be removed after a set period of time. @@ -151,7 +150,7 @@ impl Attachment { /// [`Message`]: super::Message pub async fn download(&self) -> Result> { let reqwest = ReqwestClient::new(); - let bytes = reqwest.get(&self.url).send().await?.bytes().await?; + let bytes = reqwest.get(&*self.url).send().await?.bytes().await?; Ok(bytes.to_vec()) } } diff --git a/src/model/channel/channel_id.rs b/src/model/channel/channel_id.rs index 7b92c942d3f..1926bc722bb 100644 --- a/src/model/channel/channel_id.rs +++ b/src/model/channel/channel_id.rs @@ -28,6 +28,7 @@ use crate::collector::{MessageCollector, ReactionCollector}; use crate::gateway::ShardMessenger; #[cfg(feature = "model")] use crate::http::{CacheHttp, Http, Typing}; +use crate::internal::prelude::*; #[cfg(feature = "model")] use crate::json::json; use crate::model::prelude::*; @@ -530,7 +531,7 @@ impl ChannelId { /// # Errors /// /// Same as [`Self::to_channel()`]. - pub async fn name(self, cache_http: impl CacheHttp) -> Result { + pub async fn name(self, cache_http: impl CacheHttp) -> Result> { let channel = self.to_channel(cache_http).await?; Ok(match channel { diff --git a/src/model/channel/embed.rs b/src/model/channel/embed.rs index afc849436f7..2b3f0ad1aed 100644 --- a/src/model/channel/embed.rs +++ b/src/model/channel/embed.rs @@ -1,3 +1,4 @@ +use crate::internal::prelude::*; use crate::model::{Colour, Timestamp}; /// Represents a rich embed which allows using richer markdown, multiple fields and more. This was @@ -17,20 +18,20 @@ use crate::model::{Colour, Timestamp}; pub struct Embed { /// The title of the embed. #[serde(skip_serializing_if = "Option::is_none")] - pub title: Option, + pub title: Option>, /// The type of the embed. For embeds not generated by Discord's backend, this will always be /// "rich". #[serde(rename = "type")] #[serde(skip_serializing_if = "Option::is_none")] - pub kind: Option, + pub kind: Option>, /// The description of the embed. /// /// The maximum value for this field is 2048 unicode codepoints. #[serde(skip_serializing_if = "Option::is_none")] - pub description: Option, + pub description: Option>, /// The URL of the embed. #[serde(skip_serializing_if = "Option::is_none")] - pub url: Option, + pub url: Option, /// Timestamp information. #[serde(skip_serializing_if = "Option::is_none")] pub timestamp: Option, @@ -77,18 +78,18 @@ pub struct Embed { #[non_exhaustive] pub struct EmbedAuthor { /// The name of the author. - pub name: String, + pub name: FixedString, /// The URL of the author. #[serde(skip_serializing_if = "Option::is_none")] - pub url: Option, + pub url: Option, /// The URL of the author icon. /// /// This only supports HTTP(S) and attachments. #[serde(skip_serializing_if = "Option::is_none")] - pub icon_url: Option, + pub icon_url: Option, /// A proxied URL of the author icon. #[serde(skip_serializing_if = "Option::is_none")] - pub proxy_icon_url: Option, + pub proxy_icon_url: Option, } /// A field object in an embed. @@ -101,11 +102,11 @@ pub struct EmbedField { /// The name of the field. /// /// The maximum length of this field is 512 unicode codepoints. - pub name: String, + pub name: FixedString, /// The value of the field. /// /// The maximum length of this field is 1024 unicode codepoints. - pub value: String, + pub value: FixedString, /// Indicator of whether the field should display as inline. #[serde(default)] pub inline: bool, @@ -121,10 +122,14 @@ impl EmbedField { T: Into, U: Into, { - Self::_new(name.into(), value.into(), inline) + Self::_new(name.into().into(), value.into().into(), inline) } - pub(crate) const fn _new(name: String, value: String, inline: bool) -> Self { + pub(crate) const fn _new( + name: FixedString, + value: FixedString, + inline: bool, + ) -> Self { Self { name, value, @@ -141,15 +146,15 @@ impl EmbedField { #[non_exhaustive] pub struct EmbedFooter { /// The associated text with the footer. - pub text: String, + pub text: FixedString, /// The URL of the footer icon. /// /// This only supports HTTP(S) and attachments. #[serde(skip_serializing_if = "Option::is_none")] - pub icon_url: Option, + pub icon_url: Option, /// A proxied URL of the footer icon. #[serde(skip_serializing_if = "Option::is_none")] - pub proxy_icon_url: Option, + pub proxy_icon_url: Option, } /// An image object in an embed. @@ -162,9 +167,9 @@ pub struct EmbedImage { /// Source URL of the image. /// /// This only supports HTTP(S) and attachments. - pub url: String, + pub url: FixedString, /// A proxied URL of the image. - pub proxy_url: Option, + pub proxy_url: Option, /// The height of the image. pub height: Option, /// The width of the image. @@ -179,9 +184,9 @@ pub struct EmbedImage { #[non_exhaustive] pub struct EmbedProvider { /// The name of the provider. - pub name: Option, + pub name: Option, /// The URL of the provider. - pub url: Option, + pub url: Option, } /// The dimensions and URL of an embed thumbnail. @@ -194,9 +199,9 @@ pub struct EmbedThumbnail { /// The source URL of the thumbnail. /// /// This only supports HTTP(S) and attachments. - pub url: String, + pub url: FixedString, /// A proxied URL of the thumbnail. - pub proxy_url: Option, + pub proxy_url: Option, /// The height of the thumbnail in pixels. pub height: Option, /// The width of the thumbnail in pixels. @@ -211,9 +216,9 @@ pub struct EmbedThumbnail { #[non_exhaustive] pub struct EmbedVideo { /// The source URL of the video. - pub url: String, + pub url: FixedString, /// A proxied URL of the thumbnail. - pub proxy_url: Option, + pub proxy_url: Option, /// The height of the video in pixels. pub height: Option, /// The width of the video in pixels. diff --git a/src/model/channel/guild_channel.rs b/src/model/channel/guild_channel.rs index 1afd459be89..beb5b4dbc41 100644 --- a/src/model/channel/guild_channel.rs +++ b/src/model/channel/guild_channel.rs @@ -27,7 +27,6 @@ use crate::collector::{MessageCollector, ReactionCollector}; use crate::gateway::ShardMessenger; #[cfg(feature = "model")] use crate::http::{CacheHttp, Http, Typing}; -#[cfg(all(feature = "cache", feature = "model"))] use crate::internal::prelude::*; use crate::model::prelude::*; @@ -72,11 +71,11 @@ pub struct GuildChannel { /// /// **Note**: This is only available for text channels. pub last_pin_timestamp: Option, - /// The name of the channel. - pub name: String, + /// The name of the channel. (1-100 characters) + pub name: FixedString, /// Permission overwrites for [`Member`]s and for [`Role`]s. #[serde(default)] - pub permission_overwrites: Vec, + pub permission_overwrites: FixedArray, /// The position of the channel. /// /// The default text channel will _almost always_ have a position of `0`. @@ -85,7 +84,7 @@ pub struct GuildChannel { /// The topic of the channel. /// /// **Note**: This is only available for text, forum and stage channels. - pub topic: Option, + pub topic: Option>, /// The maximum number of members allowed in the channel. /// /// **Note**: This is only available for voice channels. @@ -105,7 +104,7 @@ pub struct GuildChannel { /// /// **Note**: This is only available for voice and stage channels. [`None`] for voice and stage /// channels means automatic region selection. - pub rtc_region: Option, + pub rtc_region: Option>, /// The video quality mode for a voice channel. pub video_quality_mode: Option, /// An approximate count of messages in the thread. @@ -144,12 +143,12 @@ pub struct GuildChannel { /// /// **Note**: This is only available in forum channels. #[serde(default)] - pub available_tags: Vec, + pub available_tags: FixedArray, /// The set of applied tags. /// /// **Note**: This is only available in a thread in a forum. #[serde(default)] - pub applied_tags: Vec, + pub applied_tags: FixedArray, /// The emoji to show in the add reaction button /// /// **Note**: This is only available in a forum. @@ -162,7 +161,7 @@ pub struct GuildChannel { /// The status of a voice channel. /// /// **Note**: This is only available in voice channels. - pub status: Option, + pub status: Option>, /// The default sort order type used to order posts /// /// **Note**: This is only available in a forum. diff --git a/src/model/channel/message.rs b/src/model/channel/message.rs index 3fd40a32302..2c30ca97075 100644 --- a/src/model/channel/message.rs +++ b/src/model/channel/message.rs @@ -21,6 +21,7 @@ use crate::constants; use crate::gateway::ShardMessenger; #[cfg(feature = "model")] use crate::http::{CacheHttp, Http}; +use crate::internal::prelude::*; use crate::model::prelude::*; use crate::model::utils::StrOrInt; #[cfg(all(feature = "model", feature = "cache"))] @@ -41,7 +42,7 @@ pub struct Message { /// The user that sent the message. pub author: User, /// The content of the message. - pub content: String, + pub content: FixedString, /// Initial message creation timestamp, calculated from its Id. pub timestamp: Timestamp, /// The timestamp of the last time the message was updated, if it was. @@ -53,9 +54,9 @@ pub struct Message { /// Indicator of whether the message mentions everyone. pub mention_everyone: bool, /// Array of users mentioned in the message. - pub mentions: Vec, + pub mentions: FixedArray, /// Array of [`Role`]s' Ids mentioned in the message. - pub mention_roles: Vec, + pub mention_roles: FixedArray, /// Channels specifically mentioned in this message. /// /// **Note**: Not all channel mentions in a message will appear in [`Self::mention_channels`]. @@ -73,15 +74,15 @@ pub struct Message { /// [Refer to Discord's documentation for more information][discord-docs]. /// /// [discord-docs]: https://discord.com/developers/docs/resources/channel#message-object - #[serde(default = "Vec::new")] - pub mention_channels: Vec, + #[serde(default)] + pub mention_channels: FixedArray, /// An vector of the files attached to a message. - pub attachments: Vec, + pub attachments: FixedArray, /// Array of embeds sent with the message. - pub embeds: Vec, + pub embeds: FixedArray, /// Array of reactions performed on the message. #[serde(default)] - pub reactions: Vec, + pub reactions: FixedArray, /// Non-repeating number used for ensuring message order. #[serde(default)] pub nonce: Option, @@ -114,10 +115,10 @@ pub struct Message { pub thread: Option>, /// The components of this message #[serde(default)] - pub components: Vec, + pub components: FixedArray, /// Array of message sticker item objects. #[serde(default)] - pub sticker_items: Vec, + pub sticker_items: FixedArray, /// A generally increasing integer (there may be gaps or duplicates) that represents the /// approximate position of the message in a thread, it can be used to estimate the relative /// position of the message in a thread in company with total_message_sent on parent thread. @@ -361,7 +362,7 @@ impl Message { /// names and everyone/here mentions cancelled. #[cfg(feature = "cache")] pub fn content_safe(&self, cache: impl AsRef) -> String { - let mut result = self.content.clone(); + let mut result = self.content.to_string(); // First replace all user mentions. for u in &self.mentions { @@ -955,11 +956,11 @@ pub struct MessageApplication { /// ID of the embed's image asset. pub cover_image: Option, /// Application's description. - pub description: String, + pub description: FixedString, /// ID of the application's icon. pub icon: Option, /// Name of the application. - pub name: String, + pub name: FixedString, } /// Rich Presence activity information. @@ -973,7 +974,7 @@ pub struct MessageActivity { #[serde(rename = "type")] pub kind: MessageActivityKind, /// `party_id` from a Rich Presence event. - pub party_id: Option, + pub party_id: Option, } /// Reference data sent with crossposted messages. @@ -1029,7 +1030,7 @@ pub struct ChannelMention { #[serde(rename = "type")] pub kind: ChannelType, /// The name of the channel - pub name: String, + pub name: FixedString, } bitflags! { @@ -1130,7 +1131,7 @@ pub struct RoleSubscriptionData { /// The id of the sku and listing that the user is subscribed to. pub role_subscription_listing_id: SkuId, /// The name of the tier that the user is subscribed to. - pub tier_name: String, + pub tier_name: FixedString, /// The cumulative number of months that the user has been subscribed for. pub total_months_subscribed: u16, /// Whether this notification is for a renewal rather than a new purchase. diff --git a/src/model/channel/mod.rs b/src/model/channel/mod.rs index d04b0bc1005..e16f0c1b319 100644 --- a/src/model/channel/mod.rs +++ b/src/model/channel/mod.rs @@ -23,6 +23,7 @@ pub use self::private_channel::*; pub use self::reaction::*; #[cfg(feature = "model")] use crate::http::CacheHttp; +use crate::internal::prelude::*; use crate::json::*; use crate::model::prelude::*; use crate::model::utils::is_false; @@ -422,7 +423,7 @@ pub struct StageInstance { /// The Id of the associated stage channel. pub channel_id: ChannelId, /// The topic of the stage instance. - pub topic: String, + pub topic: FixedString, /// The privacy level of the Stage instance. pub privacy_level: StageInstancePrivacyLevel, /// Whether or not Stage Discovery is disabled (deprecated). @@ -471,9 +472,9 @@ pub struct ThreadMetadata { #[non_exhaustive] pub struct ThreadsData { /// The threads channels. - pub threads: Vec, + pub threads: FixedArray, /// A thread member for each returned thread the current user has joined. - pub members: Vec, + pub members: FixedArray, /// Whether there are potentially more threads that could be returned on a subsequent call. #[serde(default)] pub has_more: bool, @@ -490,13 +491,13 @@ pub enum ForumEmoji { /// The id of a guild's custom emoji. Id(EmojiId), /// The unicode character of the emoji. - Name(String), + Name(FixedString), } #[derive(Serialize, Deserialize)] struct RawForumEmoji { emoji_id: Option, - emoji_name: Option, + emoji_name: Option, } impl serde::Serialize for ForumEmoji { @@ -541,7 +542,7 @@ pub struct ForumTag { /// The id of the tag. pub id: ForumTagId, /// The name of the tag (0-20 characters). - pub name: String, + pub name: FixedString, /// Whether this tag can only be added to or removed from threads by a member with the /// MANAGE_THREADS permission. pub moderated: bool, diff --git a/src/model/channel/partial_channel.rs b/src/model/channel/partial_channel.rs index 663eac6d052..1e544c9d115 100644 --- a/src/model/channel/partial_channel.rs +++ b/src/model/channel/partial_channel.rs @@ -1,3 +1,4 @@ +use crate::internal::prelude::*; use crate::model::channel::{ChannelType, ThreadMetadata}; use crate::model::id::{ChannelId, WebhookId}; use crate::model::Permissions; @@ -13,7 +14,7 @@ pub struct PartialChannel { /// The channel Id. pub id: ChannelId, /// The channel name. - pub name: Option, + pub name: Option, /// The channel type. #[serde(rename = "type")] pub kind: ChannelType, diff --git a/src/model/channel/private_channel.rs b/src/model/channel/private_channel.rs index 6eb441a41d0..cf18664a5c5 100644 --- a/src/model/channel/private_channel.rs +++ b/src/model/channel/private_channel.rs @@ -8,6 +8,7 @@ use crate::builder::{CreateAttachment, CreateMessage, EditMessage, GetMessages}; use crate::http::CacheHttp; #[cfg(feature = "model")] use crate::http::{Http, Typing}; +use crate::internal::prelude::*; use crate::model::prelude::*; use crate::model::utils::single_recipient; @@ -199,8 +200,8 @@ impl PrivateChannel { /// Returns "DM with $username#discriminator". #[must_use] - pub fn name(&self) -> String { - format!("DM with {}", self.recipient.tag()) + pub fn name(&self) -> FixedString { + format!("DM with {}", self.recipient.tag()).into() } /// Gets the list of [`User`]s who have reacted to a [`Message`] with a certain [`Emoji`]. diff --git a/src/model/channel/reaction.rs b/src/model/channel/reaction.rs index 91e211b8a18..3c2c508488e 100644 --- a/src/model/channel/reaction.rs +++ b/src/model/channel/reaction.rs @@ -265,10 +265,10 @@ pub enum ReactionType { id: EmojiId, /// The name of the custom emoji. This is primarily used for decoration and distinguishing /// the emoji client-side. - name: Option, + name: Option, }, /// A reaction with a twemoji. - Unicode(String), + Unicode(FixedString), } // Manual impl needed to decide enum variant by presence of `id` @@ -279,7 +279,7 @@ impl<'de> Deserialize<'de> for ReactionType { #[serde(default)] animated: bool, id: Option, - name: Option, + name: Option, } let emoji = PartialEmoji::deserialize(deserializer)?; Ok(match (emoji.id, emoji.name) { @@ -353,7 +353,7 @@ impl ReactionType { #[must_use] pub fn unicode_eq(&self, other: &str) -> bool { if let ReactionType::Unicode(unicode) = &self { - unicode == other + &**unicode == other } else { // Always return false if not a unicode reaction false @@ -395,7 +395,7 @@ impl From for ReactionType { /// # fn main() {} /// ``` fn from(ch: char) -> ReactionType { - ReactionType::Unicode(ch.to_string()) + ReactionType::Unicode(ch.to_string().into()) } } @@ -449,7 +449,7 @@ impl TryFrom for ReactionType { } if !emoji_string.starts_with('<') { - return Ok(ReactionType::Unicode(emoji_string)); + return Ok(ReactionType::Unicode(emoji_string.into())); } ReactionType::try_from(&emoji_string[..]) } @@ -489,7 +489,7 @@ impl<'a> TryFrom<&'a str> for ReactionType { /// let reaction2 = ReactionType::Custom { /// animated: false, /// id: EmojiId::new(600404340292059257), - /// name: Some("customemoji".to_string()), + /// name: Some("customemoji".to_string().into()), /// }; /// /// assert_eq!(reaction, reaction2); @@ -503,7 +503,7 @@ impl<'a> TryFrom<&'a str> for ReactionType { } if !emoji_str.starts_with('<') { - return Ok(ReactionType::Unicode(emoji_str.to_string())); + return Ok(ReactionType::Unicode(emoji_str.to_string().into())); } if !emoji_str.ends_with('>') { @@ -515,7 +515,7 @@ impl<'a> TryFrom<&'a str> for ReactionType { let mut split_iter = emoji_str.split(':'); let animated = split_iter.next().ok_or(ReactionConversionError)? == "a"; - let name = split_iter.next().ok_or(ReactionConversionError)?.to_string().into(); + let name = Some(split_iter.next().ok_or(ReactionConversionError)?.to_string().into()); let id = split_iter.next().and_then(|s| s.parse().ok()).ok_or(ReactionConversionError)?; Ok(ReactionType::Custom { diff --git a/src/model/connection.rs b/src/model/connection.rs index 7968fccdd50..338e4c03727 100644 --- a/src/model/connection.rs +++ b/src/model/connection.rs @@ -1,6 +1,7 @@ //! Models for user connections. use super::prelude::*; +use crate::internal::prelude::*; /// Information about a connection between the current user and a third party service. /// @@ -9,20 +10,20 @@ use super::prelude::*; #[non_exhaustive] pub struct Connection { /// The ID of the account on the other side of this connection. - pub id: String, + pub id: FixedString, /// The username of the account on the other side of this connection. - pub name: String, + pub name: FixedString, /// The service that this connection represents (e.g. twitch, youtube) /// /// [Discord docs](https://discord.com/developers/docs/resources/user#connection-object-services). #[serde(rename = "type")] - pub kind: String, + pub kind: FixedString, /// Whether this connection has been revoked and is no longer valid. #[serde(default)] pub revoked: bool, /// A list of partial guild [`Integration`]s that use this connection. #[serde(default)] - pub integrations: Vec, + pub integrations: FixedArray, /// Whether this connection has been verified and the user has proven they own the account. pub verified: bool, /// Whether friend sync is enabled for this connection. diff --git a/src/model/event.rs b/src/model/event.rs index 77226c1be1d..c2b21995b0c 100644 --- a/src/model/event.rs +++ b/src/model/event.rs @@ -19,6 +19,8 @@ use crate::model::utils::{ remove_from_map_opt, stickers, }; +use crate::constants::Opcode; +use crate::internal::prelude::*; /// Requires no gateway intents. /// @@ -247,9 +249,9 @@ pub struct GuildMemberRemoveEvent { #[non_exhaustive] pub struct GuildMemberUpdateEvent { pub guild_id: GuildId, - pub nick: Option, + pub nick: Option>, pub joined_at: Timestamp, - pub roles: Vec, + pub roles: FixedArray, pub user: User, pub premium_since: Option, #[serde(default)] @@ -283,12 +285,12 @@ pub struct GuildMembersChunkEvent { /// When passing an invalid ID to [`crate::gateway::ShardRunnerMessage::ChunkGuild`], it will /// be returned here. #[serde(default)] - pub not_found: Vec, + pub not_found: FixedArray, /// When passing true to [`crate::gateway::ShardRunnerMessage::ChunkGuild`], presences of the /// returned members will be here. pub presences: Option>, /// Nonce used in the [`crate::gateway::ShardRunnerMessage::ChunkGuild`] request. - pub nonce: Option, + pub nonce: Option, } // Manual impl needed to insert guild_id fields in Member @@ -390,7 +392,7 @@ pub struct InviteCreateEvent { /// Channel the invite is for. pub channel_id: ChannelId, /// Unique invite [code](Invite::code). - pub code: String, + pub code: FixedString, /// Time at which the invite was created. pub created_at: Timestamp, /// Guild of the invite. @@ -422,7 +424,7 @@ pub struct InviteCreateEvent { pub struct InviteDeleteEvent { pub channel_id: ChannelId, pub guild_id: Option, - pub code: String, + pub code: FixedString, } /// Requires [`GatewayIntents::GUILDS`]. @@ -457,7 +459,7 @@ pub struct MessageCreateEvent { pub struct MessageDeleteBulkEvent { pub guild_id: Option, pub channel_id: ChannelId, - pub ids: Vec, + pub ids: FixedArray, } /// Requires [`GatewayIntents::GUILD_MESSAGES`] or [`GatewayIntents::DIRECT_MESSAGES`]. @@ -498,17 +500,17 @@ pub struct MessageUpdateEvent { pub id: MessageId, pub channel_id: ChannelId, pub author: Option, - pub content: Option, + pub content: Option>, pub timestamp: Option, pub edited_timestamp: Option, pub tts: Option, pub mention_everyone: Option, - pub mentions: Option>, - pub mention_roles: Option>, - pub mention_channels: Option>, - pub attachments: Option>, - pub embeds: Option>, - pub reactions: Option>, + pub mentions: Option>, + pub mention_roles: Option>, + pub mention_channels: Option>, + pub attachments: Option>, + pub embeds: Option>, + pub reactions: Option>, pub pinned: Option, #[serde(default, deserialize_with = "deserialize_some")] pub webhook_id: Option>, @@ -529,8 +531,8 @@ pub struct MessageUpdateEvent { pub interaction: Option>>, #[serde(default, deserialize_with = "deserialize_some")] pub thread: Option>>, - pub components: Option>, - pub sticker_items: Option>, + pub components: Option>, + pub sticker_items: Option>, pub position: Option>, pub role_subscription_data: Option>, pub guild_id: Option, @@ -633,7 +635,7 @@ pub struct PresenceUpdateEvent { #[serde(transparent)] #[non_exhaustive] pub struct PresencesReplaceEvent { - pub presences: Vec, + pub presences: FixedArray, } /// Requires [`GatewayIntents::GUILD_MESSAGE_REACTIONS`] or @@ -733,7 +735,7 @@ pub struct TypingStartEvent { #[non_exhaustive] pub struct UnknownEvent { #[serde(rename = "t")] - pub kind: String, + pub kind: FixedString, #[serde(rename = "d")] pub value: Value, } @@ -758,9 +760,9 @@ pub struct UserUpdateEvent { #[derive(Clone, Debug, Deserialize, Serialize)] #[non_exhaustive] pub struct VoiceServerUpdateEvent { - pub token: String, + pub token: FixedString, pub guild_id: Option, - pub endpoint: Option, + pub endpoint: Option, } /// Requires [`GatewayIntents::GUILD_VOICE_STATES`]. @@ -781,7 +783,7 @@ pub struct VoiceStateUpdateEvent { #[derive(Clone, Debug, Deserialize, Serialize)] #[non_exhaustive] pub struct VoiceChannelStatusUpdateEvent { - pub status: Option, + pub status: Option>, pub id: ChannelId, pub guild_id: GuildId, } @@ -922,10 +924,10 @@ pub struct ThreadListSyncEvent { /// well, so you know to clear that data. pub channel_ids: Option>, /// All active threads in the given channels that the current user can access. - pub threads: Vec, + pub threads: FixedArray, /// All thread member objects from the synced threads for the current user, indicating which /// threads the current user has been added to - pub members: Vec, + pub members: FixedArray, } /// Requires [`GatewayIntents::GUILDS`], and, to receive this event for other users, @@ -958,10 +960,10 @@ pub struct ThreadMembersUpdateEvent { pub member_count: i16, /// The users who were added to the thread. #[serde(default)] - pub added_members: Vec, + pub added_members: FixedArray, /// The ids of the users who were removed from the thread. #[serde(default)] - pub removed_member_ids: Vec, + pub removed_member_ids: FixedArray, } /// Requires [`GatewayIntents::GUILD_SCHEDULED_EVENTS`]. diff --git a/src/model/gateway.rs b/src/model/gateway.rs index 15ca1a80c94..ed67ea7a2d9 100644 --- a/src/model/gateway.rs +++ b/src/model/gateway.rs @@ -7,6 +7,7 @@ use url::Url; use super::prelude::*; use super::utils::*; +use crate::internal::prelude::*; /// A representation of the data retrieved from the bot gateway endpoint. /// @@ -20,7 +21,7 @@ use super::utils::*; #[non_exhaustive] pub struct BotGateway { /// The gateway to connect to. - pub url: String, + pub url: FixedString, /// The number of shards that is recommended to be used by the current bot user. pub shards: NonZeroU16, /// Information describing how many gateway sessions you can initiate within a ratelimit @@ -42,7 +43,7 @@ pub struct Activity { /// Images for the presence and their texts. pub assets: Option, /// What the user is doing. - pub details: Option, + pub details: Option, /// Activity flags describing what the payload includes. pub flags: Option, /// Whether or not the activity is an instanced game session. @@ -51,13 +52,13 @@ pub struct Activity { #[serde(rename = "type")] pub kind: ActivityType, /// The name of the activity. - pub name: String, + pub name: FixedString, /// Information about the user's current party. pub party: Option, /// Secrets for Rich Presence joining and spectating. pub secrets: Option, /// The user's current party status. - pub state: Option, + pub state: Option, /// Emoji currently used in custom status pub emoji: Option, /// Unix timestamps for the start and/or end times of the activity. @@ -65,18 +66,18 @@ pub struct Activity { /// The sync ID of the activity. Mainly used by the Spotify activity type which uses this /// parameter to store the track ID. #[cfg(feature = "unstable_discord_api")] - pub sync_id: Option, + pub sync_id: Option, /// The session ID of the activity. Reserved for specific activity types, such as the Activity /// that is transmitted when a user is listening to Spotify. #[cfg(feature = "unstable_discord_api")] - pub session_id: Option, + pub session_id: Option, /// The Stream URL if [`Self::kind`] is [`ActivityType::Streaming`]. pub url: Option, /// The buttons of this activity. /// /// **Note**: There can only be up to 2 buttons. #[serde(default, deserialize_with = "deserialize_buttons")] - pub buttons: Vec, + pub buttons: FixedArray, /// Unix timestamp (in milliseconds) of when the activity was added to the user's session pub created_at: u64, } @@ -87,12 +88,12 @@ pub struct Activity { #[non_exhaustive] pub struct ActivityButton { /// The text shown on the button. - pub label: String, + pub label: FixedString, /// The url opened when clicking the button. /// /// **Note**: Bots cannot access activity button URL. #[serde(default)] - pub url: String, + pub url: FixedString, } /// The assets for an activity. @@ -103,13 +104,13 @@ pub struct ActivityButton { #[non_exhaustive] pub struct ActivityAssets { /// The ID for a large asset of the activity, usually a snowflake. - pub large_image: Option, + pub large_image: Option, /// Text displayed when hovering over the large image of the activity. - pub large_text: Option, + pub large_text: Option, /// The ID for a small asset of the activity, usually a snowflake. - pub small_image: Option, + pub small_image: Option, /// Text displayed when hovering over the small image of the activity. - pub small_text: Option, + pub small_text: Option, } bitflags! { @@ -148,7 +149,7 @@ bitflags! { #[non_exhaustive] pub struct ActivityParty { /// The ID of the party. - pub id: Option, + pub id: Option, /// Used to show the party's current and maximum size. pub size: Option<[u32; 2]>, } @@ -161,12 +162,12 @@ pub struct ActivityParty { #[non_exhaustive] pub struct ActivitySecrets { /// The secret for joining a party. - pub join: Option, + pub join: Option, /// The secret for a specific instanced match. #[serde(rename = "match")] - pub match_: Option, + pub match_: Option, /// The secret for spectating an activity. - pub spectate: Option, + pub spectate: Option, } /// Representation of an emoji used in a custom status @@ -177,7 +178,7 @@ pub struct ActivitySecrets { #[non_exhaustive] pub struct ActivityEmoji { /// The name of the emoji. - pub name: String, + pub name: FixedString, /// The id of the emoji. pub id: Option, /// Whether this emoji is animated. @@ -217,7 +218,7 @@ enum_number! { #[non_exhaustive] pub struct Gateway { /// The gateway to connect to. - pub url: String, + pub url: FixedString, } /// Information detailing the current active status of a [`User`]. @@ -248,10 +249,10 @@ pub struct PresenceUser { pub bot: Option, #[serde(default, skip_serializing_if = "Option::is_none", with = "discriminator")] pub discriminator: Option, - pub email: Option, + pub email: Option, pub mfa_enabled: Option, #[serde(rename = "username")] - pub name: Option, + pub name: Option>, pub verified: Option, pub public_flags: Option, } @@ -323,7 +324,7 @@ pub struct Presence { pub status: OnlineStatus, /// [`User`]'s current activities. #[serde(default)] - pub activities: Vec, + pub activities: FixedArray, /// The devices a user are currently active on, if available. pub client_status: Option, } @@ -341,11 +342,11 @@ pub struct Ready { /// Information about the user including email pub user: CurrentUser, /// Guilds the user is in - pub guilds: Vec, + pub guilds: FixedArray, /// Used for resuming connections - pub session_id: String, + pub session_id: FixedString, /// Gateway URL for resuming connections - pub resume_gateway_url: String, + pub resume_gateway_url: FixedString, /// Shard information associated with this session, if sent when identifying pub shard: Option, /// Contains id and flags diff --git a/src/model/guild/audit_log/change.rs b/src/model/guild/audit_log/change.rs index 0c5dcb1ad3d..ed5037b344d 100644 --- a/src/model/guild/audit_log/change.rs +++ b/src/model/guild/audit_log/change.rs @@ -1,3 +1,4 @@ +use crate::internal::prelude::*; use crate::json::Value; use crate::model::channel::PermissionOverwrite; use crate::model::guild::automod::{Action, EventType, TriggerMetadata, TriggerType}; @@ -19,7 +20,7 @@ use crate::model::{Permissions, Timestamp}; #[non_exhaustive] pub struct AffectedRole { pub id: RoleId, - pub name: String, + pub name: FixedString, } #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))] @@ -88,7 +89,7 @@ macro_rules! generate_change { /// Unknown key was changed. Other { - name: String, + name: FixedString, #[serde(skip_serializing_if = "Option::is_none")] #[serde(rename = "old_value")] old_value: Option, diff --git a/src/model/guild/audit_log/mod.rs b/src/model/guild/audit_log/mod.rs index 1e6a6e938cf..ad600e05805 100644 --- a/src/model/guild/audit_log/mod.rs +++ b/src/model/guild/audit_log/mod.rs @@ -10,6 +10,7 @@ mod utils; pub use change::{AffectedRole, Change, EntityType}; use utils::{optional_string, users, webhooks}; +use crate::internal::prelude::*; use crate::model::prelude::*; /// Determines the action that was done on a target. @@ -294,20 +295,20 @@ pub enum VoiceChannelStatusAction { pub struct AuditLogs { /// List of audit log entries, sorted from most to least recent. #[serde(rename = "audit_log_entries")] - pub entries: Vec, + pub entries: FixedArray, /// List of auto moderation rules referenced in the audit log. - pub auto_moderation_rules: Vec, + pub auto_moderation_rules: FixedArray, /// List of application commands referenced in the audit log. - pub application_commands: Vec, + pub application_commands: FixedArray, /// List of guild scheduled events referenced in the audit log. - pub guild_scheduled_events: Vec, + pub guild_scheduled_events: FixedArray, /// List of partial integration objects. - pub integrations: Vec, + pub integrations: FixedArray, /// List of threads referenced in the audit log. /// /// Threads referenced in THREAD_CREATE and THREAD_UPDATE events are included in the threads /// map since archived threads might not be kept in memory by clients. - pub threads: Vec, + pub threads: FixedArray, /// List of users referenced in the audit log. #[serde(with = "users")] pub users: HashMap, @@ -324,9 +325,9 @@ pub struct AuditLogs { #[non_exhaustive] pub struct PartialIntegration { pub id: IntegrationId, - pub name: String, + pub name: FixedString, #[serde(rename = "type")] - pub kind: String, + pub kind: FixedString, pub account: IntegrationAccount, pub application: Option, } @@ -342,7 +343,7 @@ pub struct AuditLogEntry { #[serde(rename = "action_type")] pub action: Action, /// What was the reasoning by doing an action on a target? If there was one. - pub reason: Option, + pub reason: Option, /// The user that did this action on a target. pub user_id: UserId, /// What changes were made. @@ -360,9 +361,9 @@ pub struct AuditLogEntry { #[non_exhaustive] pub struct Options { /// Name of the Auto Moderation rule that was triggered. - pub auto_moderation_rule_name: Option, + pub auto_moderation_rule_name: Option, /// Trigger type of the Auto Moderation rule that was triggered. - pub auto_moderation_rule_trigger_type: Option, + pub auto_moderation_rule_trigger_type: Option, /// ID of the app whose permissions were targeted. pub application_id: Option, /// Number of days after which inactive members were kicked. @@ -382,16 +383,16 @@ pub struct Options { pub id: Option, /// Type of overwritten entity ("member" or "role"). #[serde(default, rename = "type")] - pub kind: Option, + pub kind: Option, /// Message that was pinned or unpinned. #[serde(default)] pub message_id: Option, /// Name of the role if type is "role" #[serde(default)] - pub role_name: Option, + pub role_name: Option, /// The status of a voice channel when set. #[serde(default)] - pub status: Option, + pub status: Option, } #[cfg(test)] diff --git a/src/model/guild/automod.rs b/src/model/guild/automod.rs index bb5e6d2f1b2..92e469af9a8 100644 --- a/src/model/guild/automod.rs +++ b/src/model/guild/automod.rs @@ -8,6 +8,7 @@ use serde::de::{Deserializer, Error}; use serde::ser::Serializer; use serde::{Deserialize, Serialize}; +use crate::internal::prelude::*; use crate::model::id::*; /// Configured auto moderation rule. @@ -23,7 +24,7 @@ pub struct Rule { /// ID of the guild this rule belongs to. pub guild_id: GuildId, /// Name of the rule. - pub name: String, + pub name: FixedString, /// ID of the user which created the rule. pub creator_id: UserId, /// Event context in which the rule should be checked. @@ -32,17 +33,17 @@ pub struct Rule { #[serde(flatten)] pub trigger: Trigger, /// Actions which will execute when the rule is triggered. - pub actions: Vec, + pub actions: FixedArray, /// Whether the rule is enabled. pub enabled: bool, /// Roles that should not be affected by the rule. /// /// Maximum of 20. - pub exempt_roles: Vec, + pub exempt_roles: FixedArray, /// Channels that should not be affected by the rule. /// /// Maximum of 50. - pub exempt_channels: Vec, + pub exempt_channels: FixedArray, } /// Indicates in what event context a rule should be checked. @@ -330,7 +331,7 @@ pub enum Action { /// Additional explanation that will be shown to members whenever their message is blocked /// /// Maximum of 150 characters - custom_message: Option, + custom_message: Option>, }, /// Logs user content to a specified channel. Alert(ChannelId), @@ -381,15 +382,15 @@ pub struct ActionExecution { /// Requires [`GatewayIntents::MESSAGE_CONTENT`] to receive non-empty values. /// /// [`GatewayIntents::MESSAGE_CONTENT`]: crate::model::gateway::GatewayIntents::MESSAGE_CONTENT - pub content: String, + pub content: FixedString, /// Word or phrase configured in the rule that triggered the rule. - pub matched_keyword: Option, + pub matched_keyword: Option, /// Substring in content that triggered the rule. /// /// Requires [`GatewayIntents::MESSAGE_CONTENT`] to receive non-empty values. /// /// [`GatewayIntents::MESSAGE_CONTENT`]: crate::model::gateway::GatewayIntents::MESSAGE_CONTENT - pub matched_content: Option, + pub matched_content: Option, } /// Helper struct for the (de)serialization of `Action`. @@ -400,7 +401,7 @@ struct RawActionMetadata { #[serde(skip_serializing_if = "Option::is_none")] duration_seconds: Option, #[serde(skip_serializing_if = "Option::is_none")] - custom_message: Option, + custom_message: Option>, } /// Helper struct for the (de)serialization of `Action`. diff --git a/src/model/guild/emoji.rs b/src/model/guild/emoji.rs index 7559b8c5642..6c827ce74e2 100644 --- a/src/model/guild/emoji.rs +++ b/src/model/guild/emoji.rs @@ -1,5 +1,6 @@ use std::fmt; +use crate::internal::prelude::*; use crate::model::id::{EmojiId, RoleId}; use crate::model::user::User; use crate::model::utils::default_true; @@ -23,7 +24,7 @@ pub struct Emoji { pub id: EmojiId, /// The name of the emoji. It must be at least 2 characters long and can only contain /// alphanumeric characters and underscores. - pub name: String, + pub name: FixedString, /// Whether the emoji is managed via an [`Integration`] service. /// /// [`Integration`]: super::Integration @@ -37,7 +38,7 @@ pub struct Emoji { /// /// [`Role`]: super::Role #[serde(default)] - pub roles: Vec, + pub roles: FixedArray, /// The user who created the emoji. pub user: Option, } diff --git a/src/model/guild/guild_id.rs b/src/model/guild/guild_id.rs index b9874753641..82fdf570532 100644 --- a/src/model/guild/guild_id.rs +++ b/src/model/guild/guild_id.rs @@ -1157,7 +1157,7 @@ impl GuildId { #[cfg(feature = "cache")] #[must_use] pub fn name(self, cache: impl AsRef) -> Option { - self.to_guild_cached(cache.as_ref()).map(|g| g.name.clone()) + self.to_guild_cached(cache.as_ref()).map(|g| g.name.to_string()) } /// Disconnects a member from a voice channel in the guild. diff --git a/src/model/guild/guild_preview.rs b/src/model/guild/guild_preview.rs index 75aedcbb736..5514311848e 100644 --- a/src/model/guild/guild_preview.rs +++ b/src/model/guild/guild_preview.rs @@ -1,3 +1,4 @@ +use crate::internal::prelude::*; use crate::model::guild::Emoji; use crate::model::id::GuildId; use crate::model::misc::ImageHash; @@ -14,7 +15,7 @@ pub struct GuildPreview { /// The guild Id. pub id: GuildId, /// The guild name. - pub name: String, + pub name: FixedString, /// The guild icon hash if it has one. pub icon: Option, /// The guild splash hash if it has one. @@ -22,17 +23,17 @@ pub struct GuildPreview { /// The guild discovery splash hash it it has one. pub discovery_splash: Option, /// The custom guild emojis. - pub emojis: Vec, + pub emojis: FixedArray, /// The guild features. See [`Guild::features`] /// /// [`Guild::features`]: super::Guild::features - pub features: Vec, + pub features: FixedArray, /// Approximate number of members in this guild. pub approximate_member_count: u64, /// Approximate number of online members in this guild. pub approximate_presence_count: u64, /// The description for the guild, if the guild has the `DISCOVERABLE` feature. - pub description: Option, + pub description: Option, /// Custom guild stickers. - pub stickers: Vec, + pub stickers: FixedArray, } diff --git a/src/model/guild/integration.rs b/src/model/guild/integration.rs index 2c1c6e29540..0710a23c344 100644 --- a/src/model/guild/integration.rs +++ b/src/model/guild/integration.rs @@ -10,9 +10,9 @@ use crate::model::prelude::*; #[non_exhaustive] pub struct Integration { pub id: IntegrationId, - pub name: String, + pub name: FixedString, #[serde(rename = "type")] - pub kind: String, + pub kind: FixedString, pub enabled: bool, pub syncing: Option, pub role_id: Option, @@ -60,8 +60,8 @@ impl From for IntegrationId { #[derive(Clone, Debug, Deserialize, Serialize)] #[non_exhaustive] pub struct IntegrationAccount { - pub id: String, - pub name: String, + pub id: FixedString, + pub name: FixedString, } /// Integration application object. @@ -72,8 +72,8 @@ pub struct IntegrationAccount { #[non_exhaustive] pub struct IntegrationApplication { pub id: ApplicationId, - pub name: String, + pub name: FixedString, pub icon: Option, - pub description: String, + pub description: FixedString, pub bot: Option, } diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs index 10f734ea495..71144624136 100644 --- a/src/model/guild/member.rs +++ b/src/model/guild/member.rs @@ -8,7 +8,6 @@ use crate::builder::EditMember; use crate::cache::Cache; #[cfg(feature = "model")] use crate::http::{CacheHttp, Http}; -#[cfg(all(feature = "cache", feature = "model"))] use crate::internal::prelude::*; use crate::model::prelude::*; #[cfg(feature = "model")] @@ -27,11 +26,11 @@ pub struct Member { /// The member's nickname, if present. /// /// Can't be longer than 32 characters. - pub nick: Option, + pub nick: Option>, /// The guild avatar hash pub avatar: Option, /// Vector of Ids of [`Role`]s given to the member. - pub roles: Vec, + pub roles: FixedArray, /// Timestamp representing the date when the member joined. pub joined_at: Option, /// Timestamp representing the date since the member is boosting the guild. @@ -575,9 +574,9 @@ pub struct PartialMember { /// The member's nickname, if present. /// /// Can't be longer than 32 characters. - pub nick: Option, + pub nick: Option>, /// Vector of Ids of [`Role`]s given to the member. - pub roles: Vec, + pub roles: FixedArray, /// Indicator that the member hasn't accepted the rules of the guild yet. #[serde(default)] pub pending: bool, diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs index bed3160b846..d75c9b8ce4e 100644 --- a/src/model/guild/mod.rs +++ b/src/model/guild/mod.rs @@ -58,6 +58,7 @@ use crate::constants::LARGE_THRESHOLD; use crate::gateway::ShardMessenger; #[cfg(feature = "model")] use crate::http::{CacheHttp, Http, UserPagination}; +use crate::internal::prelude::*; #[cfg(feature = "model")] use crate::json::json; use crate::model::prelude::*; @@ -70,7 +71,7 @@ use crate::model::utils::*; #[non_exhaustive] pub struct Ban { /// The reason given for this ban. - pub reason: Option, + pub reason: Option, /// The user that was banned. pub user: User, } @@ -98,7 +99,7 @@ pub struct Guild { /// This is equivalent to the Id of the default role (`@everyone`). pub id: GuildId, /// The name of the guild. - pub name: String, + pub name: FixedString, /// The hash of the icon used by the guild. /// /// In the client, this appears on the guild list on the left-hand side. @@ -170,7 +171,7 @@ pub struct Guild { /// /// /// [`discord documentation`]: https://discord.com/developers/docs/resources/guild#guild-object-guild-features - pub features: Vec, + pub features: FixedArray, /// Indicator of whether the guild requires multi-factor authentication for [`Role`]s or /// [`User`]s with moderation permissions. pub mfa_level: MfaLevel, @@ -191,18 +192,18 @@ pub struct Guild { /// The maximum number of members for the guild. pub max_members: Option, /// The vanity url code for the guild, if it has one. - pub vanity_url_code: Option, + pub vanity_url_code: Option, /// The server's description, if it has one. - pub description: Option, + pub description: Option, /// The guild's banner, if it has one. - pub banner: Option, + pub banner: Option, /// The server's premium boosting level. pub premium_tier: PremiumTier, /// The total number of users currently boosting this server. pub premium_subscription_count: Option, /// The preferred locale of this guild only set if guild has the "DISCOVERABLE" feature, /// defaults to en-US. - pub preferred_locale: String, + pub preferred_locale: FixedString, /// The id of the channel where admins and moderators of Community guilds receive notices from /// Discord. /// @@ -260,17 +261,17 @@ pub struct Guild { #[serde(deserialize_with = "deserialize_guild_channels")] pub channels: HashMap, /// All active threads in this guild that current user has permission to view. - pub threads: Vec, + pub threads: FixedArray, /// A mapping of [`User`]s' Ids to their current presences. /// /// **Note**: This will be empty unless the "guild presences" privileged intent is enabled. #[serde(with = "presences")] pub presences: HashMap, /// The stage instances in this guild. - pub stage_instances: Vec, + pub stage_instances: FixedArray, /// The stage instances in this guild. #[serde(rename = "guild_scheduled_events")] - pub scheduled_events: Vec, + pub scheduled_events: FixedArray, } #[cfg(feature = "model")] @@ -436,7 +437,7 @@ impl Guild { let guild_channels = cache.as_ref().guild_channels(self.id)?; for (id, channel) in guild_channels.iter() { - if channel.name == name { + if &*channel.name == name { return Some(*id); } } @@ -1639,14 +1640,14 @@ impl Guild { }; for member in self.members.values() { - if member.user.name == username + if &*member.user.name == username && discrim.map_or(true, |d| member.user.discriminator == d) { return Some(member); } } - self.members.values().find(|member| member.nick.as_ref().is_some_and(|nick| nick == name)) + self.members.values().find(|member| member.nick.as_deref().is_some_and(|nick| nick == name)) } /// Retrieves all [`Member`] that start with a given [`String`]. @@ -1673,7 +1674,7 @@ impl Guild { prefix: &str, case_sensitive: bool, sorted: bool, - ) -> Vec<(&Member, String)> { + ) -> Vec<(&Member, &str)> { fn starts_with(name: &str, prefix: &str, case_sensitive: bool) -> bool { if case_sensitive { name.starts_with(prefix) @@ -1689,19 +1690,19 @@ impl Guild { let username = &member.user.name; if starts_with(username, prefix, case_sensitive) { - Some((member, username.clone())) + Some((member, username.as_str())) } else { match &member.nick { Some(nick) => starts_with(nick, prefix, case_sensitive) - .then(|| (member, nick.clone())), + .then(|| (member, nick.as_str())), None => None, } } }) - .collect::>(); + .collect::>(); if sorted { - members.sort_by(|a, b| closest_to_origin(prefix, &a.1[..], &b.1[..])); + members.sort_by(|a, b| closest_to_origin(prefix, a.1, b.1)); } members @@ -1750,11 +1751,11 @@ impl Guild { let username = &member.user.name; if contains(username, substring, case_sensitive) { - Some((member, username.clone())) + Some((member, username.clone().into())) } else { match &member.nick { Some(nick) => contains(nick, substring, case_sensitive) - .then(|| (member, nick.clone())), + .then(|| (member, nick.clone().into())), None => None, } } @@ -1804,7 +1805,7 @@ impl Guild { .values() .filter_map(|member| { let name = &member.user.name; - contains(name, substring, case_sensitive).then(|| (member, name.clone())) + contains(name, substring, case_sensitive).then(|| (member, name.clone().into())) }) .collect::>(); @@ -1853,7 +1854,7 @@ impl Guild { .values() .filter_map(|member| { let nick = member.nick.as_ref().unwrap_or(&member.user.name); - contains(nick, substring, case_sensitive).then(|| (member, nick.clone())) + contains(nick, substring, case_sensitive).then(|| (member, nick.clone().into())) }) .collect::>(); @@ -2314,7 +2315,7 @@ impl Guild { /// ``` #[must_use] pub fn role_by_name(&self, role_name: &str) -> Option<&Role> { - self.roles.values().find(|role| role_name == role.name) + self.roles.values().find(|role| role_name == &*role.name) } /// Returns a builder which can be awaited to obtain a message or stream of messages in this @@ -2508,7 +2509,7 @@ pub struct GuildInfo { /// Can be used to calculate creation date. pub id: GuildId, /// The name of the guild. - pub name: String, + pub name: FixedString, /// The hash of the icon of the guild. /// /// This can be used to generate a URL to the guild's icon image. @@ -2518,7 +2519,7 @@ pub struct GuildInfo { /// The permissions that the current user has. pub permissions: Permissions, /// See [`Guild::features`]. - pub features: Vec, + pub features: FixedArray, } #[cfg(feature = "model")] @@ -2687,9 +2688,9 @@ mod test { fn gen_member() -> Member { Member { - nick: Some("aaaa".to_string()), + nick: Some("aaaa".to_string().into()), user: User { - name: "test".into(), + name: "test".to_string().into(), discriminator: NonZeroU16::new(1432), ..User::default() }, diff --git a/src/model/guild/partial_guild.rs b/src/model/guild/partial_guild.rs index baf3b6aee14..d4089c3d25c 100644 --- a/src/model/guild/partial_guild.rs +++ b/src/model/guild/partial_guild.rs @@ -22,6 +22,7 @@ use crate::collector::{MessageCollector, ReactionCollector}; use crate::gateway::ShardMessenger; #[cfg(feature = "model")] use crate::http::{CacheHttp, Http, UserPagination}; +use crate::internal::prelude::*; use crate::model::prelude::*; #[cfg(feature = "model")] use crate::model::utils::icon_url; @@ -43,7 +44,7 @@ pub struct PartialGuild { /// This is equivalent to the Id of the default role (`@everyone`). pub id: GuildId, /// The name of the guild. - pub name: String, + pub name: FixedString, /// The hash of the icon used by the guild. /// /// In the client, this appears on the guild list on the left-hand side. @@ -115,7 +116,7 @@ pub struct PartialGuild { /// /// /// [`discord documentation`]: https://discord.com/developers/docs/resources/guild#guild-object-guild-features - pub features: Vec, + pub features: FixedArray, /// Indicator of whether the guild requires multi-factor authentication for [`Role`]s or /// [`User`]s with moderation permissions. pub mfa_level: MfaLevel, @@ -136,18 +137,18 @@ pub struct PartialGuild { /// The maximum number of members for the guild. pub max_members: Option, /// The vanity url code for the guild, if it has one. - pub vanity_url_code: Option, + pub vanity_url_code: Option, /// The server's description, if it has one. - pub description: Option, + pub description: Option, /// The guild's banner, if it has one. - pub banner: Option, + pub banner: Option, /// The server's premium boosting level. pub premium_tier: PremiumTier, /// The total number of users currently boosting this server. pub premium_subscription_count: Option, /// The preferred locale of this guild only set if guild has the "DISCOVERABLE" feature, /// defaults to en-US. - pub preferred_locale: String, + pub preferred_locale: FixedString, /// The id of the channel where admins and moderators of Community guilds receive notices from /// Discord. /// @@ -386,7 +387,7 @@ impl PartialGuild { let guild_channels = cache.as_ref().guild_channels(self.id)?; for (id, channel) in guild_channels.iter() { - if channel.name == name { + if &*channel.name == name { return Some(*id); } } @@ -1513,7 +1514,7 @@ impl PartialGuild { #[inline] #[must_use] pub fn role_by_name(&self, role_name: &str) -> Option<&Role> { - self.roles.values().find(|role| role_name == role.name) + self.roles.values().find(|role| role_name == &*role.name) } /// Returns a builder which can be awaited to obtain a message or stream of messages in this diff --git a/src/model/guild/role.rs b/src/model/guild/role.rs index 9203a0d0bdc..1d18991a7a5 100644 --- a/src/model/guild/role.rs +++ b/src/model/guild/role.rs @@ -5,7 +5,6 @@ use std::fmt; use crate::builder::EditRole; #[cfg(feature = "model")] use crate::http::Http; -#[cfg(all(feature = "cache", feature = "model"))] use crate::internal::prelude::*; use crate::model::prelude::*; use crate::model::utils::is_false; @@ -43,7 +42,7 @@ pub struct Role { #[serde(default)] pub mentionable: bool, /// The name of the role. - pub name: String, + pub name: FixedString, /// A set of permissions that the role has been assigned. /// /// See the [`permissions`] module for more information. @@ -65,7 +64,7 @@ pub struct Role { /// Role icon image hash. pub icon: Option, /// Role unicoded image. - pub unicode_emoji: Option, + pub unicode_emoji: Option, } #[cfg(feature = "model")] diff --git a/src/model/guild/scheduled_event.rs b/src/model/guild/scheduled_event.rs index 19a5499c4f2..ac5994ac20e 100644 --- a/src/model/guild/scheduled_event.rs +++ b/src/model/guild/scheduled_event.rs @@ -1,3 +1,4 @@ +use crate::internal::prelude::*; use crate::model::prelude::*; /// Information about a guild scheduled event. @@ -18,9 +19,9 @@ pub struct ScheduledEvent { /// Only `None` for events created before October 25th, 2021. pub creator_id: Option, /// The name of the scheduled event. - pub name: String, + pub name: FixedString, /// The description of the scheduled event, if any. - pub description: Option, + pub description: Option, /// The event's starting time. #[serde(rename = "scheduled_start_time")] pub start_time: Timestamp, @@ -88,7 +89,7 @@ enum_number! { #[non_exhaustive] pub struct ScheduledEventMetadata { #[serde(default)] - pub location: Option, + pub location: Option, } /// [Discord docs](https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-user-object). diff --git a/src/model/guild/welcome_screen.rs b/src/model/guild/welcome_screen.rs index f809065d2a0..29d98ffd286 100644 --- a/src/model/guild/welcome_screen.rs +++ b/src/model/guild/welcome_screen.rs @@ -1,5 +1,6 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use crate::internal::prelude::*; use crate::model::id::{ChannelId, EmojiId}; /// Information relating to a guild's welcome screen. @@ -10,11 +11,11 @@ use crate::model::id::{ChannelId, EmojiId}; #[non_exhaustive] pub struct GuildWelcomeScreen { /// The server description shown in the welcome screen. - pub description: Option, + pub description: Option, /// The channels shown in the welcome screen. /// /// **Note**: There can only be only up to 5 channels. - pub welcome_channels: Vec, + pub welcome_channels: FixedArray, } /// A channel shown in the [`GuildWelcomeScreen`]. @@ -27,7 +28,7 @@ pub struct GuildWelcomeChannel { /// The channel Id. pub channel_id: ChannelId, /// The description shown for the channel. - pub description: String, + pub description: FixedString, /// The emoji shown, if there is one. pub emoji: Option, } @@ -38,9 +39,9 @@ impl<'de> Deserialize<'de> for GuildWelcomeChannel { #[derive(Deserialize)] struct Helper { channel_id: ChannelId, - description: String, + description: FixedString, emoji_id: Option, - emoji_name: Option, + emoji_name: Option, } let Helper { channel_id, @@ -95,7 +96,7 @@ impl Serialize for GuildWelcomeChannel { #[non_exhaustive] pub enum GuildWelcomeChannelEmoji { /// A custom emoji. - Custom { id: EmojiId, name: String }, + Custom { id: EmojiId, name: FixedString }, /// A unicode emoji. - Unicode(String), + Unicode(FixedString), } diff --git a/src/model/invite.rs b/src/model/invite.rs index ab2b09bf3d0..22b851c3e88 100644 --- a/src/model/invite.rs +++ b/src/model/invite.rs @@ -7,7 +7,6 @@ use crate::builder::CreateInvite; use crate::cache::Cache; #[cfg(feature = "model")] use crate::http::{CacheHttp, Http}; -#[cfg(feature = "model")] use crate::internal::prelude::*; /// Information about an invite code. @@ -26,7 +25,7 @@ pub struct Invite { /// These include [invisible][`OnlineStatus::Invisible`] members. pub approximate_presence_count: Option, /// The unique code for the invite. - pub code: String, + pub code: FixedString, /// A representation of the minimal amount of information needed about the [`GuildChannel`] /// being invited to. pub channel: InviteChannel, @@ -199,7 +198,7 @@ impl Invite { #[derive(Clone, Debug, Deserialize, Serialize)] pub struct InviteChannel { pub id: ChannelId, - pub name: String, + pub name: FixedString, #[serde(rename = "type")] pub kind: ChannelType, } @@ -211,14 +210,14 @@ pub struct InviteChannel { #[non_exhaustive] pub struct InviteGuild { pub id: GuildId, - pub name: String, + pub name: FixedString, pub splash: Option, pub banner: Option, - pub description: Option, + pub description: Option, pub icon: Option, - pub features: Vec, + pub features: FixedArray, pub verification_level: VerificationLevel, - pub vanity_url_code: Option, + pub vanity_url_code: Option, pub nsfw_level: NsfwLevel, pub premium_subscription_count: Option, } @@ -280,7 +279,7 @@ pub struct RichInvite { /// invited to. pub channel: InviteChannel, /// The unique code for the invite. - pub code: String, + pub code: FixedString, /// When the invite was created. pub created_at: Timestamp, /// A representation of the minimal amount of information needed about the [`Guild`] being @@ -392,13 +391,13 @@ impl RichInvite { #[non_exhaustive] pub struct InviteStageInstance { /// The members speaking in the Stage - pub members: Vec, + pub members: FixedArray, /// The number of users in the Stage pub participant_count: u64, /// The number of users speaking in the Stage pub speaker_count: u64, /// The topic of the Stage instance (1-120 characters) - pub topic: String, + pub topic: FixedString, } enum_number! { diff --git a/src/model/misc.rs b/src/model/misc.rs index e5d6d8c2a78..3b0214551be 100644 --- a/src/model/misc.rs +++ b/src/model/misc.rs @@ -11,6 +11,7 @@ use std::str::FromStr; use arrayvec::ArrayString; use super::prelude::*; +use crate::internal::prelude::*; #[cfg(all(feature = "model", any(feature = "cache", feature = "utils")))] use crate::utils; @@ -170,7 +171,7 @@ pub struct EmojiIdentifier { pub id: EmojiId, /// The name of the emoji. It must be at least 2 characters long and can only contain /// alphanumeric characters and underscores. - pub name: String, + pub name: FixedString, } #[cfg(all(feature = "model", feature = "utils"))] @@ -204,7 +205,7 @@ impl fmt::Display for EmojiIdentifier { #[derive(Debug)] #[cfg(all(feature = "model", feature = "utils"))] pub struct EmojiIdentifierParseError { - parsed_string: String, + parsed_string: FixedString, } #[cfg(all(feature = "model", feature = "utils"))] @@ -223,7 +224,7 @@ impl FromStr for EmojiIdentifier { fn from_str(s: &str) -> StdResult { utils::parse_emoji(s).ok_or_else(|| EmojiIdentifierParseError { - parsed_string: s.to_owned(), + parsed_string: s.to_owned().into(), }) } } @@ -236,17 +237,17 @@ impl FromStr for EmojiIdentifier { #[derive(Clone, Debug, Deserialize, Serialize)] #[non_exhaustive] pub struct Incident { - pub created_at: String, - pub id: String, - pub impact: String, - pub incident_updates: Vec, - pub monitoring_at: Option, - pub name: String, - pub page_id: String, - pub resolved_at: Option, - pub shortlink: String, - pub status: String, - pub updated_at: String, + pub created_at: FixedString, + pub id: FixedString, + pub impact: FixedString, + pub incident_updates: FixedArray, + pub monitoring_at: Option, + pub name: FixedString, + pub page_id: FixedString, + pub resolved_at: Option, + pub shortlink: FixedString, + pub status: FixedString, + pub updated_at: FixedString, } /// An update to an incident from the Discord status page. @@ -257,13 +258,13 @@ pub struct Incident { #[derive(Clone, Debug, Deserialize, Serialize)] #[non_exhaustive] pub struct IncidentUpdate { - pub body: String, - pub created_at: String, - pub display_at: String, - pub id: String, - pub incident_id: String, - pub status: String, - pub updated_at: String, + pub body: FixedString, + pub created_at: FixedString, + pub display_at: FixedString, + pub id: FixedString, + pub incident_id: FixedString, + pub status: FixedString, + pub updated_at: FixedString, } /// A Discord status maintenance message. This can be either for active maintenances or for @@ -273,19 +274,19 @@ pub struct IncidentUpdate { #[derive(Clone, Debug, Deserialize, Serialize)] #[non_exhaustive] pub struct Maintenance { - pub created_at: String, - pub id: String, - pub impact: String, - pub incident_updates: Vec, - pub monitoring_at: Option, - pub name: String, - pub page_id: String, - pub resolved_at: Option, - pub scheduled_for: String, - pub scheduled_until: String, - pub shortlink: String, - pub status: String, - pub updated_at: String, + pub created_at: FixedString, + pub id: FixedString, + pub impact: FixedString, + pub incident_updates: FixedArray, + pub monitoring_at: Option, + pub name: FixedString, + pub page_id: FixedString, + pub resolved_at: Option, + pub scheduled_for: FixedString, + pub scheduled_until: FixedString, + pub shortlink: FixedString, + pub status: FixedString, + pub updated_at: FixedString, } #[cfg(test)] diff --git a/src/model/sticker.rs b/src/model/sticker.rs index bac5045cf79..8696c3fcf39 100644 --- a/src/model/sticker.rs +++ b/src/model/sticker.rs @@ -2,7 +2,6 @@ use crate::builder::EditSticker; #[cfg(feature = "model")] use crate::http::{CacheHttp, Http}; -#[cfg(feature = "model")] use crate::internal::prelude::*; use crate::model::prelude::*; use crate::model::utils::comma_separated_string; @@ -30,7 +29,7 @@ pub struct StickerItem { /// The unique ID given to this sticker. pub id: StickerId, /// The name of the sticker. - pub name: String, + pub name: FixedString, /// The type of sticker format. pub format_type: StickerFormatType, } @@ -69,15 +68,15 @@ pub struct StickerPack { /// The unique ID given to this sticker sticker pack. pub id: StickerPackId, /// The stickers in the pack - pub stickers: Vec, + pub stickers: FixedArray, /// The name of the sticker pack - pub name: String, + pub name: FixedString, /// The unique ID given to the pack's SKU. pub sku_id: SkuId, /// ID of a sticker in the pack which is shown as the pack's icon. pub cover_sticker_id: Option, /// Description of the sticker pack. - pub description: String, + pub description: FixedString, /// The unique ID given to the sticker pack's banner image. pub banner_asset_id: StickerPackBannerId, } @@ -113,13 +112,13 @@ pub struct Sticker { /// The unique ID of the pack the sticker is from. pub pack_id: Option, /// The name of the sticker. - pub name: String, + pub name: FixedString, /// Description of the sticker - pub description: Option, + pub description: Option, /// For guild stickers, the Discord name of a unicode emoji representing the sticker's /// expression. For standard stickers, a list of related expressions. #[serde(with = "comma_separated_string")] - pub tags: Vec, + pub tags: FixedArray, /// The type of sticker. #[serde(rename = "type")] pub kind: StickerType, diff --git a/src/model/user.rs b/src/model/user.rs index 4fcb4a608fe..8c1ec5afd4b 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -19,7 +19,6 @@ use crate::collector::{MessageCollector, ReactionCollector}; use crate::gateway::ShardMessenger; #[cfg(feature = "model")] use crate::http::CacheHttp; -#[cfg(feature = "model")] use crate::internal::prelude::*; #[cfg(feature = "model")] use crate::json::json; @@ -234,7 +233,7 @@ pub struct User { /// change if the username+discriminator pair becomes non-unique. Unless the account has /// migrated to a next generation username, which does not have a discriminant. #[serde(rename = "username")] - pub name: String, + pub name: FixedString, /// The account's discriminator to differentiate the user from others with /// the same [`Self::name`]. The name+discriminator pair is always unique. /// If the discriminator is not present, then this is a next generation username @@ -243,7 +242,7 @@ pub struct User { pub discriminator: Option, /// The account's display name, if it is set. /// For bots this is the application name. - pub global_name: Option, + pub global_name: Option>, /// Optional avatar hash. pub avatar: Option, /// Indicator of whether the user is a bot. @@ -267,7 +266,7 @@ pub struct User { #[serde(rename = "accent_color")] pub accent_colour: Option, /// The user's chosen language option - pub locale: Option, + pub locale: Option, /// Whether the email on this account has been verified /// /// Requires [`Scope::Email`] @@ -275,7 +274,7 @@ pub struct User { /// The user's email /// /// Requires [`Scope::Email`] - pub email: Option, + pub email: Option, /// The flags on a user's account #[serde(default)] pub flags: UserPublicFlags, @@ -598,14 +597,19 @@ impl User { if let Some(cache) = cache_http.cache() { if let Some(guild) = guild_id.to_guild_cached(cache) { if let Some(member) = guild.members.get(&self.id) { - return member.nick.clone(); + return member.nick.clone().map(Into::into); } } } } // At this point we're guaranteed to do an API call. - guild_id.member(cache_http, &self.id).await.ok().and_then(|member| member.nick) + guild_id + .member(cache_http, &self.id) + .await + .ok() + .and_then(|member| member.nick) + .map(Into::into) } /// Returns a builder which can be awaited to obtain a message or stream of messages sent by @@ -825,7 +829,7 @@ mod test { id: UserId::new(210), avatar: Some(ImageHash::from_str("fb211703bcc04ee612c88d494df0272f").unwrap()), discriminator: NonZeroU16::new(1432), - name: "test".to_string(), + name: "test".to_string().into(), ..Default::default() }; diff --git a/src/model/utils.rs b/src/model/utils.rs index cc075a3ea77..ea08a9ecc19 100644 --- a/src/model/utils.rs +++ b/src/model/utils.rs @@ -4,9 +4,11 @@ use std::hash::Hash; use std::marker::PhantomData; use std::num::NonZeroU64; +use arrayvec::ArrayVec; use serde::ser::{Serialize, SerializeSeq, Serializer}; use super::prelude::*; +use crate::internal::prelude::*; pub fn default_true() -> bool { true @@ -267,13 +269,13 @@ pub mod presences { pub fn deserialize_buttons<'de, D: Deserializer<'de>>( deserializer: D, -) -> StdResult, D::Error> { - Vec::deserialize(deserializer).map(|labels| { +) -> StdResult, D::Error> { + ArrayVec::<_, 2>::deserialize(deserializer).map(|labels| { labels .into_iter() .map(|l| ActivityButton { label: l, - url: String::new(), + url: FixedString::default(), }) .collect() }) @@ -321,19 +323,23 @@ pub mod stickers { pub mod comma_separated_string { use serde::{Deserialize, Deserializer, Serializer}; - use super::CowStr; + use crate::internal::prelude::*; pub fn deserialize<'de, D: Deserializer<'de>>( deserializer: D, - ) -> Result, D::Error> { + ) -> Result, D::Error> { let str_sequence = CowStr::deserialize(deserializer)?.0; - let vec = str_sequence.split(", ").map(str::to_owned).collect(); + let vec = str_sequence.split(", ").map(str::to_owned).map(FixedString::from).collect(); Ok(vec) } #[allow(clippy::ptr_arg)] - pub fn serialize(vec: &Vec, serializer: S) -> Result { + pub fn serialize( + vec: &FixedArray, + serializer: S, + ) -> Result { + let vec: Vec = vec.iter().map(FixedString::clone).map(String::from).collect(); serializer.serialize_str(&vec.join(", ")) } } diff --git a/src/model/voice.rs b/src/model/voice.rs index 9912c945f17..a219702ade3 100644 --- a/src/model/voice.rs +++ b/src/model/voice.rs @@ -3,6 +3,7 @@ use serde::de::{Deserialize, Deserializer}; use serde::Serialize; +use crate::internal::prelude::*; use crate::model::guild::Member; use crate::model::id::{ChannelId, GuildId, UserId}; use crate::model::Timestamp; @@ -18,9 +19,9 @@ pub struct VoiceRegion { /// Whether it is a deprecated voice region, which you should avoid using. pub deprecated: bool, /// The internal Id of the voice region. - pub id: String, + pub id: FixedString, /// A recognizable name of the location of the voice region. - pub name: String, + pub name: FixedString, /// Whether the voice region is optimal for use by the current user. pub optimal: bool, } @@ -42,7 +43,7 @@ pub struct VoiceState { pub self_mute: bool, pub self_stream: Option, pub self_video: bool, - pub session_id: String, + pub session_id: FixedString, pub suppress: bool, pub user_id: UserId, /// When unsuppressed, non-bot users will have this set to the current time. Bot users will be diff --git a/src/model/webhook.rs b/src/model/webhook.rs index 27cbff90cac..3a8ca255a9a 100644 --- a/src/model/webhook.rs +++ b/src/model/webhook.rs @@ -11,7 +11,6 @@ use crate::builder::{Builder, EditWebhook, EditWebhookMessage, ExecuteWebhook}; use crate::cache::{Cache, GuildChannelRef, GuildRef}; #[cfg(feature = "model")] use crate::http::{CacheHttp, Http}; -#[cfg(feature = "model")] use crate::internal::prelude::*; use crate::model::prelude::*; @@ -74,7 +73,7 @@ pub struct Webhook { /// The default name of the webhook. /// /// This can be temporarily overridden via [`ExecuteWebhook::username`]. - pub name: Option, + pub name: Option>, /// The default avatar. /// /// This can be temporarily overridden via [`ExecuteWebhook::avatar_url`]. @@ -103,7 +102,7 @@ pub struct WebhookGuild { /// The unique Id identifying the guild. pub id: GuildId, /// The name of the guild. - pub name: String, + pub name: FixedString, /// The hash of the icon used by the guild. /// /// In the client, this appears on the guild list on the left-hand side. @@ -165,7 +164,7 @@ pub struct WebhookChannel { /// The unique Id of the channel. pub id: ChannelId, /// The name of the channel. - pub name: String, + pub name: FixedString, } #[cfg(feature = "model")] diff --git a/src/utils/argument_convert/user.rs b/src/utils/argument_convert/user.rs index fb9a00073a6..24fb459fb86 100644 --- a/src/utils/argument_convert/user.rs +++ b/src/utils/argument_convert/user.rs @@ -43,7 +43,7 @@ fn lookup_by_global_cache(ctx: impl CacheHttp, s: &str) -> Option { let lookup_by_name = || { users.iter().find_map(|m| { let user = m.value(); - (user.name == s).then(|| user.clone()) + (&*user.name == s).then(|| user.clone()) }) }; diff --git a/src/utils/content_safe.rs b/src/utils/content_safe.rs index 22ac630feb7..3ed64a46523 100644 --- a/src/utils/content_safe.rs +++ b/src/utils/content_safe.rs @@ -280,13 +280,13 @@ mod tests { fn test_content_safe() { let user = User { id: UserId::new(100000000000000000), - name: "Crab".to_string(), + name: "Crab".to_string().into(), ..Default::default() }; let outside_cache_user = User { id: UserId::new(100000000000000001), - name: "Boat".to_string(), + name: "Boat".to_string().into(), ..Default::default() }; @@ -296,19 +296,19 @@ mod tests { }; let member = Member { - nick: Some("Ferris".to_string()), + nick: Some("Ferris".to_string().into()), ..Default::default() }; let role = Role { id: RoleId::new(333333333333333333), - name: "ferris-club-member".to_string(), + name: "ferris-club-member".to_string().into(), ..Default::default() }; let channel = GuildChannel { id: ChannelId::new(111880193700067777), - name: "general".to_string(), + name: "general".to_string().into(), ..Default::default() }; diff --git a/src/utils/custom_message.rs b/src/utils/custom_message.rs index 7250c789d43..0594ad7bf04 100644 --- a/src/utils/custom_message.rs +++ b/src/utils/custom_message.rs @@ -65,7 +65,7 @@ impl CustomMessage { /// If not used, the default value is an empty string (`String::default()`). #[inline] pub fn content(&mut self, s: impl Into) -> &mut Self { - self.msg.content = s.into(); + self.msg.content = s.into().into(); self } diff --git a/src/utils/message_builder.rs b/src/utils/message_builder.rs index 73ac20f8535..cc1f5984d57 100644 --- a/src/utils/message_builder.rs +++ b/src/utils/message_builder.rs @@ -1200,10 +1200,10 @@ mod test { animated: false, available: true, id: EmojiId::new(32), - name: "Rohrkatze".to_string(), + name: "Rohrkatze".to_string().into(), managed: false, require_colons: true, - roles: vec![], + roles: vec![].into(), user: None, }) .build(); diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 3950f6fe270..e681ad0f3d7 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -246,7 +246,7 @@ pub fn parse_channel_mention(mention: &str) -> Option { /// let emoji = parse_emoji("<:smugAnimeFace:302516740095606785>").unwrap(); /// assert_eq!(emoji.animated, false); /// assert_eq!(emoji.id, EmojiId::new(302516740095606785)); -/// assert_eq!(emoji.name, "smugAnimeFace".to_string()); +/// assert_eq!(&*emoji.name, "smugAnimeFace"); /// ``` /// /// Asserting that an invalid emoji usage returns [`None`]: @@ -291,9 +291,9 @@ pub fn parse_emoji(mention: impl AsRef) -> Option { } id.parse().ok().map(|id| EmojiIdentifier { + name: name.into(), animated, id, - name, }) } else { None @@ -532,7 +532,7 @@ mod test { #[test] fn test_emoji_parser() { let emoji = parse_emoji("<:name:12345>").unwrap(); - assert_eq!(emoji.name, "name"); + assert_eq!(&*emoji.name, "name"); assert_eq!(emoji.id, 12_345); } diff --git a/src/utils/quick_modal.rs b/src/utils/quick_modal.rs index 1aa2befd4bd..0dd7f93fb6f 100644 --- a/src/utils/quick_modal.rs +++ b/src/utils/quick_modal.rs @@ -7,12 +7,13 @@ use crate::builder::{ }; use crate::client::Context; use crate::collector::ModalInteractionCollector; +use crate::internal::prelude::*; use crate::model::prelude::*; #[cfg(feature = "collector")] pub struct QuickModalResponse { pub interaction: ModalInteraction, - pub inputs: Vec, + pub inputs: FixedArray>, } /// Convenience builder to create a modal, wait for the user to submit and parse the response. @@ -27,7 +28,7 @@ pub struct QuickModalResponse { /// .paragraph_field("Hobbies and interests"); /// let response = interaction.quick_modal(ctx, modal).await?; /// let inputs = response.unwrap().inputs; -/// let (first_name, last_name, hobbies) = (&inputs[0], &inputs[1], &inputs[2]); +/// let (first_name, last_name, hobbies) = (&inputs[0_usize], &inputs[1_usize], &inputs[2_usize]); /// # Ok(()) /// # } /// ``` @@ -105,7 +106,7 @@ impl CreateQuickModal { builder.execute(ctx, (interaction_id, token)).await?; let collector = - ModalInteractionCollector::new(&ctx.shard).custom_ids(vec![modal_custom_id]); + ModalInteractionCollector::new(&ctx.shard).custom_ids(vec![modal_custom_id.into()]); let collector = match self.timeout { Some(timeout) => collector.timeout(timeout), diff --git a/tests/test_reaction.rs b/tests/test_reaction.rs index 135deb172f6..cafd1e2c01b 100644 --- a/tests/test_reaction.rs +++ b/tests/test_reaction.rs @@ -10,7 +10,7 @@ fn str_to_reaction_type() { let reaction2 = ReactionType::Custom { animated: false, id: EmojiId::new(600404340292059257), - name: Some("customemoji".to_string()), + name: Some("customemoji".to_string().into()), }; assert_eq!(reaction, reaction2); } @@ -22,7 +22,7 @@ fn str_to_reaction_type_animated() { let reaction2 = ReactionType::Custom { animated: true, id: EmojiId::new(600409340292059257), - name: Some("customemoji2".to_string()), + name: Some("customemoji2".to_string().into()), }; assert_eq!(reaction, reaction2); } @@ -34,7 +34,7 @@ fn string_to_reaction_type() { let reaction2 = ReactionType::Custom { animated: false, id: EmojiId::new(600404340292059257), - name: Some("customemoji".to_string()), + name: Some("customemoji".to_string().into()), }; assert_eq!(reaction, reaction2); } @@ -105,7 +105,7 @@ fn json_to_reaction_type() { let value = serde_json::from_str(s).unwrap(); assert!(matches!(value, ReactionType::Unicode(_))); if let ReactionType::Unicode(value) = value { - assert_eq!(value, "foo"); + assert_eq!(&*value, "foo"); } let s = r#"{"name": null}"#;