Iterator ftw

This commit is contained in:
Maybe Waffle 2022-08-23 20:37:23 +04:00
parent cfe75ae844
commit f03264e694
4 changed files with 80 additions and 56 deletions

View file

@ -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 {

View file

@ -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(

View file

@ -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
View 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)
}
}