From 5b369bbafde38f74670681dc9f4b55430712a4ff Mon Sep 17 00:00:00 2001 From: Gnome! Date: Sat, 4 May 2024 01:14:37 +0100 Subject: [PATCH] [Macros] Reduce generated code for field conversions (#260) * [Macros] Reduce generated code for field conversions * Avoid generating CooldownConfig initialisation entirely if default --- macros/src/command/mod.rs | 62 +++++++++++++++++++++++++------------ macros/src/command/slash.rs | 25 ++++++--------- macros/src/util.rs | 42 ++++++++++++++++++++++--- 3 files changed, 89 insertions(+), 40 deletions(-) diff --git a/macros/src/command/mod.rs b/macros/src/command/mod.rs index fe8b8a221dec..8c7f8bbd6136 100644 --- a/macros/src/command/mod.rs +++ b/macros/src/command/mod.rs @@ -1,7 +1,9 @@ mod prefix; mod slash; -use crate::util::{wrap_option, wrap_option_to_string}; +use crate::util::{ + iter_tuple_2_to_hash_map, wrap_option, wrap_option_and_map, wrap_option_to_string, +}; use proc_macro::TokenStream; use syn::spanned::Spanned as _; @@ -271,20 +273,14 @@ fn generate_command(mut inv: Invocation) -> Result quote::quote! { Some(#x.to_string()) }, - None => quote::quote! { None }, - }; let hide_in_help = &inv.args.hide_in_help; + let description = wrap_option_to_string(inv.description.as_ref()); let category = wrap_option_to_string(inv.args.category.as_ref()); - let global_cooldown = wrap_option(inv.args.global_cooldown); - let user_cooldown = wrap_option(inv.args.user_cooldown); - let guild_cooldown = wrap_option(inv.args.guild_cooldown); - let channel_cooldown = wrap_option(inv.args.channel_cooldown); - let member_cooldown = wrap_option(inv.args.member_cooldown); + let cooldown_config = generate_cooldown_config(&inv.args); let default_member_permissions = &inv.default_member_permissions; let required_permissions = &inv.required_permissions; @@ -324,9 +320,9 @@ fn generate_command(mut inv: Invocation) -> Result quote::quote! { Box::new(()) }, }; - let name_localizations = crate::util::vec_tuple_2_to_hash_map(inv.args.name_localized); + let name_localizations = iter_tuple_2_to_hash_map(inv.args.name_localized.into_iter()); let description_localizations = - crate::util::vec_tuple_2_to_hash_map(inv.args.description_localized); + iter_tuple_2_to_hash_map(inv.args.description_localized.into_iter()); let function_ident = std::mem::replace(&mut inv.function.sig.ident, syn::parse_quote! { inner }); @@ -359,14 +355,7 @@ fn generate_command(mut inv: Invocation) -> Result Result proc_macro2::TokenStream { + let all_cooldowns = [ + args.global_cooldown, + args.user_cooldown, + args.guild_cooldown, + args.channel_cooldown, + args.member_cooldown, + ]; + + if all_cooldowns.iter().all(Option::is_none) { + return quote::quote!(std::sync::RwLock::default()); + } + + let to_seconds_path = quote::quote!(std::time::Duration::from_secs); + + let global_cooldown = wrap_option_and_map(args.global_cooldown, &to_seconds_path); + let user_cooldown = wrap_option_and_map(args.user_cooldown, &to_seconds_path); + let guild_cooldown = wrap_option_and_map(args.guild_cooldown, &to_seconds_path); + let channel_cooldown = wrap_option_and_map(args.channel_cooldown, &to_seconds_path); + let member_cooldown = wrap_option_and_map(args.member_cooldown, &to_seconds_path); + + quote::quote!( + std::sync::RwLock::new(::poise::CooldownConfig { + global: #global_cooldown, + user: #user_cooldown, + guild: #guild_cooldown, + channel: #channel_cooldown, + member: #member_cooldown, + __non_exhaustive: () + }) + ) +} diff --git a/macros/src/command/slash.rs b/macros/src/command/slash.rs index 41c004c837be..ce27546b3a19 100644 --- a/macros/src/command/slash.rs +++ b/macros/src/command/slash.rs @@ -1,5 +1,7 @@ use super::Invocation; -use crate::util::extract_type_parameter; +use crate::util::{ + extract_type_parameter, iter_tuple_2_to_hash_map, tuple_2_iter_deref, wrap_option_to_string, +}; use quote::format_ident; use syn::spanned::Spanned as _; @@ -8,10 +10,7 @@ pub fn generate_parameters(inv: &Invocation) -> Result quote::quote! { Some(#x.to_string()) }, - None => quote::quote! { None }, - }; + let description = wrap_option_to_string(param.args.description.as_ref()); let (mut required, type_) = match extract_type_parameter("Option", ¶m.type_) .or_else(|| extract_type_parameter("Vec", ¶m.type_)) @@ -26,10 +25,10 @@ pub fn generate_parameters(inv: &Invocation) -> Result { @@ -118,13 +117,9 @@ pub fn generate_parameters(inv: &Invocation) -> Result(literal: Option) -> syn::Expr { } } -/// Converts None => `None` and Some(x) => `Some(#x.to_string())` -pub fn wrap_option_to_string(literal: Option) -> syn::Expr { +/// Converts None => `None` and Some(x) => `Some(#map_path(#x))` +pub fn wrap_option_and_map( + literal: Option, + map_path: impl quote::ToTokens, +) -> syn::Expr { match literal { - Some(literal) => syn::parse_quote! { Some(#literal.to_string()) }, + Some(literal) => syn::parse_quote! { Some(#map_path(#literal)) }, None => syn::parse_quote! { None }, } } +pub fn wrap_option_to_string(literal: Option) -> syn::Expr { + let to_string_path = quote::quote!(::std::string::ToString::to_string); + wrap_option_and_map(literal, to_string_path) +} + /// Syn Fold to make all lifetimes 'static. Used to access trait items of a type without having its /// concrete lifetime available pub struct AllLifetimesToStatic; @@ -79,8 +87,32 @@ impl darling::FromMeta for Tuple2 { } } -pub fn vec_tuple_2_to_hash_map(v: Vec>) -> proc_macro2::TokenStream { - let (keys, values): (Vec, Vec) = v.into_iter().map(|x| (x.0, x.1)).unzip(); +pub fn tuple_2_iter_deref<'a, I: 'a, T: 'a, D: ?Sized + 'a>( + iter: I, +) -> impl ExactSizeIterator> +where + I: IntoIterator>, + I::IntoIter: ExactSizeIterator, + T: std::ops::Deref, +{ + iter.into_iter() + .map(|Tuple2(t, v)| Tuple2(t.deref(), v.deref())) +} + +pub fn iter_tuple_2_to_hash_map(v: I) -> proc_macro2::TokenStream +where + I: ExactSizeIterator>, + T: quote::ToTokens, +{ + if v.len() == 0 { + return quote::quote!(std::collections::HashMap::new()); + } + + let (keys, values) = v + .into_iter() + .map(|x| (x.0, x.1)) + .unzip::<_, _, Vec<_>, Vec<_>>(); + quote::quote! { std::collections::HashMap::from([ #( (#keys.to_string(), #values.to_string()) ),*