From f13e3b6e4a07af9822149c0b3f581c4cd0c679cf Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 25 Aug 2022 17:01:03 +0400 Subject: [PATCH] refactor generated code --- src/fields_parse.rs | 100 +++++++++++++++++++++++++------------------- src/lib.rs | 26 +++++++----- 2 files changed, 73 insertions(+), 53 deletions(-) diff --git a/src/fields_parse.rs b/src/fields_parse.rs index 19b518a6..af33a490 100644 --- a/src/fields_parse.rs +++ b/src/fields_parse.rs @@ -41,11 +41,8 @@ pub(crate) fn impl_parse_args_unnamed( variant: proc_macro2::TokenStream, parser_type: &ParserType, ) -> proc_macro2::TokenStream { - let get_arguments = create_parser( - parser_type, - data.unnamed.iter().map(|f| &f.ty), - data.unnamed.len(), - ); + let get_arguments = + create_parser(parser_type, data.unnamed.iter().map(|f| &f.ty)); let iter = (0..data.unnamed.len()).map(syn::Index::from); let mut initialization = quote! {}; for i in iter { @@ -65,12 +62,9 @@ pub(crate) fn impl_parse_args_named( variant: proc_macro2::TokenStream, parser_type: &ParserType, ) -> proc_macro2::TokenStream { - let get_arguments = create_parser( - parser_type, - data.named.iter().map(|f| &f.ty), - data.named.len(), - ); - let i = (0..data.named.len()).map(syn::Index::from); + let get_arguments = + create_parser(parser_type, data.named.iter().map(|f| &f.ty)); + let i = (0..).map(syn::Index::from); let name = data.named.iter().map(|f| f.ident.as_ref().unwrap()); let res = quote! { { @@ -83,26 +77,30 @@ pub(crate) fn impl_parse_args_named( fn create_parser<'a>( parser_type: &ParserType, - mut types: impl Iterator, - count_args: usize, + mut types: impl ExactSizeIterator, ) -> proc_macro2::TokenStream { let function_to_parse = match parser_type { - ParserType::Default => match count_args { + ParserType::Default => match types.len() { 1 => { - let ty = types.next().expect("count_args != types.len()"); - quote! { (|s: String| { - let res = <#ty>::from_str(&s) - .map_err(|e|ParseError::IncorrectFormat({ let e: Box = e.into(); e }))?; - Ok((res, )) - }) + let ty = types.next().unwrap(); + quote! { + ( + |s: String| { + let res = <#ty>::from_str(&s) + .map_err(|e| ParseError::IncorrectFormat(e.into()))?; + + Ok((res,)) + } + ) } } - _ => quote! { compile_error!("Expected exactly 1 argument") }, + _ => { + quote! { compile_error!("Default parser works only with exactly 1 field") } + } }, ParserType::Split { separator } => parser_with_separator( &separator.clone().unwrap_or_else(|| " ".to_owned()), types, - count_args, ), ParserType::Custom(s) => { let path = syn::parse_str::(s).unwrap_or_else(|_| { @@ -111,6 +109,7 @@ fn create_parser<'a>( quote! { #path } } }; + quote! { let arguments = #function_to_parse(args)?; } @@ -118,31 +117,46 @@ fn create_parser<'a>( fn parser_with_separator<'a>( separator: &str, - types: impl Iterator, - count_args: usize, + types: impl ExactSizeIterator, ) -> proc_macro2::TokenStream { - let inner = quote! { let mut splited = s.split(#separator); }; - let i = 0..count_args; - let inner2 = quote! { - #(<#types>::from_str(splited.next().ok_or(ParseError::TooFewArguments { - expected: #count_args, - found: #i, - message: format!("Expected but not found arg number {}", #i + 1), - })?).map_err(|e|ParseError::IncorrectFormat({ let e: Box = e.into(); e }))?,)* + let expected = types.len(); + let res = { + let found = 0usize..; + quote! { + ( + #( + { + let s = splitted.next().ok_or(ParseError::TooFewArguments { + expected: #expected, + found: #found, + message: format!("Expected but not found arg number {}", #found + 1), + })?; + + <#types>::from_str(s).map_err(|e| ParseError::IncorrectFormat(e.into()))? + } + ),* + ) + } }; + let res = quote! { - (|s: String| { - #inner - let res = (#inner2); - match splited.next() { - Some(d) => Err(ParseError::TooManyArguments { - expected: #count_args, - found: #count_args + 1, - message: format!("Excess argument: {}", d), - }), - None => Ok(res) + ( + |s: String| { + let mut splitted = s.split(#separator); + + let res = #res; + + match splitted.next() { + Some(d) => Err(ParseError::TooManyArguments { + expected: #expected, + found: #expected + 1, + message: format!("Excess argument: {}", d), + }), + None => Ok(res) + } } - }) + ) }; + res } diff --git a/src/lib.rs b/src/lib.rs index eba47a57..1475255b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -131,25 +131,31 @@ fn impl_parse( where N: Into { + // FIXME: we should probably just call a helper function from `teloxide`, instead of parsing command syntax ourselves use std::str::FromStr; use teloxide::utils::command::ParseError; + // 2 is used to only split once (=> in two parts), + // we only need to split the command and the rest of arguments. let mut words = s.splitn(2, ' '); - let mut splitted = words.next().expect("First item will be always.").split('@'); - let command_raw = splitted.next().expect("First item will be always."); - let bot = splitted.next(); - let bot_name = bot_name.into(); - match bot { - Some(name) if name.eq_ignore_ascii_case(&bot_name) => {} + + // Unwrap: split iterators always have at least one item + let mut full_command = words.next().unwrap().split('@'); + let command = full_command.next().unwrap(); + + let bot_username = full_command.next(); + match bot_username { None => {} - Some(n) => return Err(ParseError::WrongBotName(n.to_string())), + Some(username) if username.eq_ignore_ascii_case(&bot_name.into()) => {} + Some(n) => return Err(ParseError::WrongBotName(n.to_owned())), } - let mut args = words.next().unwrap_or("").to_string(); - match command_raw { + + let args = words.next().unwrap_or("").to_owned(); + match command { #( #matching_values => Ok(#variants_initialization), )* - _ => Err(ParseError::UnknownCommand(command_raw.to_string())), + _ => Err(ParseError::UnknownCommand(command.to_owned())), } } }