Skip to content

Commit

Permalink
Perform inline choice conversion to string in macro (#322)
Browse files Browse the repository at this point in the history
  • Loading branch information
GnomedDev authored Nov 13, 2024
1 parent 7b3fad4 commit 3a2ab5e
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 4 deletions.
2 changes: 1 addition & 1 deletion examples/feature_showcase/choice_parameter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub async fn choice(
//
// Limitations: due to macro limitations (partially self-imposed, partially external), poise
// currently does not support Options parameters, and only supports parameter types that can be
// constructed from a literal (https://doc.rust-lang.org/reference/expressions/literal-expr.html).
// constructed from a literal which can be converted to a string at compile time.

#[poise::command(slash_command)]
pub async fn inline_choice(
Expand Down
26 changes: 23 additions & 3 deletions macros/src/command/slash.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
use super::Invocation;
use crate::util::{
extract_type_parameter, iter_tuple_2_to_hash_map, tuple_2_iter_deref, wrap_option_to_string,
List,
};
use quote::format_ident;
use syn::spanned::Spanned as _;

fn lit_to_string(lit: &syn::Lit) -> Result<String, syn::Error> {
match lit {
syn::Lit::Str(lit_str) => Ok(lit_str.value()),
syn::Lit::Char(lit_char) => Ok(lit_char.value().to_string()),
syn::Lit::Int(lit_int) => Ok(lit_int.base10_digits().to_owned()),
syn::Lit::Float(lit_float) => Ok(lit_float.token().to_string()),
syn::Lit::Bool(lit_bool) => Ok(lit_bool.value.to_string()),

_ => Err(syn::Error::new(
lit.span(),
"Inline choice must be convertable to a string at compile time",
)),
}
}

pub fn generate_parameters(inv: &Invocation) -> Result<Vec<proc_macro2::TokenStream>, syn::Error> {
let mut parameter_structs = Vec::new();
for param in &inv.parameters {
Expand Down Expand Up @@ -77,10 +93,14 @@ pub fn generate_parameters(inv: &Invocation) -> Result<Vec<proc_macro2::TokenStr
// TODO: move this to poise::CommandParameter::choices (is there a reason not to?)
let choices = match inv.args.slash_command {
true => {
if let Some(choices) = &param.args.choices {
let choices = &choices.0;
if let Some(List(choices)) = &param.args.choices {
let choices = choices
.iter()
.map(lit_to_string)
.collect::<Result<Vec<_>, _>>()?;

quote::quote! { vec![#( ::poise::CommandParameterChoice {
name: ToString::to_string(&#choices),
name: String::from(#choices),
localizations: Default::default(),
__non_exhaustive: (),
} ),*] }
Expand Down

0 comments on commit 3a2ab5e

Please sign in to comment.