diff --git a/Cargo.lock b/Cargo.lock index 456a4f6e3ddf..1a0998cd2bc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,7 +58,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.46", + "syn 2.0.48", ] [[package]] @@ -112,12 +112,13 @@ dependencies = [ [[package]] name = "bool_to_bitflags" version = "0.1.0" -source = "git+https://github.com/GnomedDev/bool-to-bitflags#3cdceebeb5441366c30b7588f4f136ac022ed21f" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b88d7c0d95451949312298449b27e4a0c8af520bc880685625ea2a2a4d30a84" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.46", + "syn 2.0.48", ] [[package]] @@ -221,9 +222,9 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -287,7 +288,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.46", + "syn 2.0.48", ] [[package]] @@ -298,7 +299,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.46", + "syn 2.0.48", ] [[package]] @@ -360,7 +361,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.46", + "syn 2.0.48", ] [[package]] @@ -529,7 +530,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.46", + "syn 2.0.48", ] [[package]] @@ -1010,7 +1011,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.46", + "syn 2.0.48", ] [[package]] @@ -1027,9 +1028,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.74" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db" +checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708" dependencies = [ "unicode-ident", ] @@ -1317,14 +1318,14 @@ checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.46", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.110" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fbd975230bada99c8bb618e0c365c2eefa219158d5c6c29610fd09ff1833257" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", @@ -1346,7 +1347,7 @@ dependencies = [ [[package]] name = "serenity" version = "0.12.0" -source = "git+https://github.com/serenity-rs/serenity?branch=next#10f0d4b11615a37c6f70a90c6a8355d0573c215d" +source = "git+https://github.com/serenity-rs/serenity?branch=next#590cc89e9ed5fde7e8992efc47f6f342dfdcba1a" dependencies = [ "arrayvec", "async-trait", @@ -1414,8 +1415,9 @@ dependencies = [ [[package]] name = "small-fixed-array" -version = "0.1.0" -source = "git+https://github.com/GnomedDev/small-fixed-array#af8c9c76503b98c11fcb62a354b7d6fe6653d69e" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06d9ffc21173849a13fec2307fbd84d529ebf0b3952dcc76f5c81cfa549d22c1" dependencies = [ "serde", "tracing", @@ -1462,9 +1464,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.46" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89456b690ff72fddcecf231caedbe615c59480c93358a93dfae7fc29e3ebbf0e" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -1537,7 +1539,7 @@ checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.46", + "syn 2.0.48", ] [[package]] @@ -1618,7 +1620,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.46", + "syn 2.0.48", ] [[package]] @@ -1686,7 +1688,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.46", + "syn 2.0.48", ] [[package]] @@ -1778,7 +1780,7 @@ checksum = "0b122284365ba8497be951b9a21491f70c9688eb6fddc582931a0703f6a00ece" dependencies = [ "proc-macro2", "quote", - "syn 2.0.46", + "syn 2.0.48", ] [[package]] @@ -1905,7 +1907,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.46", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -1939,7 +1941,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.46", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/examples/feature_showcase/autocomplete.rs b/examples/feature_showcase/autocomplete.rs index 1997686a01b0..f52c1f053f94 100644 --- a/examples/feature_showcase/autocomplete.rs +++ b/examples/feature_showcase/autocomplete.rs @@ -37,7 +37,7 @@ async fn autocomplete_name<'a>( async fn autocomplete_number( _ctx: Context<'_>, _partial: &str, -) -> impl Iterator { +) -> impl Iterator> { // Dummy choices [1_u32, 2, 3, 4, 5].iter().map(|&n| { serenity::AutocompleteChoice::new( diff --git a/examples/fluent_localization/translation.rs b/examples/fluent_localization/translation.rs index 250c20e40650..d2f9a397b74f 100644 --- a/examples/fluent_localization/translation.rs +++ b/examples/fluent_localization/translation.rs @@ -1,5 +1,7 @@ //! Wraps the fluent API and provides easy to use functions and macros for translation +use std::borrow::Cow; + use crate::{Context, Data, Error}; type FluentBundle = fluent::bundle::FluentBundle< @@ -136,8 +138,8 @@ pub fn apply_translations( // If this is a choice parameter, insert its localized variants for choice in &mut parameter.choices { choice.localizations.insert( - locale.clone(), - format(bundle, &choice.name, None, None).unwrap(), + Cow::Owned(locale.clone()), + Cow::Owned(format(bundle, &choice.name, None, None).unwrap()), ); } } @@ -171,7 +173,7 @@ pub fn apply_translations( // If this is a choice parameter, set the choice names to en-US for choice in &mut parameter.choices { - choice.name = format(bundle, &choice.name, None, None).unwrap(); + choice.name = Cow::Owned(format(bundle, &choice.name, None, None).unwrap()); } } } diff --git a/examples/invocation_data/main.rs b/examples/invocation_data/main.rs index 21c18e08600f..7257c2bda8fd 100644 --- a/examples/invocation_data/main.rs +++ b/examples/invocation_data/main.rs @@ -60,7 +60,7 @@ async fn main() { poise::builtins::create_application_commands(&framework.options().commands); serenity::GuildId::new(703332075914264606) - .set_commands(ctx, commands) + .set_commands(ctx, &commands) .await .unwrap(); Ok(()) diff --git a/macros/src/choice_parameter.rs b/macros/src/choice_parameter.rs index e84005371af1..3ae8091fcabb 100644 --- a/macros/src/choice_parameter.rs +++ b/macros/src/choice_parameter.rs @@ -70,9 +70,9 @@ pub fn choice_parameter(input: syn::DeriveInput) -> Result Vec { vec![ #( poise::CommandParameterChoice { __non_exhaustive: (), - name: #names.to_string(), + name: #names.into(), localizations: std::collections::HashMap::from([ - #( (#locales.to_string(), #localized_names.to_string()) ),* + #( (#locales.into(), #localized_names.into()) ),* ]), }, )* ] } diff --git a/macros/src/command/slash.rs b/macros/src/command/slash.rs index d7a36d2dac4a..9bc02e2875b4 100644 --- a/macros/src/command/slash.rs +++ b/macros/src/command/slash.rs @@ -42,7 +42,7 @@ pub fn generate_parameters(inv: &Invocation) -> Result = choices_stream .take(25) // T or AutocompleteChoice -> AutocompleteChoice .map(poise::serenity_prelude::AutocompleteChoice::from) diff --git a/macros/src/modal.rs b/macros/src/modal.rs index 597e4d402d61..a04a6f43edbf 100644 --- a/macros/src/modal.rs +++ b/macros/src/modal.rs @@ -101,7 +101,7 @@ pub fn modal(input: syn::DeriveInput) -> Result { Ok(quote::quote! { const _: () = { use poise::serenity_prelude as serenity; impl #impl_generics poise::Modal for #struct_ident #ty_generics #where_clause { - fn create(mut defaults: Option, custom_id: String) -> serenity::CreateInteractionResponse { + fn create(mut defaults: Option, custom_id: String) -> serenity::CreateInteractionResponse<'static> { serenity::CreateInteractionResponse::Modal( serenity::CreateModal::new(custom_id, #modal_title).components(vec!{#( #builders )*}) ) diff --git a/src/builtins/register.rs b/src/builtins/register.rs index 8caa9a2f2b1b..6de8ab3c227e 100644 --- a/src/builtins/register.rs +++ b/src/builtins/register.rs @@ -13,18 +13,18 @@ use crate::serenity_prelude as serenity; /// let commands = &ctx.framework().options().commands; /// let create_commands = poise::builtins::create_application_commands(commands); /// -/// serenity::Command::set_global_commands(ctx, create_commands).await?; +/// serenity::Command::set_global_commands(ctx, &create_commands).await?; /// # Ok(()) } /// ``` pub fn create_application_commands( commands: &[crate::Command], -) -> Vec { +) -> Vec> { /// We decided to extract context menu commands recursively, despite the subcommand hierarchy /// not being preserved. Because it's more confusing to just silently discard context menu /// commands if they're not top-level commands. /// https://discord.com/channels/381880193251409931/919310428344029265/947970605985189989 fn recursively_add_context_menu_commands( - builder: &mut Vec, + builder: &mut Vec>, command: &crate::Command, ) { if let Some(context_menu_command) = command.create_as_context_menu_command() { @@ -54,7 +54,7 @@ pub async fn register_globally( commands: &[crate::Command], ) -> Result<(), serenity::Error> { let builder = create_application_commands(commands); - serenity::Command::set_global_commands(http, builder).await?; + serenity::Command::set_global_commands(http, &builder).await?; Ok(()) } @@ -68,7 +68,7 @@ pub async fn register_in_guild( guild_id: serenity::GuildId, ) -> Result<(), serenity::Error> { let builder = create_application_commands(commands); - guild_id.set_commands(http, builder).await?; + guild_id.set_commands(http, &builder).await?; Ok(()) } @@ -101,7 +101,7 @@ pub async fn register_application_commands( if global { ctx.say(format!("Registering {num_commands} commands...",)) .await?; - serenity::Command::set_global_commands(ctx, commands_builder).await?; + serenity::Command::set_global_commands(ctx, &commands_builder).await?; } else { let guild_id = match ctx.guild_id() { Some(x) => x, @@ -113,7 +113,7 @@ pub async fn register_application_commands( ctx.say(format!("Registering {num_commands} commands...")) .await?; - guild_id.set_commands(ctx, commands_builder).await?; + guild_id.set_commands(ctx, &commands_builder).await?; } ctx.say("Done!").await?; @@ -228,10 +228,10 @@ pub async fn register_application_commands_buttons( ":gear: Registering {num_commands} global commands...", )) .await?; - serenity::Command::set_global_commands(ctx, create_commands).await?; + serenity::Command::set_global_commands(ctx, &create_commands).await?; } else { ctx.say(":gear: Unregistering global commands...").await?; - serenity::Command::set_global_commands(ctx, vec![]).await?; + serenity::Command::set_global_commands(ctx, &[]).await?; } } else { let guild_id = match ctx.guild_id() { @@ -246,10 +246,10 @@ pub async fn register_application_commands_buttons( ":gear: Registering {num_commands} guild commands...", )) .await?; - guild_id.set_commands(ctx, create_commands).await?; + guild_id.set_commands(ctx, &create_commands).await?; } else { ctx.say(":gear: Unregistering guild commands...").await?; - guild_id.set_commands(ctx, vec![]).await?; + guild_id.set_commands(ctx, &[]).await?; } } diff --git a/src/choice_parameter.rs b/src/choice_parameter.rs index 94b7753494a6..e8cb4f1b0c64 100644 --- a/src/choice_parameter.rs +++ b/src/choice_parameter.rs @@ -46,7 +46,7 @@ impl crate::SlashArgument for T { }) } - fn create(builder: serenity::CreateCommandOption) -> serenity::CreateCommandOption { + fn create(builder: serenity::CreateCommandOption<'_>) -> serenity::CreateCommandOption<'_> { builder.kind(serenity::CommandOptionType::Integer) } diff --git a/src/modal.rs b/src/modal.rs index e24f5cf9afb4..609f99877511 100644 --- a/src/modal.rs +++ b/src/modal.rs @@ -45,7 +45,7 @@ async fn execute_modal_generic< F: std::future::Future>, >( ctx: &serenity::Context, - create_interaction_response: impl FnOnce(serenity::CreateInteractionResponse) -> F, + create_interaction_response: impl FnOnce(serenity::CreateInteractionResponse<'static>) -> F, modal_custom_id: String, defaults: Option, timeout: Option, @@ -175,7 +175,10 @@ pub trait Modal: Sized { /// /// Optionally takes an initialized instance as pre-filled values of this modal (see /// [`Self::execute_with_defaults()`] for more info) - fn create(defaults: Option, custom_id: String) -> serenity::CreateInteractionResponse; + fn create( + defaults: Option, + custom_id: String, + ) -> serenity::CreateInteractionResponse<'static>; /// Parses a received modal submit interaction into this type /// diff --git a/src/reply/builder.rs b/src/reply/builder.rs index 980db844bf7a..ff6a860491d1 100644 --- a/src/reply/builder.rs +++ b/src/reply/builder.rs @@ -1,31 +1,33 @@ //! The builder to create a new reply +use std::borrow::Cow; + use crate::serenity_prelude as serenity; /// Message builder that abstracts over prefix and application command responses #[derive(Default, Clone)] -pub struct CreateReply { +pub struct CreateReply<'a> { /// Message content. - pub content: Option, + pub content: Option>, /// Embeds, if present. - pub embeds: Vec, + pub embeds: Vec>, /// Message attachments. - pub attachments: Vec, + pub attachments: Vec>, /// Whether the message is ephemeral (only has an effect in application commands) pub ephemeral: Option, /// Message components, that is, buttons and select menus. - pub components: Option>, + pub components: Option]>>, /// The allowed mentions for the message. - pub allowed_mentions: Option, + pub allowed_mentions: Option>, /// Whether this message is an inline reply. pub reply: bool, #[doc(hidden)] pub __non_exhaustive: (), } -impl CreateReply { +impl<'a> CreateReply<'a> { /// Set the content of the message. - pub fn content(mut self, content: impl Into) -> Self { + pub fn content(mut self, content: impl Into>) -> Self { self.content = Some(content.into()); self } @@ -33,7 +35,7 @@ impl CreateReply { /// Adds an embed to the message. /// /// Existing embeds are kept. - pub fn embed(mut self, embed: serenity::CreateEmbed) -> Self { + pub fn embed(mut self, embed: serenity::CreateEmbed<'a>) -> Self { self.embeds.push(embed); self } @@ -41,15 +43,18 @@ impl CreateReply { /// Set components (buttons and select menus) for this message. /// /// Any previously set components will be overwritten. - pub fn components(mut self, components: Vec) -> Self { - self.components = Some(components); + pub fn components( + mut self, + components: impl Into]>>, + ) -> Self { + self.components = Some(components.into()); self } /// Add an attachment. /// /// This will not have an effect in a slash command's initial response! - pub fn attachment(mut self, attachment: serenity::CreateAttachment) -> Self { + pub fn attachment(mut self, attachment: serenity::CreateAttachment<'a>) -> Self { self.attachments.push(attachment); self } @@ -65,7 +70,10 @@ impl CreateReply { /// Set the allowed mentions for the message. /// /// See [`serenity::CreateAllowedMentions`] for more information. - pub fn allowed_mentions(mut self, allowed_mentions: serenity::CreateAllowedMentions) -> Self { + pub fn allowed_mentions( + mut self, + allowed_mentions: serenity::CreateAllowedMentions<'a>, + ) -> Self { self.allowed_mentions = Some(allowed_mentions); self } @@ -83,12 +91,12 @@ impl CreateReply { /// Methods to create a message builder from any type from this [`CreateReply`]. Used by poise /// internally to actually send a response to Discord -impl CreateReply { +impl<'a> CreateReply<'a> { /// Serialize this response builder to a [`serenity::CreateInteractionResponseMessage`] pub fn to_slash_initial_response( self, - mut builder: serenity::CreateInteractionResponseMessage, - ) -> serenity::CreateInteractionResponseMessage { + mut builder: serenity::CreateInteractionResponseMessage<'a>, + ) -> serenity::CreateInteractionResponseMessage<'a> { let crate::CreateReply { content, embeds, @@ -119,8 +127,8 @@ impl CreateReply { /// Serialize this response builder to a [`serenity::CreateInteractionResponseFollowup`] pub fn to_slash_followup_response( self, - mut builder: serenity::CreateInteractionResponseFollowup, - ) -> serenity::CreateInteractionResponseFollowup { + mut builder: serenity::CreateInteractionResponseFollowup<'a>, + ) -> serenity::CreateInteractionResponseFollowup<'a> { let crate::CreateReply { content, embeds, @@ -152,8 +160,8 @@ impl CreateReply { /// Serialize this response builder to a [`serenity::EditInteractionResponse`] pub fn to_slash_initial_response_edit( self, - mut builder: serenity::EditInteractionResponse, - ) -> serenity::EditInteractionResponse { + mut builder: serenity::EditInteractionResponse<'a>, + ) -> serenity::EditInteractionResponse<'a> { let crate::CreateReply { content, embeds, @@ -179,7 +187,10 @@ impl CreateReply { } /// Serialize this response builder to a [`serenity::EditMessage`] - pub fn to_prefix_edit(self, mut builder: serenity::EditMessage) -> serenity::EditMessage { + pub fn to_prefix_edit( + self, + mut builder: serenity::EditMessage<'a>, + ) -> serenity::EditMessage<'a> { let crate::CreateReply { content, embeds, @@ -213,7 +224,7 @@ impl CreateReply { pub fn to_prefix( self, invocation_message: serenity::MessageReference, - ) -> serenity::CreateMessage { + ) -> serenity::CreateMessage<'a> { let crate::CreateReply { content, embeds, diff --git a/src/reply/mod.rs b/src/reply/mod.rs index 23c6e2287519..8f72a00a6fcf 100644 --- a/src/reply/mod.rs +++ b/src/reply/mod.rs @@ -93,10 +93,10 @@ impl ReplyHandle<'_> { // TODO: return the edited Message object? // TODO: should I eliminate the ctx parameter by storing it in self instead? Would infect // ReplyHandle with type parameters - pub async fn edit<'att, U, E>( + pub async fn edit<'att, 'a, U, E>( &self, - ctx: crate::Context<'_, U, E>, - builder: CreateReply, + ctx: crate::Context<'a, U, E>, + builder: CreateReply<'a>, ) -> Result<(), serenity::Error> { let reply = ctx.reply_builder(builder); diff --git a/src/reply/send_reply.rs b/src/reply/send_reply.rs index 5308e825da69..aa07a5d42b8d 100644 --- a/src/reply/send_reply.rs +++ b/src/reply/send_reply.rs @@ -23,10 +23,13 @@ use crate::serenity_prelude as serenity; /// ).await?; /// # Ok(()) } /// ``` -pub async fn send_reply( - ctx: crate::Context<'_, U, E>, - builder: crate::CreateReply, -) -> Result, serenity::Error> { +pub async fn send_reply<'ret, 'arg, U, E>( + ctx: crate::Context<'ret, U, E>, + builder: crate::CreateReply<'arg>, +) -> Result, serenity::Error> +where + 'ret: 'arg, +{ Ok(match ctx { crate::Context::Prefix(ctx) => super::ReplyHandle(super::ReplyHandleInner::Prefix( crate::send_prefix_reply(ctx, builder).await?, @@ -51,10 +54,13 @@ pub async fn say_reply( /// [followup](serenity::CommandInteraction::create_followup) is sent. /// /// No-op if autocomplete context -pub async fn send_application_reply( - ctx: crate::ApplicationContext<'_, U, E>, - builder: crate::CreateReply, -) -> Result, serenity::Error> { +pub async fn send_application_reply<'ret, 'arg, U, E>( + ctx: crate::ApplicationContext<'ret, U, E>, + builder: crate::CreateReply<'arg>, +) -> Result, serenity::Error> +where + 'ret: 'arg, +{ let builder = ctx.reply_builder(builder); if ctx.interaction_type == crate::CommandInteractionType::Autocomplete { @@ -98,9 +104,9 @@ pub async fn send_application_reply( } /// Prefix-specific reply function. For more details, see [`crate::send_reply`]. -pub async fn send_prefix_reply( - ctx: crate::PrefixContext<'_, U, E>, - builder: crate::CreateReply, +pub async fn send_prefix_reply<'a, U, E>( + ctx: crate::PrefixContext<'a, U, E>, + builder: crate::CreateReply<'a>, ) -> Result, serenity::Error> { let builder = ctx.reply_builder(builder); diff --git a/src/slash_argument/slash_trait.rs b/src/slash_argument/slash_trait.rs index df52687a0d32..1434d52c05ca 100644 --- a/src/slash_argument/slash_trait.rs +++ b/src/slash_argument/slash_trait.rs @@ -27,7 +27,7 @@ pub trait SlashArgument: Sized { /// filling in `name()`, `description()`, and possibly `required()` or other fields. /// /// Don't call this method directly! Use [`crate::create_slash_argument!`] - fn create(builder: serenity::CreateCommandOption) -> serenity::CreateCommandOption; + fn create(builder: serenity::CreateCommandOption<'_>) -> serenity::CreateCommandOption<'_>; /// If this is a choice parameter, returns the choices /// @@ -51,7 +51,10 @@ pub trait SlashArgumentHack: Sized { value: &serenity::ResolvedValue<'_>, ) -> Result; - fn create(self, builder: serenity::CreateCommandOption) -> serenity::CreateCommandOption; + fn create( + self, + builder: serenity::CreateCommandOption<'_>, + ) -> serenity::CreateCommandOption<'_>; fn choices(self) -> Vec { Vec::new() @@ -124,7 +127,10 @@ where }) } - fn create(self, builder: serenity::CreateCommandOption) -> serenity::CreateCommandOption { + fn create( + self, + builder: serenity::CreateCommandOption<'_>, + ) -> serenity::CreateCommandOption<'_> { builder.kind(serenity::CommandOptionType::String) } } @@ -151,7 +157,7 @@ macro_rules! impl_for_integer { } } - fn create(builder: serenity::CreateCommandOption) -> serenity::CreateCommandOption { + fn create(builder: serenity::CreateCommandOption<'_>) -> serenity::CreateCommandOption<'_> { builder .min_number_value(f64::max(<$t>::MIN as f64, -9007199254740991.)) .max_number_value(f64::min(<$t>::MAX as f64, 9007199254740991.)) @@ -173,7 +179,10 @@ impl SlashArgumentHack for &PhantomData { ::extract(ctx, interaction, value).await } - fn create(self, builder: serenity::CreateCommandOption) -> serenity::CreateCommandOption { + fn create( + self, + builder: serenity::CreateCommandOption<'_>, + ) -> serenity::CreateCommandOption<'_> { ::create(builder) } @@ -200,7 +209,7 @@ macro_rules! impl_slash_argument { } } - fn create(builder: serenity::CreateCommandOption) -> serenity::CreateCommandOption { + fn create(builder: serenity::CreateCommandOption<'_>) -> serenity::CreateCommandOption<'_> { builder.kind(serenity::CommandOptionType::$slash_param_type) } } diff --git a/src/structs/command.rs b/src/structs/command.rs index 453a4840151f..e1ea62050237 100644 --- a/src/structs/command.rs +++ b/src/structs/command.rs @@ -1,7 +1,12 @@ //! The Command struct, which stores all information about a single framework command +use std::borrow::Cow; + use crate::{serenity_prelude as serenity, BoxFuture}; +/// Default name given to commands +const DEFAULT_NAME: Cow<'static, str> = Cow::Borrowed("A slash command"); + /// Type returned from `#[poise::command]` annotated functions, which contains all of the generated /// prefix and application commands #[derive(derivative::Derivative)] @@ -138,7 +143,7 @@ impl Eq for Command {} impl Command { /// Serializes this Command into an application command option, which is the form which Discord /// requires subcommands to be in - fn create_as_subcommand(&self) -> Option { + fn create_as_subcommand(&self) -> Option> { self.slash_action?; let kind = if self.subcommands.is_empty() { @@ -147,14 +152,14 @@ impl Command { serenity::CommandOptionType::SubCommandGroup }; - let description = self.description.as_deref().unwrap_or("A slash command"); + let description = self.description.clone().map_or(DEFAULT_NAME, Cow::Owned); let mut builder = serenity::CreateCommandOption::new(kind, self.name.clone(), description); for (locale, name) in &self.name_localizations { - builder = builder.name_localized(locale, name); + builder = builder.name_localized(locale.clone(), name.clone()); } for (locale, description) in &self.description_localizations { - builder = builder.description_localized(locale, description); + builder = builder.description_localized(locale.clone(), description.clone()); } if self.subcommands.is_empty() { @@ -176,17 +181,17 @@ impl Command { /// Generates a slash command builder from this [`Command`] instance. This can be used /// to register this command on Discord's servers - pub fn create_as_slash_command(&self) -> Option { + pub fn create_as_slash_command(&self) -> Option> { self.slash_action?; let mut builder = serenity::CreateCommand::new(self.name.clone()) - .description(self.description.as_deref().unwrap_or("A slash command")); + .description(self.description.clone().map_or(DEFAULT_NAME, Cow::Owned)); for (locale, name) in &self.name_localizations { - builder = builder.name_localized(locale, name); + builder = builder.name_localized(locale.clone(), name.clone()); } for (locale, description) in &self.description_localizations { - builder = builder.description_localized(locale, description); + builder = builder.description_localized(locale.clone(), description.clone()); } // This is_empty check is needed because Discord special cases empty @@ -218,11 +223,11 @@ impl Command { /// Generates a context menu command builder from this [`Command`] instance. This can be used /// to register this command on Discord's servers - pub fn create_as_context_menu_command(&self) -> Option { + pub fn create_as_context_menu_command(&self) -> Option> { let context_menu_action = self.context_menu_action?; // TODO: localization? - let name = self.context_menu_name.as_deref().unwrap_or(&self.name); + let name = self.context_menu_name.clone().unwrap_or(self.name.clone()); let mut builder = serenity::CreateCommand::new(name).kind(match context_menu_action { crate::ContextMenuCommandAction::User(_) => serenity::CommandType::User, crate::ContextMenuCommandAction::Message(_) => serenity::CommandType::Message, diff --git a/src/structs/context.rs b/src/structs/context.rs index 4464cc8a1bb7..4691592c5f14 100644 --- a/src/structs/context.rs +++ b/src/structs/context.rs @@ -48,23 +48,23 @@ macro_rules! context_methods { // pub $(async $($dummy:block)?)? fn $fn_name:ident $() // $fn_name:ident ($($sig:tt)*) $body:block $($await:ident)? ( $fn_name:ident $self:ident $($arg:ident)* ) - ( $($sig:tt)* ) $body:block + ( $($sig:tt)* ) $(where $b1:lifetime : $b2:lifetime)? $body:block )* ) => { impl<'a, U, E> Context<'a, U, E> { $( $( #[$($attrs)*] )* - $($sig)* $body + $($sig)* $(where $b1:$b2)* $body )* } impl<'a, U, E> crate::PrefixContext<'a, U, E> { $( $( #[$($attrs)*] )* - $($sig)* { + $($sig)* $(where $b1:$b2)* { $crate::Context::Prefix($self).$fn_name($($arg)*) $(.$await)? } )* } impl<'a, U, E> crate::ApplicationContext<'a, U, E> { $( $( #[$($attrs)*] )* - $($sig)* { + $($sig)* $(where $b1:$b2)* { $crate::Context::Application($self).$fn_name($($arg)*) $(.$await)? } )* } @@ -144,7 +144,7 @@ context_methods! { await (reply self text) (pub async fn reply( self, - text: impl Into, + text: impl Into>, ) -> Result, serenity::Error>) { self.send(crate::CreateReply::default().content(text).reply(true)).await } @@ -155,7 +155,7 @@ context_methods! { await (send self builder) (pub async fn send<'att>( self, - builder: crate::CreateReply, + builder: crate::CreateReply<'a>, ) -> Result, serenity::Error>) { crate::send_reply(self, builder).await } @@ -493,7 +493,7 @@ context_methods! { /// convert [`crate::CreateReply`] instances into Discord requests. #[allow(unused_mut)] // side effect of how macro works (reply_builder self builder) - (pub fn reply_builder(self, mut builder: crate::CreateReply) -> crate::CreateReply) { + (pub fn reply_builder(self, mut builder: crate::CreateReply<'a>) -> crate::CreateReply<'a>) { let fw_options = self.framework().options(); builder.ephemeral = builder.ephemeral.or(Some(self.command().ephemeral)); builder.allowed_mentions = builder.allowed_mentions.or_else(|| fw_options.allowed_mentions.clone()); diff --git a/src/structs/framework_options.rs b/src/structs/framework_options.rs index 3ec310e9c3c5..20b94d73fcf1 100644 --- a/src/structs/framework_options.rs +++ b/src/structs/framework_options.rs @@ -28,13 +28,14 @@ pub struct FrameworkOptions { /// Default set of allowed mentions to use for all responses /// /// By default, user pings are allowed and role pings and everyone pings are filtered - pub allowed_mentions: Option, + pub allowed_mentions: Option>, /// Invoked before every message sent using [`crate::Context::say`] or [`crate::Context::send`] /// /// Allows you to modify every outgoing message in a central place #[derivative(Debug = "ignore")] - pub reply_callback: - Option, crate::CreateReply) -> crate::CreateReply>, + pub reply_callback: Option< + for<'a> fn(crate::Context<'a, U, E>, crate::CreateReply<'a>) -> crate::CreateReply<'a>, + >, /// If `true`, disables automatic cooldown handling before every command invocation. /// /// Useful for implementing custom cooldown behavior. See [`crate::Command::cooldowns`] and diff --git a/src/structs/slash.rs b/src/structs/slash.rs index 9419bc923437..39cc97ab8815 100644 --- a/src/structs/slash.rs +++ b/src/structs/slash.rs @@ -1,5 +1,7 @@ //! Holds application command definition structs. +use std::{borrow::Cow, collections::HashMap}; + use crate::{serenity_prelude as serenity, BoxFuture}; /// Specifies if the current invokation is from a Command or Autocomplete. @@ -118,9 +120,9 @@ impl Clone for ContextMenuCommandAction { #[derive(Debug, Clone)] pub struct CommandParameterChoice { /// Label of this choice - pub name: String, + pub name: Cow<'static, str>, /// Localized labels with locale string as the key (slash-only) - pub localizations: std::collections::HashMap, + pub localizations: HashMap, Cow<'static, str>>, #[doc(hidden)] pub __non_exhaustive: (), } @@ -132,11 +134,11 @@ pub struct CommandParameter { /// Name of this command parameter pub name: String, /// Localized names with locale string as the key (slash-only) - pub name_localizations: std::collections::HashMap, + pub name_localizations: HashMap, /// Description of the command. Required for slash commands pub description: Option, /// Localized descriptions with locale string as the key (slash-only) - pub description_localizations: std::collections::HashMap, + pub description_localizations: HashMap, /// `true` is this parameter is required, `false` if it's optional or variadic pub required: bool, /// If this parameter is a channel, users can only enter these channel types in a slash command @@ -151,11 +153,12 @@ pub struct CommandParameter { /// ```rust /// # use poise::serenity_prelude as serenity; /// # let _: fn(serenity::CreateCommandOption) -> serenity::CreateCommandOption = - /// |b| b.kind(serenity::CommandOptionType::Integer).min_int_value(0).max_int_value(u64::MAX) + /// |b| b.kind(serenity::CommandOptionType::Integer).min_int_value(0).max_int_value(i64::MAX) /// # ; /// ``` #[derivative(Debug = "ignore")] - pub type_setter: Option serenity::CreateCommandOption>, + pub type_setter: + Option) -> serenity::CreateCommandOption<'_>>, /// Optionally, a callback that is invoked on autocomplete interactions. This closure should /// extract the partial argument from the given JSON value and generate the autocomplete /// response which contains the list of autocomplete suggestions. @@ -166,7 +169,7 @@ pub struct CommandParameter { &'a str, ) -> BoxFuture< 'a, - Result, + Result, crate::SlashArgError>, >, >, #[doc(hidden)] @@ -176,13 +179,13 @@ pub struct CommandParameter { impl CommandParameter { /// Generates a slash command parameter builder from this [`CommandParameter`] instance. This /// can be used to register the command on Discord's servers - pub fn create_as_slash_command_option(&self) -> Option { + pub fn create_as_slash_command_option(&self) -> Option> { let description = self .description - .as_deref() - .unwrap_or("A slash command parameter"); + .clone() + .map_or(Cow::Borrowed("A slash command parameter"), Cow::Owned); - let mut builder = serenity::CreateCommandOption::new( + let mut builder = serenity::CreateCommandOption::<'static>::new( serenity::CommandOptionType::String, self.name.clone(), description, @@ -193,17 +196,20 @@ impl CommandParameter { .set_autocomplete(self.autocomplete_callback.is_some()); for (locale, name) in &self.name_localizations { - builder = builder.name_localized(locale, name); + builder = builder.name_localized(locale.clone(), name.clone()); } for (locale, description) in &self.description_localizations { - builder = builder.description_localized(locale, description); + builder = builder.description_localized(locale.clone(), description.clone()); } if let Some(channel_types) = self.channel_types.clone() { builder = builder.channel_types(channel_types); } for (i, choice) in self.choices.iter().enumerate() { - builder = - builder.add_int_choice_localized(&choice.name, i as _, choice.localizations.iter()); + builder = builder.add_int_choice_localized( + choice.name.clone(), + i as _, + choice.localizations.clone(), + ); } Some((self.type_setter?)(builder))