diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c997856..a3bc8fec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - `#[command(rename = "...")]` now always renames to `"..."`, to rename multiple commands using the same pattern, use `#[command(rename_rule = "snake_case")]` and the like. +- `#[command(parse_with = ...)]` now requires a path, instead of a string, when specifying custom parsers ## 0.6.3 - 2022-07-19 diff --git a/src/attr.rs b/src/attr.rs index dd4b9493..04a070ed 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -99,7 +99,7 @@ impl AttrValue { // }) // } - fn expect( + pub fn expect( self, expected: &str, f: impl FnOnce(Self) -> Result, diff --git a/src/command_attr.rs b/src/command_attr.rs index 3aeb8e63..e735b7bb 100644 --- a/src/command_attr.rs +++ b/src/command_attr.rs @@ -106,9 +106,7 @@ impl CommandAttr { .and_then(|r| self::RenameRule::parse(&r))?, ), "rename" => Rename(value.expect_string()?), - "parse_with" => { - ParseWith(value.expect_string().map(|p| ParserType::parse(&p))?) - } + "parse_with" => ParseWith(ParserType::parse(value)?), "separator" => Separator(value.expect_string()?), _ => { return Err(compile_error_at( diff --git a/src/fields_parse.rs b/src/fields_parse.rs index 6dc2baeb..1845812a 100644 --- a/src/fields_parse.rs +++ b/src/fields_parse.rs @@ -1,21 +1,26 @@ use quote::quote; use syn::{Fields, FieldsNamed, FieldsUnnamed, Type}; +use crate::{attr::AttrValue, error::Result}; + #[derive(Debug, Clone)] pub(crate) enum ParserType { Default, Split { separator: Option }, - Custom(String), + Custom(syn::Path), } impl ParserType { - // FIXME: use path for custom - pub fn parse(data: &str) -> Self { - match data { - "default" => ParserType::Default, - "split" => ParserType::Split { separator: None }, - s => ParserType::Custom(s.to_owned()), - } + pub fn parse(value: AttrValue) -> Result { + value.expect(r#""default", "split" or a path"#, |v| match v { + AttrValue::Path(p) => Ok(ParserType::Custom(p)), + AttrValue::Lit(syn::Lit::Str(ref l)) => match &*l.value() { + "default" => Ok(ParserType::Default), + "split" => Ok(ParserType::Split { separator: None }), + _ => Err(v), + }, + _ => Err(v), + }) } } @@ -101,12 +106,7 @@ fn create_parser<'a>( &separator.clone().unwrap_or_else(|| " ".to_owned()), types, ), - ParserType::Custom(s) => { - let path = syn::parse_str::(s).unwrap_or_else(|_| { - panic!("Failed to parse a custom command parser, {}", s) - }); - quote! { #path } - } + ParserType::Custom(path) => quote! { #path }, }; quote! { diff --git a/tests/command.rs b/tests/command.rs index f7297c8d..65aea651 100644 --- a/tests/command.rs +++ b/tests/command.rs @@ -180,11 +180,11 @@ fn parse_custom_parser() { #[derive(BotCommands, Debug, PartialEq)] #[command(rename_rule = "lowercase")] enum DefaultCommands { - #[command(parse_with = "custom_parse_function")] + #[command(parse_with = custom_parse_function)] Start(u8, String), // Test . - #[command(parse_with = "parser::custom_parse_function")] + #[command(parse_with = parser::custom_parse_function)] TestPath(u8, String), Help,