diff --git a/Cargo.lock b/Cargo.lock index 889762b..26d9458 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -228,9 +228,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "camino" @@ -266,9 +266,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.19" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" dependencies = [ "jobserver", "libc", @@ -893,18 +893,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "getset" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f636605b743120a8d32ed92fc27b6cde1a769f8f936c065151eb66f88ded513c" -dependencies = [ - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.77", -] - [[package]] name = "gif" version = "0.13.1" @@ -1691,9 +1679,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oneshot" @@ -1935,28 +1923,6 @@ dependencies = [ "toml_edit", ] -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.77", -] - [[package]] name = "proc-macro2" version = "1.0.86" @@ -2853,15 +2819,15 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.30.13" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3" +checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be" dependencies = [ - "cfg-if", "core-foundation-sys", "libc", + "memchr", "ntapi", - "once_cell", + "rayon", "windows", ] @@ -3141,9 +3107,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" dependencies = [ "indexmap", "serde", @@ -3464,9 +3430,9 @@ checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] @@ -3547,14 +3513,13 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vergen" -version = "9.0.0" +version = "9.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c32e7318e93a9ac53693b6caccfb05ff22e04a44c7cf8a279051f24c09da286f" +checksum = "349ed9e45296a581f455bc18039878f409992999bc1d5da12a6800eb18c8752f" dependencies = [ "anyhow", "cargo_metadata", "derive_builder", - "getset", "regex", "rustc_version", "rustversion", @@ -3565,9 +3530,9 @@ dependencies = [ [[package]] name = "vergen-git2" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62c52cd2b2b8b7ec75fc20111b3022ac3ff83e4fc14b9497cfcfd39c54f9c67" +checksum = "e771aff771c0d7c2f42e434e2766d304d917e29b40f0424e8faaaa936bbc3f29" dependencies = [ "anyhow", "derive_builder", @@ -3580,13 +3545,12 @@ dependencies = [ [[package]] name = "vergen-lib" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e06bee42361e43b60f363bad49d63798d0f42fb1768091812270eca00c784720" +checksum = "229eaddb0050920816cf051e619affaf18caa3dd512de8de5839ccbc8e53abb0" dependencies = [ "anyhow", "derive_builder", - "getset", "rustversion", ] @@ -3743,9 +3707,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.52.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" dependencies = [ "windows-core", "windows-targets 0.52.6", @@ -3753,24 +3717,58 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.52.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ + "windows-implement", + "windows-interface", + "windows-result 0.1.2", "windows-targets 0.52.6", ] +[[package]] +name = "windows-implement" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "windows-interface" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "windows-registry" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-strings", "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-result" version = "0.2.0" @@ -3786,7 +3784,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-targets 0.52.6", ] diff --git a/flake.lock b/flake.lock index 95839db..400c364 100644 --- a/flake.lock +++ b/flake.lock @@ -77,11 +77,11 @@ "pre-commit-hooks": "pre-commit-hooks_2" }, "locked": { - "lastModified": 1726417371, - "narHash": "sha256-tBq8w81ZV48tyFhLz5WQjqfoEShIXkOb6Rlzidcz8yQ=", + "lastModified": 1726671107, + "narHash": "sha256-XxQbcOSjvHsEC1hqZ5WU0aXtuomSikJnBCt38Qhk4b8=", "owner": "cachix", "repo": "devenv", - "rev": "1f55f89ca32d617b7a7c18422e3c364cb003df3d", + "rev": "5cac85ca427b5461a657472ffc4d15d0a61a5ef2", "type": "github" }, "original": { @@ -167,11 +167,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1726381916, - "narHash": "sha256-/ybEGP0EyalM6UNe8hnx/SqcGtey+UMtKKOy1sCpX7I=", + "lastModified": 1726641202, + "narHash": "sha256-NrSmOWnr0bIudOLwXd7UwspaHCGwVp8F0jed+nleWpI=", "owner": "nix-community", "repo": "fenix", - "rev": "3ade5be29c0ed4f5aeb93d9293a2b5bad62f1d1c", + "rev": "59e6cc52c6242800bb448c5a2b6427bd949385ad", "type": "github" }, "original": { @@ -647,11 +647,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1726220668, - "narHash": "sha256-0Cb2bK2eyZ1njSX3593USMlcrj94VZprNN1/HllIfgw=", + "lastModified": 1726443025, + "narHash": "sha256-nCmG4NJpwI0IoIlYlwtDwVA49yuspA2E6OhfCOmiArQ=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "4221354a8fe90ea8218d3757d14735eac08d3e81", + "rev": "94b526fc86eaa0e90fb4d54a5ba6313aa1e9b269", "type": "github" }, "original": { diff --git a/lyra/Cargo.toml b/lyra/Cargo.toml index 20ac5b8..670bab1 100644 --- a/lyra/Cargo.toml +++ b/lyra/Cargo.toml @@ -11,7 +11,7 @@ build = "build.rs" [build-dependencies] anyhow = "1" -vergen-git2 = { version = "1.0.0", features = [ +vergen-git2 = { version = "1.0.1", features = [ "build", "cargo", "rustc", diff --git a/lyra/src/command/declare.rs b/lyra/src/command/declare.rs index 733f06f..aed0099 100644 --- a/lyra/src/command/declare.rs +++ b/lyra/src/command/declare.rs @@ -1,5 +1,7 @@ use std::{ collections::HashMap, + future::Future, + pin::Pin, sync::{LazyLock, OnceLock}, }; @@ -11,7 +13,7 @@ use twilight_model::application::{ use crate::{ command::{ check, - model::{BotAutocomplete, BotMessageCommand, BotSlashCommand, CommandInfoAware}, + model::{BotAutocomplete, BotMessageCommand, BotSlashCommand}, AutocompleteCtx, MessageCtx, SlashCtx, }, component::{ @@ -35,6 +37,7 @@ macro_rules! count { macro_rules! declare_slash_commands { ($( $raw_cmd: ident ),* $(,)? ) => { + const SLASH_COMMANDS_N: usize = count!($($raw_cmd)*); ::paste::paste! { struct SlashCommandMap { $([<_ $raw_cmd:snake>]: Command,)* @@ -49,40 +52,40 @@ macro_rules! declare_slash_commands { } }); - type SlashCommands = [Command; count!($($raw_cmd)*)]; + type SlashCommands = [Command; SLASH_COMMANDS_N]; - pub static SLASH_COMMANDS: LazyLock = LazyLock::new(|| { + #[inline] + fn slash_commands() -> SlashCommands { ::paste::paste! { - [$(SLASH_COMMANDS_MAP.[<_ $raw_cmd:snake>].clone(),)*] + [ $( SLASH_COMMANDS_MAP.[<_ $raw_cmd:snake>].clone(), )* ] } - }); - - pub static POPULATED_COMMANDS_MAP: OnceLock> = OnceLock::new(); + } - $( - impl CommandInfoAware for $raw_cmd { - fn name() -> &'static str { - ::paste::paste! { - &SLASH_COMMANDS_MAP.[<_ $raw_cmd:snake>].name + // using a hashmap should significantly improve command respond times + type Callback = &'static (dyn Fn(SlashCtx, CommandData) -> + Pin> + Send>> + Send + Sync); + static SLASH_COMMANDS_CALLBACK: LazyLock> = LazyLock::new(|| { + HashMap::from( + ::paste::paste! {[$({ + #[lavalink_rs::hook] + async fn callback(ctx: SlashCtx, data: CommandData) -> Result<(), CommandExecuteError> { + Ok(<$raw_cmd>::from_interaction(data.into())?.run(ctx).await?) } - } - } - )* + + ($raw_cmd::NAME, &callback as Callback) + },)*]} + ) + }); impl SlashCtx { pub async fn execute(self, data: CommandData) -> Result<(), CommandExecuteError> { check::user_allowed_in(&self).await?; - match data.name { - $( - ref n if n == <$raw_cmd>::name() => { - return Ok(<$raw_cmd>::from_interaction(data.into())?.run(self).await?); - } - )* - _ => { - let cmd_data = self.into_command_data(); - return Err(CommandExecuteError::UnknownCommand(cmd_data)) - } + if let Some(callback) = SLASH_COMMANDS_CALLBACK.get(&*data.name) { + Ok(callback(self, data).await?) + } else { + let cmd_data = self.into_command_data(); + return Err(CommandExecuteError::UnknownCommand(cmd_data)) } } } @@ -91,6 +94,7 @@ macro_rules! declare_slash_commands { macro_rules! declare_message_commands { ($( $raw_cmd: ident ),* $(,)? ) => { + const MESSAGE_COMMANDS_N: usize = count!($($raw_cmd)*); ::paste::paste! { struct MessageCommandMap { $([<_ $raw_cmd:snake>]: Command,)* @@ -105,31 +109,23 @@ macro_rules! declare_message_commands { } }); - type MessageCommands = [Command; count!($($raw_cmd)*)]; + type MessageCommands = [Command; MESSAGE_COMMANDS_N]; - pub static MESSAGE_COMMANDS: LazyLock = LazyLock::new(|| { + #[inline] + fn message_commands() -> MessageCommands { ::paste::paste! { - [$(MESSAGE_COMMANDS_MAP.[<_ $raw_cmd:snake>].clone(),)*] - } - }); - - $( - impl CommandInfoAware for $raw_cmd { - fn name() -> &'static str { - ::paste::paste! { - &MESSAGE_COMMANDS_MAP.[<_ $raw_cmd:snake>].name - } - } + [ $( MESSAGE_COMMANDS_MAP.[<_ $raw_cmd:snake>].clone(), )* ] } - )* + } impl MessageCtx { pub async fn execute(self, data: CommandData) -> Result<(), CommandExecuteError> { check::user_allowed_in(&self).await?; + // there aren't as much message commands, so this should be fast enough match data.name { $( - n if n == <$raw_cmd>::name() => { + n if n == <$raw_cmd>::NAME => { return Ok(<$raw_cmd>::run(self).await?); } )* @@ -149,7 +145,7 @@ macro_rules! declare_autocomplete { pub async fn execute(self, data: CommandData) -> Result<(), AutocompleteExecuteError> { match data.name { $( - ref n if n == <$raw_cmd>::name() => { + ref n if n == <$raw_cmd>::NAME => { return Ok(<$raw_autocomplete>::from_interaction(data.into())?.execute(self).await?); } )* @@ -188,6 +184,7 @@ declare_slash_commands![ Skip, Back, ]; + declare_message_commands![AddToQueue,]; declare_autocomplete![ @@ -197,3 +194,43 @@ declare_autocomplete![ Move => MoveAutocomplete, Jump => JumpAutocomplete, ]; + +pub static POPULATED_COMMANDS_MAP: OnceLock> = OnceLock::new(); + +type Commands = [Command; SLASH_COMMANDS_N + MESSAGE_COMMANDS_N]; + +#[inline] +pub fn commands() -> Commands { + let a = slash_commands(); + let b = message_commands(); + + let mut result = std::mem::MaybeUninit::::uninit(); + let dest = result.as_mut_ptr().cast::(); + + // SAFETY: The source pointer `a.as_ptr()` is valid for `a.len()` elements, + // and `dest` is valid and initialized for at least `a.len()` elements + // since `result` is uninitialized but has enough space to hold both arrays. + unsafe { + std::ptr::copy_nonoverlapping(a.as_ptr(), dest, a.len()); + } + + // SAFETY: The pointer `dest` is valid for the entire array, and the offset + // `a.len()` is guaranteed to be within bounds because `Commands` has enough space + // to store both `a` and `b`. This simply calculates the address of where `b` should start. + let new_dest = unsafe { dest.add(a.len()) }; + + // SAFETY: The source pointer `b.as_ptr()` is valid for `b.len()` elements, + // and `new_dest` points to the remaining uninitialized part of the `result` array. + // Since we ensure the bounds of `result` by construction, this is safe. + unsafe { + std::ptr::copy_nonoverlapping(b.as_ptr(), new_dest, b.len()); + } + + std::mem::forget(a); + std::mem::forget(b); + + // SAFETY: The `result` has now been fully initialized by copying the elements from + // `a` and `b` into it. Therefore, it is safe to call `assume_init()` to retrieve the + // fully initialized array. + unsafe { result.assume_init() } +} diff --git a/lyra/src/command/model.rs b/lyra/src/command/model.rs index fe4e64b..560bb96 100644 --- a/lyra/src/command/model.rs +++ b/lyra/src/command/model.rs @@ -2,6 +2,7 @@ mod ctx; use std::sync::Arc; +use twilight_interactions::command::CreateCommand; use twilight_model::{ application::interaction::{ application_command::{CommandData, CommandDataOption}, @@ -94,19 +95,15 @@ pub enum PartialInteractionData { Component(Box), } -pub trait CommandInfoAware { - fn name() -> &'static str; -} - -pub trait BotSlashCommand: CommandInfoAware { +pub trait BotSlashCommand: CreateCommand { async fn run(self, ctx: SlashCtx) -> CommandResult; } -pub trait BotUserCommand: CommandInfoAware { +pub trait BotUserCommand: CreateCommand { async fn run(ctx: User) -> CommandResult; } -pub trait BotMessageCommand: CommandInfoAware { +pub trait BotMessageCommand: CreateCommand { async fn run(ctx: MessageCtx) -> CommandResult; } diff --git a/lyra/src/component/misc.rs b/lyra/src/component/misc.rs index ac45568..9543b29 100644 --- a/lyra/src/component/misc.rs +++ b/lyra/src/component/misc.rs @@ -20,7 +20,7 @@ impl BotSlashCommand for Ping { out!(format!("🏓 Pong! `({}ms)`", latency.as_millis()), ctx); } else { caut!( - "Cannot calculate the ping at the moment, try again later.", + "Cannot calculate the ping immediately after the bot has started, try again shortly later.", ctx ); } diff --git a/lyra/src/component/queue/play.rs b/lyra/src/component/queue/play.rs index b20bd52..5256e84 100644 --- a/lyra/src/component/queue/play.rs +++ b/lyra/src/component/queue/play.rs @@ -547,8 +547,17 @@ fn extract_queries(message: &Message) -> Vec> { pub struct AddToQueue; impl AddToQueue { + const NAME: &'static str = "➕ Add to queue"; pub fn create_command() -> Command { - CommandBuilder::new("➕ Add to queue", String::new(), CommandType::Message).build() + CommandBuilder::new(Self::NAME, String::new(), CommandType::Message).build() + } +} + +impl CreateCommand for AddToQueue { + const NAME: &'static str = Self::NAME; + fn create_command() -> twilight_interactions::command::ApplicationCommandData { + // SAFETY: `AddToQueue::create_command()` will shadow this, so the trait function will never be called + unsafe { std::hint::unreachable_unchecked() } } } diff --git a/lyra/src/core/model/interaction.rs b/lyra/src/core/model/interaction.rs index 07bea27..0fe334d 100644 --- a/lyra/src/core/model/interaction.rs +++ b/lyra/src/core/model/interaction.rs @@ -1,6 +1,7 @@ use std::fmt::{Display, Write}; use twilight_http::{request::application::interaction::UpdateResponse, Response}; +use twilight_interactions::command::CreateCommand; use twilight_model::{ application::{command::CommandOptionChoice, interaction::Interaction}, channel::{ @@ -16,10 +17,7 @@ use twilight_model::{ use twilight_util::builder::InteractionResponseDataBuilder; use crate::{ - command::{ - declare::{MESSAGE_COMMANDS, POPULATED_COMMANDS_MAP, SLASH_COMMANDS}, - model::CommandInfoAware, - }, + command::declare::{commands, POPULATED_COMMANDS_MAP}, error::core::{FollowupResult, RegisterGlobalCommandsError, RespondResult}, }; @@ -366,7 +364,7 @@ impl<'a> Client<'a> { pub async fn register_global_commands(&self) -> Result<(), RegisterGlobalCommandsError> { let commands = self .0 - .set_global_commands(&[SLASH_COMMANDS.as_slice(), MESSAGE_COMMANDS.as_slice()].concat()) + .set_global_commands(&commands()) .await? .models() .await?; @@ -381,9 +379,9 @@ impl<'a> Client<'a> { Ok(()) } - pub fn populated_command( + pub fn populated_command( ) -> &'static twilight_model::application::command::Command { - let name = T::name(); + let name = T::NAME; POPULATED_COMMANDS_MAP .get() .unwrap_or_else(|| panic!("`POPULATED_COMMANDS_MAP` is not yet populated")) @@ -391,7 +389,7 @@ impl<'a> Client<'a> { .unwrap_or_else(|| panic!("command not found: {name}")) } - pub fn mention_command() -> MentionCommand { + pub fn mention_command() -> MentionCommand { let cmd = Self::populated_command::(); let name = cmd.name.clone().into(); diff --git a/lyra_proc/src/command.rs b/lyra_proc/src/command.rs index 85f1eb4..8b5e114 100644 --- a/lyra_proc/src/command.rs +++ b/lyra_proc/src/command.rs @@ -1,28 +1,11 @@ use proc_macro::TokenStream; use quote::{__private::TokenStream as QuoteTokenStream, quote}; -use syn::{Data, DeriveInput, Fields, FieldsUnnamed, Ident, Path, Type, TypePath, Variant}; - -fn unwrap(type_path: &TypePath, from: impl Into) -> Option<&Path> { - match type_path.path.segments.last() { - Some(segment) if segment.ident == from.into() => match &segment.arguments { - syn::PathArguments::AngleBracketed(args) if args.args.len() == 1 => match &args.args[0] - { - syn::GenericArgument::Type(Type::Path(inner_type_path)) => { - Some(&inner_type_path.path) - } - _ => None, - }, - _ => None, - }, - _ => None, - } -} +use syn::{Data, DeriveInput, Fields, FieldsUnnamed, Path, Type, Variant}; fn declare_commands( fields: &FieldsUnnamed, v: &Variant, c: (QuoteTokenStream, QuoteTokenStream), - name: &Ident, ) -> (QuoteTokenStream, QuoteTokenStream) { let sub_cmd = fields .unnamed @@ -30,39 +13,15 @@ fn declare_commands( .expect("variant must have exactly one unnamed field"); let v_ident = &v.ident; match sub_cmd.ty { - Type::Path(ref type_path) => { + Type::Path(_) => { let (sub_cmd_match, impl_resolved_command_data) = c; - let sub_cmd_inner = unwrap(type_path, "Box"); - let command_info_aware_path = - syn::parse_str::("crate::command::model::CommandInfoAware") - .expect("path is valid"); - let impl_for_inner = sub_cmd_inner.map_or_else( - || quote!(), - |inner| { - quote! { - impl #command_info_aware_path for #inner { - fn name() -> &'static str { - #name::name() - } - } - } - }, - ); ( quote! { #sub_cmd_match Self::#v_ident(sub_cmd) => sub_cmd.run(ctx).await, }, - quote! { - #impl_resolved_command_data - impl #command_info_aware_path for #sub_cmd { - fn name() -> &'static str { - #name::name() - } - } - #impl_for_inner - }, + impl_resolved_command_data, ) } _ => panic!("the field must be a path"), @@ -78,7 +37,7 @@ pub fn impl_bot_command_group(input: &DeriveInput) -> TokenStream { data.variants .iter() .fold((quote!(), quote!()), |c, v| match v.fields { - Fields::Unnamed(ref fields) => declare_commands(fields, v, c, name), + Fields::Unnamed(ref fields) => declare_commands(fields, v, c), _ => panic!("all fields must be unnamed"), }) }