mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-03 17:52:12 +01:00
Iterator ftw
This commit is contained in:
parent
cfe75ae844
commit
f03264e694
4 changed files with 80 additions and 56 deletions
|
@ -55,6 +55,10 @@ impl Command {
|
|||
|
||||
(String::from(prefix), global_parameters.rename_rule.apply(&self.name))
|
||||
}
|
||||
|
||||
pub(crate) fn description_is_enabled(&self) -> bool {
|
||||
self.description != Some("off".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CommandAttrs {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
extern crate quote;
|
||||
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{FieldsNamed, FieldsUnnamed, Type};
|
||||
use quote::quote;
|
||||
use syn::{Fields, FieldsNamed, FieldsUnnamed, Type};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ParserType {
|
||||
|
@ -20,9 +20,25 @@ impl ParserType {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn impl_parse_args(
|
||||
fields: &Fields,
|
||||
self_variant: proc_macro2::TokenStream,
|
||||
parser: &ParserType,
|
||||
) -> proc_macro2::TokenStream {
|
||||
match fields {
|
||||
Fields::Unit => self_variant,
|
||||
Fields::Unnamed(fields) => {
|
||||
impl_parse_args_unnamed(fields, self_variant, parser)
|
||||
}
|
||||
Fields::Named(named) => {
|
||||
impl_parse_args_named(named, self_variant, parser)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn impl_parse_args_unnamed(
|
||||
data: &FieldsUnnamed,
|
||||
variant: impl ToTokens,
|
||||
variant: proc_macro2::TokenStream,
|
||||
parser_type: &ParserType,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let get_arguments = create_parser(
|
||||
|
@ -46,7 +62,7 @@ pub(crate) fn impl_parse_args_unnamed(
|
|||
|
||||
pub(crate) fn impl_parse_args_named(
|
||||
data: &FieldsNamed,
|
||||
variant: impl ToTokens,
|
||||
variant: proc_macro2::TokenStream,
|
||||
parser_type: &ParserType,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let get_arguments = create_parser(
|
||||
|
|
80
src/lib.rs
80
src/lib.rs
|
@ -6,19 +6,18 @@ mod command_enum;
|
|||
mod error;
|
||||
mod fields_parse;
|
||||
mod rename_rules;
|
||||
mod unzip;
|
||||
|
||||
extern crate proc_macro;
|
||||
extern crate quote;
|
||||
extern crate syn;
|
||||
use crate::{
|
||||
attr::CommandAttrs,
|
||||
command::Command,
|
||||
command_enum::CommandEnum,
|
||||
fields_parse::{impl_parse_args_named, impl_parse_args_unnamed},
|
||||
attr::CommandAttrs, command::Command, command_enum::CommandEnum,
|
||||
fields_parse::impl_parse_args, unzip::Unzip,
|
||||
};
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{DeriveInput, Fields};
|
||||
use syn::DeriveInput;
|
||||
|
||||
pub(crate) use error::{compile_error, Error, Result};
|
||||
|
||||
|
@ -30,53 +29,35 @@ pub fn bot_commands_derive(tokens: TokenStream) -> TokenStream {
|
|||
fn bot_commands_impl(tokens: TokenStream) -> Result<TokenStream, Error> {
|
||||
let input = syn::parse_macro_input::parse::<DeriveInput>(tokens)?;
|
||||
|
||||
let data_enum: &syn::DataEnum = get_enum_data(&input)?;
|
||||
let data_enum = get_enum_data(&input)?;
|
||||
let enum_attrs = CommandAttrs::from_attributes(&input.attrs)?;
|
||||
let command_enum = CommandEnum::try_from(enum_attrs)?;
|
||||
|
||||
let variant_infos = data_enum
|
||||
let Unzip(var_init, var_info) = data_enum
|
||||
.variants
|
||||
.iter()
|
||||
.map(|variant| {
|
||||
let attrs = CommandAttrs::from_attributes(&variant.attrs)?;
|
||||
let command = Command::try_from(attrs, &variant.ident.to_string())?;
|
||||
|
||||
Ok(command)
|
||||
let variant_name = &variant.ident;
|
||||
let self_variant = quote! { Self::#variant_name };
|
||||
|
||||
let parser =
|
||||
command.parser.as_ref().unwrap_or(&command_enum.parser_type);
|
||||
let parse = impl_parse_args(&variant.fields, self_variant, parser);
|
||||
|
||||
Ok((parse, command))
|
||||
})
|
||||
.collect::<Result<Vec<_>, Error>>()?;
|
||||
.collect::<Result<Unzip<Vec<_>, Vec<_>>, Error>>()?;
|
||||
|
||||
let mut vec_impl_create = vec![];
|
||||
|
||||
for (variant, info) in data_enum.variants.iter().zip(variant_infos.iter()) {
|
||||
let var = &variant.ident;
|
||||
let variant_ = quote! { Self::#var };
|
||||
match &variant.fields {
|
||||
Fields::Unnamed(fields) => {
|
||||
let parser =
|
||||
info.parser.as_ref().unwrap_or(&command_enum.parser_type);
|
||||
vec_impl_create
|
||||
.push(impl_parse_args_unnamed(fields, variant_, parser));
|
||||
}
|
||||
Fields::Unit => {
|
||||
vec_impl_create.push(variant_);
|
||||
}
|
||||
Fields::Named(named) => {
|
||||
let parser =
|
||||
info.parser.as_ref().unwrap_or(&command_enum.parser_type);
|
||||
vec_impl_create
|
||||
.push(impl_parse_args_named(named, variant_, parser));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let ident = &input.ident;
|
||||
|
||||
let fn_descriptions = impl_descriptions(&variant_infos, &command_enum);
|
||||
let fn_parse = impl_parse(&variant_infos, &command_enum, &vec_impl_create);
|
||||
let fn_commands = impl_commands(&variant_infos, &command_enum);
|
||||
let type_name = &input.ident;
|
||||
let fn_descriptions = impl_descriptions(&var_info, &command_enum);
|
||||
let fn_parse = impl_parse(&var_info, &command_enum, &var_init);
|
||||
let fn_commands = impl_commands(&var_info, &command_enum);
|
||||
|
||||
let trait_impl = quote! {
|
||||
impl BotCommands for #ident {
|
||||
impl BotCommands for #type_name {
|
||||
#fn_descriptions
|
||||
#fn_parse
|
||||
#fn_commands
|
||||
|
@ -90,19 +71,19 @@ fn impl_commands(
|
|||
infos: &[Command],
|
||||
global: &CommandEnum,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let commands_to_list = infos.iter().filter_map(|command| {
|
||||
if command.description == Some("off".into()) {
|
||||
None
|
||||
} else {
|
||||
let commands = infos
|
||||
.iter()
|
||||
.filter(|command| command.description_is_enabled())
|
||||
.map(|command| {
|
||||
let c = command.get_matched_value(global);
|
||||
let d = command.description.as_deref().unwrap_or_default();
|
||||
Some(quote! { BotCommand::new(#c,#d) })
|
||||
}
|
||||
quote! { BotCommand::new(#c,#d) }
|
||||
});
|
||||
|
||||
quote! {
|
||||
fn bot_commands() -> Vec<teloxide::types::BotCommand> {
|
||||
use teloxide::types::BotCommand;
|
||||
vec![#(#commands_to_list),*]
|
||||
vec![#(#commands),*]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,10 +92,13 @@ fn impl_descriptions(
|
|||
infos: &[Command],
|
||||
global: &CommandEnum,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let command_descriptions = infos.iter().filter_map(|c| {
|
||||
let command_descriptions = infos
|
||||
.iter()
|
||||
.filter(|command| command.description_is_enabled())
|
||||
.map(|c| {
|
||||
let (prefix, command) = c.get_matched_value2(global);
|
||||
let description = c.description.clone().unwrap_or_default();
|
||||
(description != "off").then(|| quote! { CommandDescription { prefix: #prefix, command: #command, description: #description } })
|
||||
quote! { CommandDescription { prefix: #prefix, command: #command, description: #description } }
|
||||
});
|
||||
|
||||
let global_description = match global.description.as_deref() {
|
||||
|
|
20
src/unzip.rs
Normal file
20
src/unzip.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use std::iter::FromIterator;
|
||||
|
||||
pub(crate) struct Unzip<A, B>(pub A, pub B);
|
||||
|
||||
impl<A, B, T, U> FromIterator<(T, U)> for Unzip<A, B>
|
||||
where
|
||||
A: Default + Extend<T>,
|
||||
B: Default + Extend<U>,
|
||||
{
|
||||
fn from_iter<I: IntoIterator<Item = (T, U)>>(iter: I) -> Self {
|
||||
let (mut a, mut b): (A, B) = Default::default();
|
||||
|
||||
for (t, u) in iter {
|
||||
a.extend([t]);
|
||||
b.extend([u]);
|
||||
}
|
||||
|
||||
Unzip(a, b)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue