From 241b24b9ed3ee0e8902f7c2af9b8df32d630efa5 Mon Sep 17 00:00:00 2001 From: David Thomas Date: Sun, 26 Nov 2023 22:48:31 +0000 Subject: [PATCH] Port poise to use serenity data generic --- Cargo.lock | 11 +---- Cargo.toml | 3 +- examples/advanced_cooldowns/main.rs | 9 ++-- examples/basic_structure/main.rs | 12 +++-- examples/event_handler/main.rs | 24 ++++------ examples/feature_showcase/main.rs | 4 +- examples/feature_showcase/modal.rs | 3 +- examples/fluent_localization/main.rs | 3 +- examples/generic_commands/main.rs | 2 +- examples/help_generation/main.rs | 4 +- examples/invocation_data/main.rs | 2 +- examples/manual_dispatch/main.rs | 8 ++-- examples/quickstart/main.rs | 4 +- src/builtins/help.rs | 20 ++++---- src/builtins/mod.rs | 8 ++-- src/builtins/paginate.rs | 2 +- src/builtins/register.rs | 12 ++--- src/choice_parameter.rs | 8 ++-- src/dispatch/common.rs | 16 +++++-- src/dispatch/mod.rs | 31 ++++-------- src/dispatch/prefix.rs | 16 +++---- src/dispatch/slash.rs | 23 +++++---- src/framework/builder.rs | 14 +++--- src/framework/mod.rs | 68 ++++++++++----------------- src/lib.rs | 7 +-- src/modal.rs | 7 +-- src/prefix_argument/argument_trait.rs | 24 +++++----- src/prefix_argument/code_block.rs | 4 +- src/prefix_argument/key_value_args.rs | 4 +- src/prefix_argument/macros.rs | 2 +- src/reply/mod.rs | 7 ++- src/reply/send_reply.rs | 8 ++-- src/slash_argument/context_menu.rs | 6 +-- src/slash_argument/slash_macro.rs | 2 +- src/slash_argument/slash_trait.rs | 36 +++++++------- src/structs/command.rs | 8 ++-- src/structs/context.rs | 57 ++++++++++------------ src/structs/framework_error.rs | 26 +++++----- src/structs/framework_options.rs | 12 ++--- src/structs/prefix.rs | 23 ++++----- src/structs/slash.rs | 26 +++++----- 41 files changed, 260 insertions(+), 306 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9223602f727..7c1ff534f6d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1326,8 +1326,7 @@ dependencies = [ [[package]] name = "serenity" version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385647faa24a889929028973650a4f158fb1b4272b2fcf94feb9fcc3c009e813" +source = "git+https://github.com/gnomeddev/serenity?branch=typemap-be-gone#994ca84dde9df2148b3fa01ca8a731ead58d0bab" dependencies = [ "arrayvec", "async-trait", @@ -1336,6 +1335,7 @@ dependencies = [ "bytes", "chrono", "dashmap", + "derivative", "flate2", "futures", "fxhash", @@ -1350,7 +1350,6 @@ dependencies = [ "tokio", "tokio-tungstenite", "tracing", - "typemap_rev", "typesize", "url", ] @@ -1718,12 +1717,6 @@ dependencies = [ "rustc-hash", ] -[[package]] -name = "typemap_rev" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b08b0c1257381af16a5c3605254d529d3e7e109f3c62befc5d168968192998" - [[package]] name = "typenum" version = "1.17.0" diff --git a/Cargo.toml b/Cargo.toml index 46e757405351..898e7eec2e6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,8 @@ parking_lot = "0.12.1" [dependencies.serenity] default-features = false features = ["builder", "client", "gateway", "model", "utils", "collector", "framework"] -version = "0.12.0" +git = "https://github.com/gnomeddev/serenity" +branch = "typemap-be-gone" [dev-dependencies] # For the examples diff --git a/examples/advanced_cooldowns/main.rs b/examples/advanced_cooldowns/main.rs index d21c4fda208e..bea364e2f49d 100644 --- a/examples/advanced_cooldowns/main.rs +++ b/examples/advanced_cooldowns/main.rs @@ -41,14 +41,15 @@ async fn main() { .setup(|ctx, _ready, framework| { Box::pin(async move { poise::builtins::register_globally(ctx, &framework.options().commands).await?; - Ok(Data {}) + Ok(()) }) }) .build(); - let client = serenity::Client::builder(token, serenity::GatewayIntents::non_privileged()) - .framework(framework) - .await; + let client = + serenity::Client::builder(token, serenity::GatewayIntents::non_privileged(), Data {}) + .framework(framework) + .await; client.unwrap().start().await.unwrap(); } diff --git a/examples/basic_structure/main.rs b/examples/basic_structure/main.rs index 6046e02e1e84..a4478dee1ab2 100644 --- a/examples/basic_structure/main.rs +++ b/examples/basic_structure/main.rs @@ -81,7 +81,7 @@ async fn main() { // Enforce command checks even for owners (enforced by default) // Set to true to bypass checks, which is useful for testing skip_checks_for_owners: false, - event_handler: |_ctx, event, _framework, _data| { + event_handler: |_ctx, event, _framework| { Box::pin(async move { println!( "Got an event in event handler: {:?}", @@ -93,14 +93,16 @@ async fn main() { ..Default::default() }; + let data = Data { + votes: Mutex::new(HashMap::new()), + }; + let framework = poise::Framework::builder() .setup(move |ctx, _ready, framework| { Box::pin(async move { println!("Logged in as {}", _ready.user.name); poise::builtins::register_globally(ctx, &framework.options().commands).await?; - Ok(Data { - votes: Mutex::new(HashMap::new()), - }) + Ok(()) }) }) .options(options) @@ -111,7 +113,7 @@ async fn main() { let intents = serenity::GatewayIntents::non_privileged() | serenity::GatewayIntents::MESSAGE_CONTENT; - let client = serenity::ClientBuilder::new(token, intents) + let client = serenity::ClientBuilder::new(token, intents, data) .framework(framework) .await; diff --git a/examples/event_handler/main.rs b/examples/event_handler/main.rs index a923127162d9..3e94e7e46bdb 100644 --- a/examples/event_handler/main.rs +++ b/examples/event_handler/main.rs @@ -17,28 +17,23 @@ pub struct Data { async fn main() { env_logger::init(); + let data = Data { + poise_mentions: AtomicU32::new(0), + }; + let token = var("DISCORD_TOKEN") .expect("Missing `DISCORD_TOKEN` env var, see README for more information."); let intents = serenity::GatewayIntents::non_privileged() | serenity::GatewayIntents::MESSAGE_CONTENT; let framework = poise::Framework::builder() - .setup(move |_ctx, _ready, _framework| { - Box::pin(async move { - Ok(Data { - poise_mentions: AtomicU32::new(0), - }) - }) - }) .options(poise::FrameworkOptions { - event_handler: |ctx, event, framework, data| { - Box::pin(event_handler(ctx, event, framework, data)) - }, + event_handler: |ctx, event, framework| Box::pin(event_handler(ctx, event, framework)), ..Default::default() }) .build(); - let client = serenity::ClientBuilder::new(token, intents) + let client = serenity::ClientBuilder::new(token, intents, data) .framework(framework) .await; @@ -46,10 +41,9 @@ async fn main() { } async fn event_handler( - ctx: &serenity::Context, + ctx: &serenity::Context, event: &serenity::FullEvent, _framework: poise::FrameworkContext<'_, Data, Error>, - data: &Data, ) -> Result<(), Error> { match event { serenity::FullEvent::Ready { data_about_bot, .. } => { @@ -57,8 +51,8 @@ async fn event_handler( } serenity::FullEvent::Message { new_message } => { if new_message.content.to_lowercase().contains("poise") { - let mentions = data.poise_mentions.load(Ordering::SeqCst) + 1; - data.poise_mentions.store(mentions, Ordering::SeqCst); + let mentions = ctx.data.poise_mentions.load(Ordering::SeqCst) + 1; + ctx.data.poise_mentions.store(mentions, Ordering::SeqCst); new_message .reply(ctx, format!("Poise has been mentioned {} times", mentions)) .await?; diff --git a/examples/feature_showcase/main.rs b/examples/feature_showcase/main.rs index 34ef67041659..b93037c07390 100644 --- a/examples/feature_showcase/main.rs +++ b/examples/feature_showcase/main.rs @@ -94,7 +94,7 @@ async fn main() { .setup(move |ctx, _ready, framework| { Box::pin(async move { poise::builtins::register_globally(ctx, &framework.options().commands).await?; - Ok(Data {}) + Ok(()) }) }) .build(); @@ -103,7 +103,7 @@ async fn main() { let intents = serenity::GatewayIntents::non_privileged() | serenity::GatewayIntents::MESSAGE_CONTENT; - let client = serenity::ClientBuilder::new(token, intents) + let client = serenity::ClientBuilder::new(token, intents, Data {}) .framework(framework) .await; diff --git a/examples/feature_showcase/modal.rs b/examples/feature_showcase/modal.rs index 32be2503f150..be8c090518c8 100644 --- a/examples/feature_showcase/modal.rs +++ b/examples/feature_showcase/modal.rs @@ -43,7 +43,8 @@ pub async fn component_modal(ctx: crate::Context<'_>) -> Result<(), Error> { .await { let data = - poise::execute_modal_on_component_interaction::(ctx, mci, None, None).await?; + poise::execute_modal_on_component_interaction::(ctx, mci, None, None) + .await?; println!("Got data: {:?}", data); } Ok(()) diff --git a/examples/fluent_localization/main.rs b/examples/fluent_localization/main.rs index f215a3a99584..85bdd19198da 100644 --- a/examples/fluent_localization/main.rs +++ b/examples/fluent_localization/main.rs @@ -72,10 +72,9 @@ async fn main() { commands, ..Default::default() }) - .setup(move |_, _, _| Box::pin(async move { Ok(Data { translations }) })) .build(); - let client = serenity::ClientBuilder::new(token, intents) + let client = serenity::ClientBuilder::new(token, intents, Data { translations }) .framework(framework) .await; diff --git a/examples/generic_commands/main.rs b/examples/generic_commands/main.rs index 8842eae8e938..ef8066f23365 100644 --- a/examples/generic_commands/main.rs +++ b/examples/generic_commands/main.rs @@ -4,7 +4,7 @@ //! The original use case for this feature was to have the same command in two different bots #[poise::command(slash_command)] -pub async fn example(ctx: poise::Context<'_, U, E>) -> Result<(), E> { +pub async fn example(ctx: poise::Context<'_, U, E>) -> Result<(), E> { ctx.say(format!( "My user data type is {} and the error type is {}", std::any::type_name::(), diff --git a/examples/help_generation/main.rs b/examples/help_generation/main.rs index 756372918930..f7c269fb1a31 100644 --- a/examples/help_generation/main.rs +++ b/examples/help_generation/main.rs @@ -345,12 +345,12 @@ async fn main() { .setup(|ctx, _ready, framework| { Box::pin(async move { poise::builtins::register_globally(ctx, &framework.options().commands).await?; - Ok(Data {}) + Ok(()) }) }) .build(); - let client = serenity::ClientBuilder::new(token, intents) + let client = serenity::ClientBuilder::new(token, intents, Data {}) .framework(framework) .await; diff --git a/examples/invocation_data/main.rs b/examples/invocation_data/main.rs index 21c18e08600f..ec6014a39846 100644 --- a/examples/invocation_data/main.rs +++ b/examples/invocation_data/main.rs @@ -121,7 +121,7 @@ async fn main() { }) .build(); - let client = serenity::ClientBuilder::new(token, intents) + let client = serenity::ClientBuilder::new(token, intents, ()) .framework(framework) .await; diff --git a/examples/manual_dispatch/main.rs b/examples/manual_dispatch/main.rs index f6595ae20a7f..6baf24bf8513 100644 --- a/examples/manual_dispatch/main.rs +++ b/examples/manual_dispatch/main.rs @@ -6,6 +6,7 @@ use poise::serenity_prelude as serenity; +type Data = (); type Error = serenity::Error; #[poise::command(prefix_command)] @@ -19,14 +20,13 @@ struct Handler { shard_manager: std::sync::Mutex>>, } #[serenity::async_trait] -impl serenity::EventHandler for Handler { - async fn message(&self, ctx: serenity::Context, new_message: serenity::Message) { +impl serenity::EventHandler for Handler { + async fn message(&self, ctx: serenity::Context, new_message: serenity::Message) { // FrameworkContext contains all data that poise::Framework usually manages let shard_manager = (*self.shard_manager.lock().unwrap()).clone().unwrap(); let framework_data = poise::FrameworkContext { bot_id: serenity::UserId::new(846453852164587620), options: &self.options, - user_data: &(), shard_manager: &shard_manager, }; @@ -51,7 +51,7 @@ async fn main() -> Result<(), Error> { poise::set_qualified_names(&mut handler.options.commands); // some setup let handler = std::sync::Arc::new(handler); - let mut client = serenity::Client::builder(token, intents) + let mut client = serenity::Client::builder(token, intents, ()) .event_handler_arc(handler.clone()) .await?; diff --git a/examples/quickstart/main.rs b/examples/quickstart/main.rs index ea2220999751..6433054ef0ac 100644 --- a/examples/quickstart/main.rs +++ b/examples/quickstart/main.rs @@ -29,12 +29,12 @@ async fn main() { .setup(|ctx, _ready, framework| { Box::pin(async move { poise::builtins::register_globally(ctx, &framework.options().commands).await?; - Ok(Data {}) + Ok(()) }) }) .build(); - let client = serenity::ClientBuilder::new(token, intents) + let client = serenity::ClientBuilder::new(token, intents, Data {}) .framework(framework) .await; client.unwrap().start().await.unwrap(); diff --git a/src/builtins/help.rs b/src/builtins/help.rs index e5da994ef7d8..f4c3547ee520 100644 --- a/src/builtins/help.rs +++ b/src/builtins/help.rs @@ -85,7 +85,9 @@ impl TwoColumnList { } /// Get the prefix from options -async fn get_prefix_from_options(ctx: crate::Context<'_, U, E>) -> Option { +async fn get_prefix_from_options( + ctx: crate::Context<'_, U, E>, +) -> Option { let options = &ctx.framework().options().prefix_options; match &options.prefix { Some(fixed_prefix) => Some(fixed_prefix.clone()), @@ -102,7 +104,9 @@ async fn get_prefix_from_options(ctx: crate::Context<'_, U, E>) -> Option< } /// Format context menu command name -fn format_context_menu_name(command: &crate::Command) -> Option { +fn format_context_menu_name( + command: &crate::Command, +) -> Option { let kind = match command.context_menu_action { Some(crate::ContextMenuCommandAction::User(_)) => "user", Some(crate::ContextMenuCommandAction::Message(_)) => "message", @@ -120,7 +124,7 @@ fn format_context_menu_name(command: &crate::Command) -> Option( +async fn help_single_command( ctx: crate::Context<'_, U, E>, command_name: &str, config: HelpConfiguration<'_>, @@ -234,7 +238,7 @@ async fn help_single_command( } /// Recursively formats all subcommands -fn preformat_subcommands( +fn preformat_subcommands( commands: &mut TwoColumnList, command: &crate::Command, prefix: &str, @@ -259,7 +263,7 @@ fn preformat_subcommands( } /// Preformat lines (except for padding,) like `(" /ping", "Emits a ping message")` -fn preformat_command( +fn preformat_command( commands: &mut TwoColumnList, config: &HelpConfiguration<'_>, command: &crate::Command, @@ -289,7 +293,7 @@ fn preformat_command( /// Create help text for `help_all_commands` /// /// This is a separate function so we can have tests for it -async fn generate_all_commands( +async fn generate_all_commands( ctx: crate::Context<'_, U, E>, config: &HelpConfiguration<'_>, ) -> Result { @@ -348,7 +352,7 @@ async fn generate_all_commands( } /// Code for printing an overview of all commands (e.g. `~help`) -async fn help_all_commands( +async fn help_all_commands( ctx: crate::Context<'_, U, E>, config: HelpConfiguration<'_>, ) -> Result<(), serenity::Error> { @@ -414,7 +418,7 @@ async fn help_all_commands( /// Type ?help command for more info on a command. /// You can edit your message to the bot and the bot will edit its response. /// ``` -pub async fn help( +pub async fn help( ctx: crate::Context<'_, U, E>, command: Option<&str>, config: HelpConfiguration<'_>, diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index 718436ab43ee..e3b689ef4485 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -32,7 +32,7 @@ use crate::{serenity_prelude as serenity, CreateReply}; /// } /// # }; /// ``` -pub async fn on_error( +pub async fn on_error( error: crate::FrameworkError<'_, U, E>, ) -> Result<(), serenity::Error> { match error { @@ -199,7 +199,7 @@ pub async fn on_error( /// /// See `examples/feature_showcase` for an example #[allow(clippy::unused_async)] // Required for the return type -pub async fn autocomplete_command<'a, U, E>( +pub async fn autocomplete_command<'a, U: Send + Sync + 'static, E>( ctx: crate::Context<'a, U, E>, partial: &'a str, ) -> impl Iterator + 'a { @@ -224,7 +224,9 @@ pub async fn autocomplete_command<'a, U, E>( /// > - **A public server** (7123 members) /// > - [3 private servers with 456 members total] #[cfg(feature = "cache")] -pub async fn servers(ctx: crate::Context<'_, U, E>) -> Result<(), serenity::Error> { +pub async fn servers( + ctx: crate::Context<'_, U, E>, +) -> Result<(), serenity::Error> { use std::fmt::Write as _; let show_private_guilds = ctx.framework().options().owners.contains(&ctx.author().id); diff --git a/src/builtins/paginate.rs b/src/builtins/paginate.rs index 83094be06b58..affeb747b4ec 100644 --- a/src/builtins/paginate.rs +++ b/src/builtins/paginate.rs @@ -32,7 +32,7 @@ use crate::serenity_prelude as serenity; /// ``` /// /// ![Screenshot of output](https://i.imgur.com/JGFDveA.png) -pub async fn paginate( +pub async fn paginate( ctx: crate::Context<'_, U, E>, pages: &[&str], ) -> Result<(), serenity::Error> { diff --git a/src/builtins/register.rs b/src/builtins/register.rs index 8caa9a2f2b1b..8ca6ccddc70b 100644 --- a/src/builtins/register.rs +++ b/src/builtins/register.rs @@ -16,14 +16,14 @@ use crate::serenity_prelude as serenity; /// serenity::Command::set_global_commands(ctx, create_commands).await?; /// # Ok(()) } /// ``` -pub fn create_application_commands( +pub fn create_application_commands( commands: &[crate::Command], ) -> 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( + fn recursively_add_context_menu_commands( builder: &mut Vec, command: &crate::Command, ) { @@ -49,7 +49,7 @@ pub fn create_application_commands( /// /// Thin wrapper around [`create_application_commands`] that funnels the returned builder into /// [`serenity::Command::set_global_commands`]. -pub async fn register_globally( +pub async fn register_globally( http: impl AsRef, commands: &[crate::Command], ) -> Result<(), serenity::Error> { @@ -62,7 +62,7 @@ pub async fn register_globally( /// /// Thin wrapper around [`create_application_commands`] that funnels the returned builder into /// [`serenity::GuildId::set_commands`]. -pub async fn register_in_guild( +pub async fn register_in_guild( http: impl AsRef, commands: &[crate::Command], guild_id: serenity::GuildId, @@ -85,7 +85,7 @@ pub async fn register_in_guild( /// /// Run with no arguments to register in guild, run with argument "global" to register globally. /// ``` -pub async fn register_application_commands( +pub async fn register_application_commands( ctx: crate::Context<'_, U, E>, global: bool, ) -> Result<(), serenity::Error> { @@ -148,7 +148,7 @@ pub async fn register_application_commands( /// ``` /// /// Which you can call like any prefix command, for example `@your_bot register`. -pub async fn register_application_commands_buttons( +pub async fn register_application_commands_buttons( ctx: crate::Context<'_, U, E>, ) -> Result<(), serenity::Error> { let create_commands = create_application_commands(&ctx.framework().options().commands); diff --git a/src/choice_parameter.rs b/src/choice_parameter.rs index 94b7753494a6..fa96746f86e0 100644 --- a/src/choice_parameter.rs +++ b/src/choice_parameter.rs @@ -24,8 +24,8 @@ pub trait ChoiceParameter: Sized { #[async_trait::async_trait] impl crate::SlashArgument for T { - async fn extract( - _: &serenity::Context, + async fn extract( + _: &serenity::Context, _: &serenity::CommandInteraction, value: &serenity::ResolvedValue<'_>, ) -> ::std::result::Result { @@ -57,10 +57,10 @@ impl crate::SlashArgument for T { #[async_trait::async_trait] impl<'a, T: ChoiceParameter> crate::PopArgument<'a> for T { - async fn pop_from( + async fn pop_from( args: &'a str, attachment_index: usize, - ctx: &serenity::Context, + ctx: &serenity::Context, msg: &serenity::Message, ) -> Result<(&'a str, usize, Self), (Box, Option)> { diff --git a/src/dispatch/common.rs b/src/dispatch/common.rs index ded0a852990c..c4295bd9356a 100644 --- a/src/dispatch/common.rs +++ b/src/dispatch/common.rs @@ -4,8 +4,8 @@ use crate::serenity_prelude as serenity; /// Retrieves user permissions in the given channel. If unknown, returns None. If in DMs, returns /// `Permissions::all()`. -async fn user_permissions( - ctx: &serenity::Context, +async fn user_permissions( + ctx: &serenity::Context, guild_id: Option, channel_id: serenity::ChannelId, user_id: serenity::UserId, @@ -37,7 +37,7 @@ async fn user_permissions( /// Retrieves the set of permissions that are lacking, relative to the given required permission set /// /// Returns None if permissions couldn't be retrieved -async fn missing_permissions( +async fn missing_permissions( ctx: crate::Context<'_, U, E>, user: serenity::UserId, required_permissions: serenity::Permissions, @@ -61,7 +61,10 @@ async fn missing_permissions( async fn check_permissions_and_cooldown_single<'a, U, E>( ctx: crate::Context<'a, U, E>, cmd: &'a crate::Command, -) -> Result<(), crate::FrameworkError<'a, U, E>> { +) -> Result<(), crate::FrameworkError<'a, U, E>> +where + U: Send + Sync + 'static, +{ // Skip command checks if `FrameworkOptions::skip_checks_for_owners` is set to true if ctx.framework().options.skip_checks_for_owners && ctx.framework().options().owners.contains(&ctx.author().id) @@ -180,7 +183,10 @@ async fn check_permissions_and_cooldown_single<'a, U, E>( #[allow(clippy::needless_lifetimes)] // false positive (clippy issue 7271) pub async fn check_permissions_and_cooldown<'a, U, E>( ctx: crate::Context<'a, U, E>, -) -> Result<(), crate::FrameworkError<'a, U, E>> { +) -> Result<(), crate::FrameworkError<'a, U, E>> +where + U: Send + Sync + 'static, +{ for parent_command in ctx.parent_commands() { check_permissions_and_cooldown_single(ctx, parent_command).await?; } diff --git a/src/dispatch/mod.rs b/src/dispatch/mod.rs index 38c29fe8e793..8caf628c0d68 100644 --- a/src/dispatch/mod.rs +++ b/src/dispatch/mod.rs @@ -13,25 +13,23 @@ use crate::serenity_prelude as serenity; // TODO: integrate serenity::Context in here? Every place where FrameworkContext is passed is also // passed serenity::Context /// A view into data stored by [`crate::Framework`] -pub struct FrameworkContext<'a, U, E> { +pub struct FrameworkContext<'a, U: Send + Sync + 'static, E> { /// User ID of this bot pub bot_id: serenity::UserId, /// Framework configuration pub options: &'a crate::FrameworkOptions, - /// Your provided user data - pub user_data: &'a U, /// Serenity shard manager. Can be used for example to shutdown the bot pub shard_manager: &'a std::sync::Arc, // deliberately not non exhaustive because you need to create FrameworkContext from scratch // to run your own event loop } -impl Copy for FrameworkContext<'_, U, E> {} -impl Clone for FrameworkContext<'_, U, E> { +impl Copy for FrameworkContext<'_, U, E> {} +impl Clone for FrameworkContext<'_, U, E> { fn clone(&self) -> Self { *self } } -impl<'a, U, E> FrameworkContext<'a, U, E> { +impl<'a, U: Send + Sync + 'static, E> FrameworkContext<'a, U, E> { /// Returns the stored framework options, including commands. /// /// This function exists for API compatiblity with [`crate::Framework`]. On this type, you can @@ -47,21 +45,12 @@ impl<'a, U, E> FrameworkContext<'a, U, E> { pub fn shard_manager(&self) -> std::sync::Arc { self.shard_manager.clone() } - - /// Retrieves user data - /// - /// This function exists for API compatiblity with [`crate::Framework`]. On this type, you can - /// also just access the public `user_data` field. - #[allow(clippy::unused_async)] // for API compatibility with Framework - pub async fn user_data(&self) -> &'a U { - self.user_data - } } /// Central event handling function of this library pub async fn dispatch_event( framework: crate::FrameworkContext<'_, U, E>, - ctx: &serenity::Context, + ctx: &serenity::Context, event: serenity::FullEvent, ) { match &event { @@ -123,7 +112,7 @@ pub async fn dispatch_event( .unwrap() .process_message_delete(*deleted_message_id); if let Some(bot_response) = bot_response { - if let Err(e) = bot_response.delete(ctx).await { + if let Err(e) = bot_response.delete(&ctx).await { tracing::warn!("failed to delete bot response: {}", e); } } @@ -170,14 +159,10 @@ pub async fn dispatch_event( _ => {} } - // Do this after the framework's Ready handling, so that get_user_data() doesnt - // potentially block infinitely - if let Err(error) = - (framework.options.event_handler)(ctx, &event, framework, framework.user_data).await - { + if let Err(error) = (framework.options.event_handler)(ctx, &event, framework).await { let error = crate::FrameworkError::EventHandler { - error, ctx, + error, event: &event, framework, }; diff --git a/src/dispatch/prefix.rs b/src/dispatch/prefix.rs index aba0177dfee2..ad309a156f62 100644 --- a/src/dispatch/prefix.rs +++ b/src/dispatch/prefix.rs @@ -5,9 +5,9 @@ use crate::serenity_prelude as serenity; /// Checks if this message is a bot invocation by attempting to strip the prefix /// /// Returns tuple of stripped prefix and rest of the message, if any prefix matches -async fn strip_prefix<'a, U, E>( +async fn strip_prefix<'a, U: Send + Sync + 'static, E>( framework: crate::FrameworkContext<'a, U, E>, - ctx: &'a serenity::Context, + ctx: &'a serenity::Context, msg: &'a serenity::Message, ) -> Option<(&'a str, &'a str)> { let partial_ctx = crate::PartialContext { @@ -16,7 +16,6 @@ async fn strip_prefix<'a, U, E>( author: &msg.author, serenity_context: ctx, framework, - data: framework.user_data, __non_exhaustive: (), }; @@ -68,7 +67,7 @@ async fn strip_prefix<'a, U, E>( } if let Some(dynamic_prefix) = framework.options.prefix_options.stripped_dynamic_prefix { - match dynamic_prefix(ctx, msg, framework.user_data).await { + match dynamic_prefix(ctx, msg).await { Ok(result) => { if let Some((prefix, content)) = result { return Some((prefix, content)); @@ -138,7 +137,7 @@ async fn strip_prefix<'a, U, E>( /// Some((&commands[1], "CoMmAnD2", "cOmMaNd99 my arguments")), /// ); /// assert!(parent_commands.is_empty()); -pub fn find_command<'a, U, E>( +pub fn find_command<'a, U: Send + Sync + 'static, E>( commands: &'a [crate::Command], remaining_message: &'a str, case_insensitive: bool, @@ -186,7 +185,7 @@ pub fn find_command<'a, U, E>( /// Manually dispatches a message with the prefix framework pub async fn dispatch_message<'a, U: Send + Sync, E>( framework: crate::FrameworkContext<'a, U, E>, - ctx: &'a serenity::Context, + ctx: &'a serenity::Context, msg: &'a serenity::Message, trigger: crate::MessageDispatchTrigger, invocation_data: &'a tokio::sync::Mutex>, @@ -216,7 +215,7 @@ pub async fn dispatch_message<'a, U: Send + Sync, E>( /// returns the resulting [`crate::PrefixContext`]. To run the command, see [`run_invocation`]. pub async fn parse_invocation<'a, U: Send + Sync, E>( framework: crate::FrameworkContext<'a, U, E>, - ctx: &'a serenity::Context, + ctx: &'a serenity::Context, msg: &'a serenity::Message, trigger: crate::MessageDispatchTrigger, invocation_data: &'a tokio::sync::Mutex>, @@ -276,7 +275,6 @@ pub async fn parse_invocation<'a, U: Send + Sync, E>( invoked_command_name, args, framework, - data: framework.user_data, parent_commands, command, invocation_data, @@ -288,7 +286,7 @@ pub async fn parse_invocation<'a, U: Send + Sync, E>( /// Given an existing parsed command invocation from [`parse_invocation`], run it, including all the /// before and after code like checks and built in filters from edit tracking -pub async fn run_invocation( +pub async fn run_invocation( ctx: crate::PrefixContext<'_, U, E>, ) -> Result<(), crate::FrameworkError<'_, U, E>> { // Check if we should disregard this invocation if it was triggered by an edit diff --git a/src/dispatch/slash.rs b/src/dispatch/slash.rs index dd20995f20be..c375b48a1be3 100644 --- a/src/dispatch/slash.rs +++ b/src/dispatch/slash.rs @@ -3,7 +3,7 @@ use crate::serenity_prelude as serenity; /// Check if the interaction with the given name and arguments matches any framework command -fn find_matching_command<'a, 'b, U, E>( +fn find_matching_command<'a, 'b, U: Send + Sync + 'static, E>( interaction_name: &str, interaction_options: &'b [serenity::ResolvedOption<'b>], commands: &'a [crate::Command], @@ -38,9 +38,9 @@ fn find_matching_command<'a, 'b, U, E>( /// After this, the [`crate::ApplicationContext`] should be passed into [`run_command`] or /// [`run_autocomplete`]. #[allow(clippy::too_many_arguments)] // We need to pass them all in to create Context. -fn extract_command<'a, U, E>( +fn extract_command<'a, U: Send + Sync + 'static, E>( framework: crate::FrameworkContext<'a, U, E>, - ctx: &'a serenity::Context, + ctx: &'a serenity::Context, interaction: &'a serenity::CommandInteraction, interaction_type: crate::CommandInteractionType, has_sent_initial_response: &'a std::sync::atomic::AtomicBool, @@ -62,7 +62,6 @@ fn extract_command<'a, U, E>( })?; Ok(crate::ApplicationContext { - data: framework.user_data, serenity_context: ctx, framework, interaction, @@ -78,9 +77,9 @@ fn extract_command<'a, U, E>( /// Given an interaction, finds the matching framework command and checks if the user is allowed access #[allow(clippy::too_many_arguments)] // We need to pass them all in to create Context. -pub async fn extract_command_and_run_checks<'a, U, E>( +pub async fn extract_command_and_run_checks<'a, U: Send + Sync + 'static, E>( framework: crate::FrameworkContext<'a, U, E>, - ctx: &'a serenity::Context, + ctx: &'a serenity::Context, interaction: &'a serenity::CommandInteraction, interaction_type: crate::CommandInteractionType, has_sent_initial_response: &'a std::sync::atomic::AtomicBool, @@ -104,7 +103,7 @@ pub async fn extract_command_and_run_checks<'a, U, E>( /// Given the extracted application command data from [`extract_command`], runs the command, /// including all the before and after code like checks. -async fn run_command( +async fn run_command( ctx: crate::ApplicationContext<'_, U, E>, ) -> Result<(), crate::FrameworkError<'_, U, E>> { super::common::check_permissions_and_cooldown(ctx.into()).await?; @@ -163,9 +162,9 @@ async fn run_command( } /// Dispatches this interaction onto framework commands, i.e. runs the associated command -pub async fn dispatch_interaction<'a, U, E>( +pub async fn dispatch_interaction<'a, U: Send + Sync + 'static, E>( framework: crate::FrameworkContext<'a, U, E>, - ctx: &'a serenity::Context, + ctx: &'a serenity::Context, interaction: &'a serenity::CommandInteraction, // Need to pass this in from outside because of lifetime issues has_sent_initial_response: &'a std::sync::atomic::AtomicBool, @@ -198,7 +197,7 @@ pub async fn dispatch_interaction<'a, U, E>( /// Given the extracted application command data from [`extract_command`], runs the autocomplete /// callbacks, including all the before and after code like checks. -async fn run_autocomplete( +async fn run_autocomplete( ctx: crate::ApplicationContext<'_, U, E>, ) -> Result<(), crate::FrameworkError<'_, U, E>> { super::common::check_permissions_and_cooldown(ctx.into()).await?; @@ -260,9 +259,9 @@ async fn run_autocomplete( /// Dispatches this interaction onto framework commands, i.e. runs the associated autocomplete /// callback -pub async fn dispatch_autocomplete<'a, U, E>( +pub async fn dispatch_autocomplete<'a, U: Send + Sync + 'static, E>( framework: crate::FrameworkContext<'a, U, E>, - ctx: &'a serenity::Context, + ctx: &'a serenity::Context, interaction: &'a serenity::CommandInteraction, // Need to pass the following in from outside because of lifetime issues has_sent_initial_response: &'a std::sync::atomic::AtomicBool, diff --git a/src/framework/builder.rs b/src/framework/builder.rs index 1dc388bed991..4eff26042e3e 100644 --- a/src/framework/builder.rs +++ b/src/framework/builder.rs @@ -8,17 +8,17 @@ use crate::BoxFuture; /// If one of the following required values is missing, the builder will panic on start: /// - [`Self::setup`] /// - [`Self::options`] -pub struct FrameworkBuilder { +pub struct FrameworkBuilder { /// Callback for startup code and user data creation setup: Option< Box< dyn Send + Sync + for<'a> FnOnce( - &'a serenity::Context, + &'a serenity::Context, &'a serenity::Ready, &'a crate::Framework, - ) -> BoxFuture<'a, Result>, + ) -> BoxFuture<'a, Result<(), E>>, >, >, /// Framework options @@ -29,7 +29,7 @@ pub struct FrameworkBuilder { initialize_owners: bool, } -impl Default for FrameworkBuilder { +impl Default for FrameworkBuilder { fn default() -> Self { Self { setup: Default::default(), @@ -40,7 +40,7 @@ impl Default for FrameworkBuilder { } } -impl FrameworkBuilder { +impl FrameworkBuilder { /// Sets the setup callback which also returns the user data struct. #[must_use] pub fn setup(mut self, setup: F) -> Self @@ -49,10 +49,10 @@ impl FrameworkBuilder { + Sync + 'static + for<'a> FnOnce( - &'a serenity::Context, + &'a serenity::Context, &'a serenity::Ready, &'a crate::Framework, - ) -> BoxFuture<'a, Result>, + ) -> BoxFuture<'a, Result<(), E>>, { self.setup = Some(Box::new(setup) as _); self diff --git a/src/framework/mod.rs b/src/framework/mod.rs index 2fbb4ee87d23..5c80b3a56ef1 100644 --- a/src/framework/mod.rs +++ b/src/framework/mod.rs @@ -18,9 +18,7 @@ mod builder; /// - keeps track of shard manager and bot ID automatically /// /// You can build a bot without [`Framework`]: see the `manual_dispatch` example in the repository -pub struct Framework { - /// Stores user data. Is initialized on first Ready event - user_data: std::sync::OnceLock, +pub struct Framework { /// Stores bot ID. Is initialized on first Ready event bot_id: std::sync::OnceLock, /// Stores the framework options @@ -35,10 +33,10 @@ pub struct Framework { dyn Send + Sync + for<'a> FnOnce( - &'a serenity::Context, + &'a serenity::Context, &'a serenity::Ready, &'a Self, - ) -> BoxFuture<'a, Result>, + ) -> BoxFuture<'a, Result<(), E>>, >, >, >, @@ -47,7 +45,7 @@ pub struct Framework { edit_tracker_purge_task: Option>, } -impl Framework { +impl Framework { /// Create a framework builder to configure, create and run a framework. /// /// For more information, see [`FrameworkBuilder`] @@ -75,15 +73,14 @@ impl Framework { + Sync + 'static + for<'a> FnOnce( - &'a serenity::Context, + &'a serenity::Context, &'a serenity::Ready, &'a Self, - ) -> BoxFuture<'a, Result>, + ) -> BoxFuture<'a, Result<(), E>>, U: Send + Sync + 'static, E: Send + 'static, { Self { - user_data: std::sync::OnceLock::new(), bot_id: std::sync::OnceLock::new(), setup: std::sync::Mutex::new(Some(Box::new(setup))), edit_tracker_purge_task: None, @@ -104,20 +101,9 @@ impl Framework { .as_ref() .expect("framework should have started") } - - /// Retrieves user data, or blocks until it has been initialized (once the Ready event has been - /// received). - pub async fn user_data(&self) -> &U { - loop { - match self.user_data.get() { - Some(x) => break x, - None => tokio::time::sleep(std::time::Duration::from_millis(100)).await, - } - } - } } -impl Drop for Framework { +impl Drop for Framework { fn drop(&mut self) { if let Some(task) = &mut self.edit_tracker_purge_task { task.abort() @@ -126,8 +112,8 @@ impl Drop for Framework { } #[serenity::async_trait] -impl serenity::Framework for Framework { - async fn init(&mut self, client: &serenity::Client) { +impl serenity::Framework for Framework { + async fn init(&mut self, client: &serenity::Client) { set_qualified_names(&mut self.options.commands); message_content_intent_sanity_check( @@ -149,7 +135,7 @@ impl serenity::Framework for Framework { } } - async fn dispatch(&self, ctx: serenity::Context, event: serenity::FullEvent) { + async fn dispatch(&self, ctx: serenity::Context, event: serenity::FullEvent) { raw_dispatch_event(self, ctx, event).await } } @@ -158,7 +144,7 @@ impl serenity::Framework for Framework { /// Otherwise, it forwards the event to [`crate::dispatch_event`] async fn raw_dispatch_event( framework: &Framework, - ctx: serenity::Context, + ctx: serenity::Context, event: serenity::FullEvent, ) where U: Send + Sync, @@ -167,19 +153,14 @@ async fn raw_dispatch_event( let _: Result<_, _> = framework.bot_id.set(data_about_bot.user.id); let setup = Option::take(&mut *framework.setup.lock().unwrap()); if let Some(setup) = setup { - match setup(&ctx, data_about_bot, framework).await { - Ok(user_data) => { - let _: Result<_, _> = framework.user_data.set(user_data); - } - Err(error) => { - (framework.options.on_error)(crate::FrameworkError::Setup { - error, - framework, - data_about_bot, - ctx: &ctx, - }) - .await - } + if let Err(error) = setup(&ctx, data_about_bot, framework).await { + (framework.options.on_error)(crate::FrameworkError::Setup { + error, + framework, + data_about_bot, + ctx: &ctx, + }) + .await } } else { // ignoring duplicate Discord bot ready event @@ -187,7 +168,6 @@ async fn raw_dispatch_event( } } - let user_data = framework.user_data().await; let bot_id = *framework .bot_id .get() @@ -195,16 +175,18 @@ async fn raw_dispatch_event( let framework = crate::FrameworkContext { bot_id, options: &framework.options, - user_data, shard_manager: framework.shard_manager(), }; crate::dispatch_event(framework, &ctx, event).await; } /// Traverses commands recursively and sets [`crate::Command::qualified_name`] to its actual value -pub fn set_qualified_names(commands: &mut [crate::Command]) { +pub fn set_qualified_names(commands: &mut [crate::Command]) { /// Fills in `qualified_name` fields by appending command name to the parent command name - fn set_subcommand_qualified_names(parents: &str, commands: &mut [crate::Command]) { + fn set_subcommand_qualified_names( + parents: &str, + commands: &mut [crate::Command], + ) { for cmd in commands { cmd.qualified_name = format!("{} {}", parents, cmd.name); set_subcommand_qualified_names(&cmd.qualified_name, &mut cmd.subcommands); @@ -216,7 +198,7 @@ pub fn set_qualified_names(commands: &mut [crate::Command]) { } /// Prints a warning on stderr if a prefix is configured but `MESSAGE_CONTENT` is not set -fn message_content_intent_sanity_check( +fn message_content_intent_sanity_check( prefix_options: &crate::PrefixFrameworkOptions, intents: serenity::GatewayIntents, ) { diff --git a/src/lib.rs b/src/lib.rs index 4701a17dcd54..67a445117e0f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -233,11 +233,6 @@ use poise::serenity_prelude as serenity; // Use `Framework::builder()` to create a framework builder and supply basic data to the framework: let framework = poise::Framework::builder() - .setup(|_, _, _| Box::pin(async move { - // construct user data here (invoked when bot connects to Discord) - Ok(()) - })) - // Most configuration is done via the `FrameworkOptions` struct, which you can define with // a struct literal (hint: use `..Default::default()` to fill uninitialized // settings with their default value): @@ -262,7 +257,7 @@ let framework = poise::Framework::builder() ..Default::default() }).build(); -let client = serenity::ClientBuilder::new("...", serenity::GatewayIntents::non_privileged()) +let client = serenity::ClientBuilder::new("...", serenity::GatewayIntents::non_privileged(), ()) .framework(framework).await; client.unwrap().start().await.unwrap(); diff --git a/src/modal.rs b/src/modal.rs index 7dd516c62697..0e82914154ba 100644 --- a/src/modal.rs +++ b/src/modal.rs @@ -42,9 +42,10 @@ pub fn find_modal_text( /// interaction async fn execute_modal_generic< M: Modal, + U: Send + Sync, F: std::future::Future>, >( - ctx: &serenity::Context, + ctx: &serenity::Context, create_interaction_response: impl FnOnce(serenity::CreateInteractionResponse) -> F, modal_custom_id: String, defaults: Option, @@ -119,8 +120,8 @@ pub async fn execute_modal( /// /// If you need more specialized behavior, you can copy paste the implementation of this function /// and adjust to your needs. The code of this function is just a starting point. -pub async fn execute_modal_on_component_interaction( - ctx: impl AsRef, +pub async fn execute_modal_on_component_interaction( + ctx: impl AsRef>, interaction: serenity::ModalInteraction, defaults: Option, timeout: Option, diff --git a/src/prefix_argument/argument_trait.rs b/src/prefix_argument/argument_trait.rs index d43f2959b2c5..8743dd88231a 100644 --- a/src/prefix_argument/argument_trait.rs +++ b/src/prefix_argument/argument_trait.rs @@ -34,10 +34,10 @@ pub trait PopArgument<'a>: Sized { /// If parsing fails because the string is empty, use the `TooFewArguments` type as the error. /// /// Don't call this method directly! Use [`crate::pop_prefix_argument!`] - async fn pop_from( + async fn pop_from( args: &'a str, attachment_index: usize, - ctx: &serenity::Context, + ctx: &serenity::Context, msg: &serenity::Message, ) -> Result<(&'a str, usize, Self), (Box, Option)>; } @@ -45,11 +45,11 @@ pub trait PopArgument<'a>: Sized { #[doc(hidden)] #[async_trait::async_trait] pub trait PopArgumentHack<'a, T>: Sized { - async fn pop_from( + async fn pop_from( self, args: &'a str, attachment_index: usize, - ctx: &serenity::Context, + ctx: &serenity::Context, msg: &serenity::Message, ) -> Result<(&'a str, usize, T), (Box, Option)>; } @@ -59,11 +59,11 @@ impl<'a, T: serenity::ArgumentConvert + Send> PopArgumentHack<'a, T> for Phantom where T::Err: std::error::Error + Send + Sync + 'static, { - async fn pop_from( + async fn pop_from( self, args: &'a str, attachment_index: usize, - ctx: &serenity::Context, + ctx: &serenity::Context, msg: &serenity::Message, ) -> Result<(&'a str, usize, T), (Box, Option)> { @@ -79,11 +79,11 @@ where #[async_trait::async_trait] impl<'a, T: PopArgument<'a> + Send + Sync> PopArgumentHack<'a, T> for &PhantomData { - async fn pop_from( + async fn pop_from( self, args: &'a str, attachment_index: usize, - ctx: &serenity::Context, + ctx: &serenity::Context, msg: &serenity::Message, ) -> Result<(&'a str, usize, T), (Box, Option)> { @@ -93,11 +93,11 @@ impl<'a, T: PopArgument<'a> + Send + Sync> PopArgumentHack<'a, T> for &PhantomDa #[async_trait::async_trait] impl<'a> PopArgumentHack<'a, bool> for &PhantomData { - async fn pop_from( + async fn pop_from( self, args: &'a str, attachment_index: usize, - ctx: &serenity::Context, + ctx: &serenity::Context, msg: &serenity::Message, ) -> Result<(&'a str, usize, bool), (Box, Option)> { @@ -116,11 +116,11 @@ impl<'a> PopArgumentHack<'a, bool> for &PhantomData { #[async_trait::async_trait] impl<'a> PopArgumentHack<'a, serenity::Attachment> for &PhantomData { - async fn pop_from( + async fn pop_from( self, args: &'a str, attachment_index: usize, - ctx: &serenity::Context, + ctx: &serenity::Context, msg: &serenity::Message, ) -> Result< (&'a str, usize, serenity::Attachment), diff --git a/src/prefix_argument/code_block.rs b/src/prefix_argument/code_block.rs index 81f1dc69d397..870e0261752f 100644 --- a/src/prefix_argument/code_block.rs +++ b/src/prefix_argument/code_block.rs @@ -114,10 +114,10 @@ impl<'a> PopArgument<'a> for CodeBlock { /// Parse a single-line or multi-line code block. The output of `Self::code` should mirror what /// the official Discord client renders, and the output of `Self::language` should mirror the /// official Discord client's syntax highlighting, if existent. - async fn pop_from( + async fn pop_from( args: &'a str, attachment_index: usize, - _: &serenity::Context, + _: &serenity::Context, _: &serenity::Message, ) -> Result<(&'a str, usize, Self), (Box, Option)> { diff --git a/src/prefix_argument/key_value_args.rs b/src/prefix_argument/key_value_args.rs index af54b8866eb9..b9b451358812 100644 --- a/src/prefix_argument/key_value_args.rs +++ b/src/prefix_argument/key_value_args.rs @@ -73,10 +73,10 @@ impl KeyValueArgs { #[async_trait::async_trait] impl<'a> PopArgument<'a> for KeyValueArgs { - async fn pop_from( + async fn pop_from( args: &'a str, attachment_index: usize, - _: &serenity::Context, + _: &serenity::Context, _: &serenity::Message, ) -> Result<(&'a str, usize, Self), (Box, Option)> { diff --git a/src/prefix_argument/macros.rs b/src/prefix_argument/macros.rs index 3a86d3884c4f..3f67b8cb61c4 100644 --- a/src/prefix_argument/macros.rs +++ b/src/prefix_argument/macros.rs @@ -179,9 +179,9 @@ to use this macro directly. # #[tokio::main] async fn main() -> Result<(), Box> { # use poise::serenity_prelude as serenity; # let ctx = serenity::Context { -# data: Default::default(), # shard: todo!(), # shard_id: todo!(), +# data: std::sync::Arc::new(()), # http: std::sync::Arc::new(::serenity::http::Http::new("example")), # #[cfg(feature = "cache")] # cache: Default::default(), diff --git a/src/reply/mod.rs b/src/reply/mod.rs index 23c6e2287519..9c7e919f4eb4 100644 --- a/src/reply/mod.rs +++ b/src/reply/mod.rs @@ -93,7 +93,7 @@ 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, U: Send + Sync + 'static, E>( &self, ctx: crate::Context<'_, U, E>, builder: CreateReply, @@ -139,7 +139,10 @@ impl ReplyHandle<'_> { } /// Deletes this message - pub async fn delete(&self, ctx: crate::Context<'_, U, E>) -> Result<(), serenity::Error> { + pub async fn delete( + &self, + ctx: crate::Context<'_, U, E>, + ) -> Result<(), serenity::Error> { match &self.0 { ReplyHandleInner::Prefix(msg) => msg.delete(ctx.serenity_context()).await?, ReplyHandleInner::Application { diff --git a/src/reply/send_reply.rs b/src/reply/send_reply.rs index 5308e825da69..a7c842b86cdb 100644 --- a/src/reply/send_reply.rs +++ b/src/reply/send_reply.rs @@ -23,7 +23,7 @@ use crate::serenity_prelude as serenity; /// ).await?; /// # Ok(()) } /// ``` -pub async fn send_reply( +pub async fn send_reply( ctx: crate::Context<'_, U, E>, builder: crate::CreateReply, ) -> Result, serenity::Error> { @@ -38,7 +38,7 @@ pub async fn send_reply( /// Shorthand of [`send_reply`] for text-only messages /// /// Note: panics when called in an autocomplete context! -pub async fn say_reply( +pub async fn say_reply( ctx: crate::Context<'_, U, E>, text: impl Into, ) -> Result, serenity::Error> { @@ -51,7 +51,7 @@ pub async fn say_reply( /// [followup](serenity::CommandInteraction::create_followup) is sent. /// /// No-op if autocomplete context -pub async fn send_application_reply( +pub async fn send_application_reply( ctx: crate::ApplicationContext<'_, U, E>, builder: crate::CreateReply, ) -> Result, serenity::Error> { @@ -98,7 +98,7 @@ pub async fn send_application_reply( } /// Prefix-specific reply function. For more details, see [`crate::send_reply`]. -pub async fn send_prefix_reply( +pub async fn send_prefix_reply( ctx: crate::PrefixContext<'_, U, E>, builder: crate::CreateReply, ) -> Result, serenity::Error> { diff --git a/src/slash_argument/context_menu.rs b/src/slash_argument/context_menu.rs index 0c2125ca32b0..99f1d7813e50 100644 --- a/src/slash_argument/context_menu.rs +++ b/src/slash_argument/context_menu.rs @@ -3,7 +3,7 @@ use crate::serenity_prelude as serenity; use crate::BoxFuture; /// Implemented for all types that can be used in a context menu command -pub trait ContextMenuParameter { +pub trait ContextMenuParameter { /// Convert an action function pointer that takes Self as an argument into the appropriate /// [`crate::ContextMenuCommandAction`] variant. fn to_action( @@ -14,7 +14,7 @@ pub trait ContextMenuParameter { ) -> crate::ContextMenuCommandAction; } -impl ContextMenuParameter for serenity::User { +impl ContextMenuParameter for serenity::User { fn to_action( action: fn( crate::ApplicationContext<'_, U, E>, @@ -25,7 +25,7 @@ impl ContextMenuParameter for serenity::User { } } -impl ContextMenuParameter for serenity::Message { +impl ContextMenuParameter for serenity::Message { fn to_action( action: fn( crate::ApplicationContext<'_, U, E>, diff --git a/src/slash_argument/slash_macro.rs b/src/slash_argument/slash_macro.rs index 15c419f81b7d..8588283fe8ad 100644 --- a/src/slash_argument/slash_macro.rs +++ b/src/slash_argument/slash_macro.rs @@ -108,7 +108,7 @@ directly. ```rust,no_run # #[tokio::main] async fn main() -> Result<(), Box> { # use poise::serenity_prelude as serenity; -let ctx: serenity::Context = todo!(); +let ctx: serenity::Context<()> = todo!(); let interaction: serenity::CommandInteraction = todo!(); let args: &[serenity::ResolvedOption] = todo!(); diff --git a/src/slash_argument/slash_trait.rs b/src/slash_argument/slash_trait.rs index a7bcb1bd8e4f..7cdbca189dd7 100644 --- a/src/slash_argument/slash_trait.rs +++ b/src/slash_argument/slash_trait.rs @@ -15,8 +15,8 @@ pub trait SlashArgument: Sized { /// [`serenity::json::Value`]. /// /// Don't call this method directly! Use [`crate::extract_slash_argument!`] - async fn extract( - ctx: &serenity::Context, + async fn extract( + ctx: &serenity::Context, interaction: &serenity::CommandInteraction, value: &serenity::ResolvedValue<'_>, ) -> Result; @@ -44,9 +44,9 @@ pub trait SlashArgument: Sized { #[doc(hidden)] #[async_trait::async_trait] pub trait SlashArgumentHack: Sized { - async fn extract( + async fn extract( self, - ctx: &serenity::Context, + ctx: &serenity::Context, interaction: &serenity::CommandInteraction, value: &serenity::ResolvedValue<'_>, ) -> Result; @@ -96,9 +96,9 @@ where T: serenity::ArgumentConvert + Send + Sync, T::Err: std::error::Error + Send + Sync + 'static, { - async fn extract( + async fn extract( self, - ctx: &serenity::Context, + ctx: &serenity::Context, interaction: &serenity::CommandInteraction, value: &serenity::ResolvedValue<'_>, ) -> Result { @@ -134,8 +134,8 @@ macro_rules! impl_for_integer { ($($t:ty)*) => { $( #[async_trait::async_trait] impl SlashArgument for $t { - async fn extract( - _: &serenity::Context, + async fn extract( + _: &serenity::Context, _: &serenity::CommandInteraction, value: &serenity::ResolvedValue<'_>, ) -> Result<$t, SlashArgError> { @@ -165,9 +165,9 @@ macro_rules! impl_for_float { ($($t:ty)*) => { $( #[async_trait::async_trait] impl SlashArgumentHack<$t> for &PhantomData<$t> { - async fn extract( + async fn extract( self, - _: &serenity::Context, + _: &serenity::Context, _: &serenity::CommandInteraction, value: &serenity::ResolvedValue<'_>, ) -> Result<$t, SlashArgError> { @@ -187,9 +187,9 @@ impl_for_float!(f32 f64); #[async_trait::async_trait] impl SlashArgumentHack for &PhantomData { - async fn extract( + async fn extract( self, - _: &serenity::Context, + _: &serenity::Context, _: &serenity::CommandInteraction, value: &serenity::ResolvedValue<'_>, ) -> Result { @@ -208,9 +208,9 @@ impl SlashArgumentHack for &PhantomData { #[async_trait::async_trait] impl SlashArgumentHack for &PhantomData { - async fn extract( + async fn extract( self, - _: &serenity::Context, + _: &serenity::Context, interaction: &serenity::CommandInteraction, value: &serenity::ResolvedValue<'_>, ) -> Result { @@ -246,9 +246,9 @@ impl SlashArgumentHack for &PhantomData SlashArgumentHack for &PhantomData { - async fn extract( + async fn extract( self, - ctx: &serenity::Context, + ctx: &serenity::Context, interaction: &serenity::CommandInteraction, value: &serenity::ResolvedValue<'_>, ) -> Result { @@ -269,8 +269,8 @@ macro_rules! impl_slash_argument { ($type:ty, $slash_param_type:ident) => { #[async_trait::async_trait] impl SlashArgument for $type { - async fn extract( - ctx: &serenity::Context, + async fn extract( + ctx: &serenity::Context, interaction: &serenity::CommandInteraction, value: &serenity::ResolvedValue<'_>, ) -> Result<$type, SlashArgError> { diff --git a/src/structs/command.rs b/src/structs/command.rs index 453a4840151f..e5f86f4e24f2 100644 --- a/src/structs/command.rs +++ b/src/structs/command.rs @@ -6,7 +6,7 @@ use crate::{serenity_prelude as serenity, BoxFuture}; /// prefix and application commands #[derive(derivative::Derivative)] #[derivative(Default(bound = ""), Debug(bound = ""))] -pub struct Command { +pub struct Command { // ============= /// Callback to execute when this command is invoked in a prefix context #[derivative(Debug = "ignore")] @@ -128,14 +128,14 @@ pub struct Command { pub __non_exhaustive: (), } -impl PartialEq for Command { +impl PartialEq for Command { fn eq(&self, other: &Self) -> bool { std::ptr::eq(self, other) } } -impl Eq for Command {} +impl Eq for Command {} -impl 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 { diff --git a/src/structs/context.rs b/src/structs/context.rs index d38a071970cc..9712652249f8 100644 --- a/src/structs/context.rs +++ b/src/structs/context.rs @@ -10,32 +10,34 @@ pub trait _GetGenerics { type U; type E; } -impl _GetGenerics for Context<'_, U, E> { +impl _GetGenerics for Context<'_, U, E> { type U = U; type E = E; } /// Wrapper around either [`crate::ApplicationContext`] or [`crate::PrefixContext`] #[derive(Debug)] -pub enum Context<'a, U, E> { +pub enum Context<'a, U: Send + Sync + 'static, E> { /// Application command context Application(crate::ApplicationContext<'a, U, E>), /// Prefix command context Prefix(crate::PrefixContext<'a, U, E>), // Not non_exhaustive.. adding a whole new category of commands would justify breakage lol } -impl Clone for Context<'_, U, E> { +impl Clone for Context<'_, U, E> { fn clone(&self) -> Self { *self } } -impl Copy for Context<'_, U, E> {} -impl<'a, U, E> From> for Context<'a, U, E> { +impl Copy for Context<'_, U, E> {} +impl<'a, U: Send + Sync + 'static, E> From> + for Context<'a, U, E> +{ fn from(x: crate::ApplicationContext<'a, U, E>) -> Self { Self::Application(x) } } -impl<'a, U, E> From> for Context<'a, U, E> { +impl<'a, U: Send + Sync + 'static, E> From> for Context<'a, U, E> { fn from(x: crate::PrefixContext<'a, U, E>) -> Self { Self::Prefix(x) } @@ -50,19 +52,19 @@ macro_rules! context_methods { $($await:ident)? ( $fn_name:ident $self:ident $($arg:ident)* ) ( $($sig:tt)* ) $body:block )* ) => { - impl<'a, U, E> Context<'a, U, E> { $( + impl<'a, U: Send + Sync + 'static, E> Context<'a, U, E> { $( $( #[$($attrs)*] )* $($sig)* $body )* } - impl<'a, U, E> crate::PrefixContext<'a, U, E> { $( + impl<'a, U: Send + Sync + 'static, E> crate::PrefixContext<'a, U, E> { $( $( #[$($attrs)*] )* $($sig)* { $crate::Context::Prefix($self).$fn_name($($arg)*) $(.$await)? } )* } - impl<'a, U, E> crate::ApplicationContext<'a, U, E> { $( + impl<'a, U: Send + Sync + 'static, E> crate::ApplicationContext<'a, U, E> { $( $( #[$($attrs)*] )* $($sig)* { $crate::Context::Application($self).$fn_name($($arg)*) $(.$await)? @@ -162,7 +164,7 @@ context_methods! { /// Return the stored [`serenity::Context`] within the underlying context type. (serenity_context self) - (pub fn serenity_context(self) -> &'a serenity::Context) { + (pub fn serenity_context(self) -> &'a serenity::Context) { match self { Self::Application(ctx) => ctx.serenity_context, Self::Prefix(ctx) => ctx.serenity_context, @@ -183,7 +185,7 @@ context_methods! { #[deprecated = "poise::Context can now be passed directly into most serenity functions. Otherwise, use `.serenity_context()` now"] #[allow(deprecated)] (discord self) - (pub fn discord(self) -> &'a serenity::Context) { + (pub fn discord(self) -> &'a serenity::Context) { self.serenity_context() } @@ -199,10 +201,7 @@ context_methods! { /// Return a reference to your custom user data (data self) (pub fn data(self) -> &'a U) { - match self { - Self::Application(ctx) => ctx.data, - Self::Prefix(ctx) => ctx.data, - } + &self.serenity_context().data } /// Return the channel ID of this context @@ -535,7 +534,7 @@ context_methods! { } } -impl<'a, U, E> Context<'a, U, E> { +impl<'a, U: Send + Sync + 'static, E> Context<'a, U, E> { /// Actual implementation of rerun() that returns `FrameworkError` for implementation convenience async fn rerun_inner(self) -> Result<(), crate::FrameworkError<'a, U, E>> { match self { @@ -605,29 +604,29 @@ impl<'a, U, E> Context<'a, U, E> { macro_rules! context_trait_impls { ($($type:tt)*) => { #[cfg(feature = "cache")] - impl AsRef for $($type)*<'_, U, E> { + impl AsRef for $($type)*<'_, U, E> { fn as_ref(&self) -> &serenity::Cache { &self.serenity_context().cache } } - impl AsRef for $($type)*<'_, U, E> { + impl AsRef for $($type)*<'_, U, E> { fn as_ref(&self) -> &serenity::Http { &self.serenity_context().http } } - impl AsRef for $($type)*<'_, U, E> { + impl AsRef for $($type)*<'_, U, E> { fn as_ref(&self) -> &serenity::ShardMessenger { &self.serenity_context().shard } } // Originally added as part of component interaction modals; not sure if this impl is really // required by anything else... It makes sense to have though imo - impl AsRef for $($type)*<'_, U, E> { - fn as_ref(&self) -> &serenity::Context { + impl AsRef> for $($type)*<'_, U, E> { + fn as_ref(&self) -> &serenity::Context { self.serenity_context() } } - impl serenity::CacheHttp for $($type)*<'_, U, E> { + impl serenity::CacheHttp for $($type)*<'_, U, E> { fn http(&self) -> &serenity::Http { &self.serenity_context().http } @@ -644,7 +643,7 @@ context_trait_impls!(crate::ApplicationContext); context_trait_impls!(crate::PrefixContext); /// Trimmed down, more general version of [`Context`] -pub struct PartialContext<'a, U, E> { +pub struct PartialContext<'a, U: Send + Sync + 'static, E> { /// ID of the guild, if not invoked in DMs pub guild_id: Option, /// ID of the invocation channel @@ -652,24 +651,21 @@ pub struct PartialContext<'a, U, E> { /// ID of the invocation author pub author: &'a serenity::User, /// Serenity's context, like HTTP or cache - pub serenity_context: &'a serenity::Context, + pub serenity_context: &'a serenity::Context, /// Useful if you need the list of commands, for example for a custom help command pub framework: crate::FrameworkContext<'a, U, E>, - /// Your custom user data - // TODO: redundant with framework - pub data: &'a U, #[doc(hidden)] pub __non_exhaustive: (), } -impl Copy for PartialContext<'_, U, E> {} -impl Clone for PartialContext<'_, U, E> { +impl Copy for PartialContext<'_, U, E> {} +impl Clone for PartialContext<'_, U, E> { fn clone(&self) -> Self { *self } } -impl<'a, U, E> From> for PartialContext<'a, U, E> { +impl<'a, U: Send + Sync + 'static, E> From> for PartialContext<'a, U, E> { fn from(ctx: Context<'a, U, E>) -> Self { Self { guild_id: ctx.guild_id(), @@ -677,7 +673,6 @@ impl<'a, U, E> From> for PartialContext<'a, U, E> { author: ctx.author(), serenity_context: ctx.serenity_context(), framework: ctx.framework(), - data: ctx.data(), __non_exhaustive: (), } } diff --git a/src/structs/framework_error.rs b/src/structs/framework_error.rs index 24c07b9f752f..ca0b36ab9523 100644 --- a/src/structs/framework_error.rs +++ b/src/structs/framework_error.rs @@ -8,7 +8,7 @@ use crate::serenity_prelude as serenity; /// These errors are handled with the [`crate::FrameworkOptions::on_error`] callback #[derive(derivative::Derivative)] #[derivative(Debug)] -pub enum FrameworkError<'a, U, E> { +pub enum FrameworkError<'a, U: Send + Sync + 'static, E> { /// User code threw an error in user data setup #[non_exhaustive] Setup { @@ -21,7 +21,7 @@ pub enum FrameworkError<'a, U, E> { data_about_bot: &'a serenity::Ready, /// The serenity Context passed to the event #[derivative(Debug = "ignore")] - ctx: &'a serenity::Context, + ctx: &'a serenity::Context, }, /// User code threw an error in generic event event handler #[non_exhaustive] @@ -29,7 +29,7 @@ pub enum FrameworkError<'a, U, E> { /// Error which was thrown in the event handler code error: E, /// The serenity context passed to the event handler - ctx: &'a serenity::Context, + ctx: &'a serenity::Context, /// Which event was being processed when the error occurred event: &'a serenity::FullEvent, /// The Framework passed to the event @@ -166,7 +166,7 @@ pub enum FrameworkError<'a, U, E> { UnknownCommand { /// Serenity's Context #[derivative(Debug = "ignore")] - ctx: &'a serenity::Context, + ctx: &'a serenity::Context, /// The message in question msg: &'a serenity::Message, /// The prefix that was recognized @@ -189,7 +189,7 @@ pub enum FrameworkError<'a, U, E> { UnknownInteraction { #[derivative(Debug = "ignore")] /// Serenity's Context - ctx: &'a serenity::Context, + ctx: &'a serenity::Context, /// Framework context #[derivative(Debug = "ignore")] framework: crate::FrameworkContext<'a, U, E>, @@ -201,9 +201,9 @@ pub enum FrameworkError<'a, U, E> { __NonExhaustive(std::convert::Infallible), } -impl<'a, U, E> FrameworkError<'a, U, E> { +impl<'a, U: Send + Sync + 'static, E> FrameworkError<'a, U, E> { /// Returns the [`serenity::Context`] of this error - pub fn serenity_context(&self) -> &'a serenity::Context { + pub fn serenity_context(&self) -> &'a serenity::Context { match *self { Self::Setup { ctx, .. } => ctx, Self::EventHandler { ctx, .. } => ctx, @@ -264,7 +264,7 @@ impl<'a, U, E> FrameworkError<'a, U, E> { /// Support functions for the macro, which can't create these #[non_exhaustive] enum variants #[doc(hidden)] -impl<'a, U, E> FrameworkError<'a, U, E> { +impl<'a, U: Send + Sync + 'static, E> FrameworkError<'a, U, E> { pub fn new_command(ctx: crate::Context<'a, U, E>, error: E) -> Self { Self::Command { error, ctx } } @@ -292,7 +292,9 @@ macro_rules! full_command_name { }; } -impl std::fmt::Display for FrameworkError<'_, U, E> { +impl std::fmt::Display + for FrameworkError<'_, U, E> +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Setup { @@ -409,8 +411,10 @@ impl std::fmt::Display for FrameworkError<'_, U, E> { } } -impl<'a, U: std::fmt::Debug, E: std::error::Error + 'static> std::error::Error - for FrameworkError<'a, U, E> +impl<'a, U: Send + Sync + 'static, E> std::error::Error for FrameworkError<'a, U, E> +where + U: std::fmt::Debug + Send + Sync + 'static, + E: std::error::Error + 'static, { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { diff --git a/src/structs/framework_options.rs b/src/structs/framework_options.rs index 3ec310e9c3c5..49ba837a674c 100644 --- a/src/structs/framework_options.rs +++ b/src/structs/framework_options.rs @@ -5,7 +5,7 @@ use crate::{serenity_prelude as serenity, BoxFuture}; /// Framework configuration #[derive(derivative::Derivative)] #[derivative(Debug(bound = ""))] -pub struct FrameworkOptions { +pub struct FrameworkOptions { /// List of commands in the framework pub commands: Vec>, /// Provide a callback to be invoked when any user code yields an error. @@ -49,11 +49,9 @@ pub struct FrameworkOptions { /// deletions or guild updates. #[derivative(Debug = "ignore")] pub event_handler: for<'a> fn( - &'a serenity::Context, + &'a serenity::Context, &'a serenity::FullEvent, crate::FrameworkContext<'a, U, E>, - // TODO: redundant with framework - &'a U, ) -> BoxFuture<'a, Result<(), E>>, /// Renamed to [`Self::event_handler`]! #[deprecated = "renamed to event_handler"] @@ -72,7 +70,7 @@ pub struct FrameworkOptions { pub __non_exhaustive: (), } -impl FrameworkOptions { +impl FrameworkOptions { /// Add a new command to the framework #[deprecated = "supply commands in FrameworkOptions directly with `commands: vec![...]`"] pub fn command( @@ -85,7 +83,7 @@ impl FrameworkOptions { } } -impl Default for FrameworkOptions +impl Default for FrameworkOptions where U: Send + Sync, E: std::fmt::Display + std::fmt::Debug + Send, @@ -101,7 +99,7 @@ where } }) }, - event_handler: |_, _, _, _| Box::pin(async { Ok(()) }), + event_handler: |_, _, _| Box::pin(async { Ok(()) }), listener: (), pre_command: |_| Box::pin(async {}), post_command: |_| Box::pin(async {}), diff --git a/src/structs/prefix.rs b/src/structs/prefix.rs index f80561a1e4e2..48edb4d66e4a 100644 --- a/src/structs/prefix.rs +++ b/src/structs/prefix.rs @@ -21,10 +21,10 @@ pub enum MessageDispatchTrigger { /// Contains the trigger message, the Discord connection management stuff, and the user data. #[derive(derivative::Derivative)] #[derivative(Debug(bound = ""))] -pub struct PrefixContext<'a, U, E> { +pub struct PrefixContext<'a, U: Send + Sync + 'static, E> { /// Serenity's context, like HTTP or cache #[derivative(Debug = "ignore")] - pub serenity_context: &'a serenity::Context, + pub serenity_context: &'a serenity::Context, /// The invoking user message pub msg: &'a serenity::Message, /// Prefix used by the user to invoke this command @@ -42,10 +42,6 @@ pub struct PrefixContext<'a, U, E> { pub parent_commands: &'a [&'a crate::Command], /// The command object which is the current command pub command: &'a crate::Command, - /// Your custom user data - // TODO: redundant with framework - #[derivative(Debug = "ignore")] - pub data: &'a U, /// Custom user data carried across a single command invocation pub invocation_data: &'a tokio::sync::Mutex>, /// How this command invocation was triggered @@ -61,13 +57,13 @@ pub struct PrefixContext<'a, U, E> { pub __non_exhaustive: (), } // manual Copy+Clone implementations because Rust is getting confused about the type parameter -impl Clone for PrefixContext<'_, U, E> { +impl Clone for PrefixContext<'_, U, E> { fn clone(&self) -> Self { *self } } -impl Copy for PrefixContext<'_, U, E> {} -impl crate::_GetGenerics for PrefixContext<'_, U, E> { +impl Copy for PrefixContext<'_, U, E> {} +impl crate::_GetGenerics for PrefixContext<'_, U, E> { type U = U; type E = E; } @@ -86,7 +82,7 @@ pub enum Prefix { /// Prefix-specific framework configuration #[derive(derivative::Derivative)] #[derivative(Debug(bound = ""))] -pub struct PrefixFrameworkOptions { +pub struct PrefixFrameworkOptions { /// The main bot prefix. Can be set to None if the bot supports only /// [dynamic prefixes](Self::dynamic_prefix). pub prefix: Option, @@ -108,7 +104,7 @@ pub struct PrefixFrameworkOptions { /// /// Return value is a tuple of the prefix and the rest of the message: /// ```rust,no_run - /// # poise::PrefixFrameworkOptions::<(), ()> { stripped_dynamic_prefix: Some(|_, msg, _| Box::pin(async move { + /// # poise::PrefixFrameworkOptions::<(), ()> { stripped_dynamic_prefix: Some(|_, msg| Box::pin(async move { /// let my_cool_prefix = "$"; /// if msg.content.starts_with(my_cool_prefix) { /// return Ok(Some(msg.content.split_at(my_cool_prefix.len()))); @@ -119,9 +115,8 @@ pub struct PrefixFrameworkOptions { #[derivative(Debug = "ignore")] pub stripped_dynamic_prefix: Option< for<'a> fn( - &'a serenity::Context, + &'a serenity::Context, &'a serenity::Message, - &'a U, ) -> BoxFuture<'a, Result, E>>, >, /// Treat a bot mention (a ping) like a prefix @@ -166,7 +161,7 @@ pub struct PrefixFrameworkOptions { pub __non_exhaustive: (), } -impl Default for PrefixFrameworkOptions { +impl Default for PrefixFrameworkOptions { fn default() -> Self { Self { prefix: None, diff --git a/src/structs/slash.rs b/src/structs/slash.rs index 9419bc923437..a13b89bcf8a1 100644 --- a/src/structs/slash.rs +++ b/src/structs/slash.rs @@ -14,10 +14,10 @@ pub enum CommandInteractionType { /// Application command specific context passed to command invocations. #[derive(derivative::Derivative)] #[derivative(Debug(bound = ""))] -pub struct ApplicationContext<'a, U, E> { +pub struct ApplicationContext<'a, U: Send + Sync + 'static, E> { /// Serenity's context, like HTTP or cache #[derivative(Debug = "ignore")] - pub serenity_context: &'a serenity::Context, + pub serenity_context: &'a serenity::Context, /// The interaction which triggered this command execution. pub interaction: &'a serenity::CommandInteraction, /// The type of the interaction which triggered this command execution. @@ -41,28 +41,24 @@ pub struct ApplicationContext<'a, U, E> { pub parent_commands: &'a [&'a crate::Command], /// The command object which is the current command pub command: &'a crate::Command, - /// Your custom user data - // TODO: redundant with framework - #[derivative(Debug = "ignore")] - pub data: &'a U, /// Custom user data carried across a single command invocation pub invocation_data: &'a tokio::sync::Mutex>, // #[non_exhaustive] forbids struct update syntax for ?? reason #[doc(hidden)] pub __non_exhaustive: (), } -impl Clone for ApplicationContext<'_, U, E> { +impl Clone for ApplicationContext<'_, U, E> { fn clone(&self) -> Self { *self } } -impl Copy for ApplicationContext<'_, U, E> {} -impl crate::_GetGenerics for ApplicationContext<'_, U, E> { +impl Copy for ApplicationContext<'_, U, E> {} +impl crate::_GetGenerics for ApplicationContext<'_, U, E> { type U = U; type E = E; } -impl ApplicationContext<'_, U, E> { +impl ApplicationContext<'_, U, E> { /// See [`crate::Context::defer()`] pub async fn defer_response(&self, ephemeral: bool) -> Result<(), serenity::Error> { if !self @@ -87,7 +83,7 @@ impl ApplicationContext<'_, U, E> { /// Possible actions that a context menu entry can have #[derive(derivative::Derivative)] #[derivative(Debug(bound = ""))] -pub enum ContextMenuCommandAction { +pub enum ContextMenuCommandAction { /// Context menu entry on a user User( #[derivative(Debug = "ignore")] @@ -107,8 +103,8 @@ pub enum ContextMenuCommandAction { #[doc(hidden)] __NonExhaustive, } -impl Copy for ContextMenuCommandAction {} -impl Clone for ContextMenuCommandAction { +impl Copy for ContextMenuCommandAction {} +impl Clone for ContextMenuCommandAction { fn clone(&self) -> Self { *self } @@ -128,7 +124,7 @@ pub struct CommandParameterChoice { /// A single parameter of a [`crate::Command`] #[derive(Clone, derivative::Derivative)] #[derivative(Debug(bound = ""))] -pub struct CommandParameter { +pub struct CommandParameter { /// Name of this command parameter pub name: String, /// Localized names with locale string as the key (slash-only) @@ -173,7 +169,7 @@ pub struct CommandParameter { pub __non_exhaustive: (), } -impl 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 {