mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-03 17:52:12 +01:00
refactor generated code
This commit is contained in:
parent
f03264e694
commit
f13e3b6e4a
2 changed files with 73 additions and 53 deletions
|
@ -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<Item = &'a Type>,
|
||||
count_args: usize,
|
||||
mut types: impl ExactSizeIterator<Item = &'a Type>,
|
||||
) -> 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<dyn std::error::Error + Send + Sync + 'static> = 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::<syn::Path>(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<Item = &'a Type>,
|
||||
count_args: usize,
|
||||
types: impl ExactSizeIterator<Item = &'a Type>,
|
||||
) -> 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<dyn std::error::Error + Send + Sync + 'static> = 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
|
||||
}
|
||||
|
|
26
src/lib.rs
26
src/lib.rs
|
@ -131,25 +131,31 @@ fn impl_parse(
|
|||
where
|
||||
N: Into<String>
|
||||
{
|
||||
// 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())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue