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,
|
variant: proc_macro2::TokenStream,
|
||||||
parser_type: &ParserType,
|
parser_type: &ParserType,
|
||||||
) -> proc_macro2::TokenStream {
|
) -> proc_macro2::TokenStream {
|
||||||
let get_arguments = create_parser(
|
let get_arguments =
|
||||||
parser_type,
|
create_parser(parser_type, data.unnamed.iter().map(|f| &f.ty));
|
||||||
data.unnamed.iter().map(|f| &f.ty),
|
|
||||||
data.unnamed.len(),
|
|
||||||
);
|
|
||||||
let iter = (0..data.unnamed.len()).map(syn::Index::from);
|
let iter = (0..data.unnamed.len()).map(syn::Index::from);
|
||||||
let mut initialization = quote! {};
|
let mut initialization = quote! {};
|
||||||
for i in iter {
|
for i in iter {
|
||||||
|
@ -65,12 +62,9 @@ pub(crate) fn impl_parse_args_named(
|
||||||
variant: proc_macro2::TokenStream,
|
variant: proc_macro2::TokenStream,
|
||||||
parser_type: &ParserType,
|
parser_type: &ParserType,
|
||||||
) -> proc_macro2::TokenStream {
|
) -> proc_macro2::TokenStream {
|
||||||
let get_arguments = create_parser(
|
let get_arguments =
|
||||||
parser_type,
|
create_parser(parser_type, data.named.iter().map(|f| &f.ty));
|
||||||
data.named.iter().map(|f| &f.ty),
|
let i = (0..).map(syn::Index::from);
|
||||||
data.named.len(),
|
|
||||||
);
|
|
||||||
let i = (0..data.named.len()).map(syn::Index::from);
|
|
||||||
let name = data.named.iter().map(|f| f.ident.as_ref().unwrap());
|
let name = data.named.iter().map(|f| f.ident.as_ref().unwrap());
|
||||||
let res = quote! {
|
let res = quote! {
|
||||||
{
|
{
|
||||||
|
@ -83,26 +77,30 @@ pub(crate) fn impl_parse_args_named(
|
||||||
|
|
||||||
fn create_parser<'a>(
|
fn create_parser<'a>(
|
||||||
parser_type: &ParserType,
|
parser_type: &ParserType,
|
||||||
mut types: impl Iterator<Item = &'a Type>,
|
mut types: impl ExactSizeIterator<Item = &'a Type>,
|
||||||
count_args: usize,
|
|
||||||
) -> proc_macro2::TokenStream {
|
) -> proc_macro2::TokenStream {
|
||||||
let function_to_parse = match parser_type {
|
let function_to_parse = match parser_type {
|
||||||
ParserType::Default => match count_args {
|
ParserType::Default => match types.len() {
|
||||||
1 => {
|
1 => {
|
||||||
let ty = types.next().expect("count_args != types.len()");
|
let ty = types.next().unwrap();
|
||||||
quote! { (|s: String| {
|
quote! {
|
||||||
let res = <#ty>::from_str(&s)
|
(
|
||||||
.map_err(|e|ParseError::IncorrectFormat({ let e: Box<dyn std::error::Error + Send + Sync + 'static> = e.into(); e }))?;
|
|s: String| {
|
||||||
Ok((res, ))
|
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(
|
ParserType::Split { separator } => parser_with_separator(
|
||||||
&separator.clone().unwrap_or_else(|| " ".to_owned()),
|
&separator.clone().unwrap_or_else(|| " ".to_owned()),
|
||||||
types,
|
types,
|
||||||
count_args,
|
|
||||||
),
|
),
|
||||||
ParserType::Custom(s) => {
|
ParserType::Custom(s) => {
|
||||||
let path = syn::parse_str::<syn::Path>(s).unwrap_or_else(|_| {
|
let path = syn::parse_str::<syn::Path>(s).unwrap_or_else(|_| {
|
||||||
|
@ -111,6 +109,7 @@ fn create_parser<'a>(
|
||||||
quote! { #path }
|
quote! { #path }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
let arguments = #function_to_parse(args)?;
|
let arguments = #function_to_parse(args)?;
|
||||||
}
|
}
|
||||||
|
@ -118,31 +117,46 @@ fn create_parser<'a>(
|
||||||
|
|
||||||
fn parser_with_separator<'a>(
|
fn parser_with_separator<'a>(
|
||||||
separator: &str,
|
separator: &str,
|
||||||
types: impl Iterator<Item = &'a Type>,
|
types: impl ExactSizeIterator<Item = &'a Type>,
|
||||||
count_args: usize,
|
|
||||||
) -> proc_macro2::TokenStream {
|
) -> proc_macro2::TokenStream {
|
||||||
let inner = quote! { let mut splited = s.split(#separator); };
|
let expected = types.len();
|
||||||
let i = 0..count_args;
|
let res = {
|
||||||
let inner2 = quote! {
|
let found = 0usize..;
|
||||||
#(<#types>::from_str(splited.next().ok_or(ParseError::TooFewArguments {
|
quote! {
|
||||||
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 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! {
|
let res = quote! {
|
||||||
(|s: String| {
|
(
|
||||||
#inner
|
|s: String| {
|
||||||
let res = (#inner2);
|
let mut splitted = s.split(#separator);
|
||||||
match splited.next() {
|
|
||||||
Some(d) => Err(ParseError::TooManyArguments {
|
let res = #res;
|
||||||
expected: #count_args,
|
|
||||||
found: #count_args + 1,
|
match splitted.next() {
|
||||||
message: format!("Excess argument: {}", d),
|
Some(d) => Err(ParseError::TooManyArguments {
|
||||||
}),
|
expected: #expected,
|
||||||
None => Ok(res)
|
found: #expected + 1,
|
||||||
|
message: format!("Excess argument: {}", d),
|
||||||
|
}),
|
||||||
|
None => Ok(res)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
26
src/lib.rs
26
src/lib.rs
|
@ -131,25 +131,31 @@ fn impl_parse(
|
||||||
where
|
where
|
||||||
N: Into<String>
|
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 std::str::FromStr;
|
||||||
use teloxide::utils::command::ParseError;
|
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 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.");
|
// Unwrap: split iterators always have at least one item
|
||||||
let bot = splitted.next();
|
let mut full_command = words.next().unwrap().split('@');
|
||||||
let bot_name = bot_name.into();
|
let command = full_command.next().unwrap();
|
||||||
match bot {
|
|
||||||
Some(name) if name.eq_ignore_ascii_case(&bot_name) => {}
|
let bot_username = full_command.next();
|
||||||
|
match bot_username {
|
||||||
None => {}
|
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),
|
#matching_values => Ok(#variants_initialization),
|
||||||
)*
|
)*
|
||||||
_ => Err(ParseError::UnknownCommand(command_raw.to_string())),
|
_ => Err(ParseError::UnknownCommand(command.to_owned())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue