mirror of
https://github.com/teloxide/teloxide.git
synced 2025-03-14 11:44:04 +01:00
Refactor attributes some more
This commit is contained in:
parent
59b8aa21b5
commit
cfe75ae844
4 changed files with 60 additions and 52 deletions
44
src/attr.rs
44
src/attr.rs
|
@ -1,9 +1,10 @@
|
|||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
punctuated::Punctuated,
|
||||
LitStr, Token,
|
||||
parse::{Parse, ParseBuffer, ParseStream},
|
||||
Attribute, LitStr, Token,
|
||||
};
|
||||
|
||||
use crate::Result;
|
||||
|
||||
pub(crate) enum CommandAttrName {
|
||||
Prefix,
|
||||
Description,
|
||||
|
@ -49,20 +50,47 @@ impl Parse for CommandAttr {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CommandAttrs(Punctuated<CommandAttr, Token![,]>);
|
||||
pub(crate) struct CommandAttrs(Vec<CommandAttr>);
|
||||
|
||||
impl Parse for CommandAttrs {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
input.parse_terminated(CommandAttr::parse).map(Self)
|
||||
impl CommandAttrs {
|
||||
pub fn from_attributes(attributes: &[Attribute]) -> Result<Self> {
|
||||
let mut attrs = Vec::new();
|
||||
|
||||
for attribute in attributes.iter().filter(is_command_attribute) {
|
||||
let attrs_ = attribute.parse_args_with(|input: &ParseBuffer| {
|
||||
input.parse_terminated::<_, Token![,]>(CommandAttr::parse)
|
||||
})?;
|
||||
|
||||
attrs.extend(attrs_);
|
||||
}
|
||||
|
||||
Ok(Self(attrs))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a CommandAttrs {
|
||||
type Item = &'a CommandAttr;
|
||||
|
||||
type IntoIter = std::slice::Iter<'a, CommandAttr>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for CommandAttrs {
|
||||
type Item = CommandAttr;
|
||||
|
||||
type IntoIter = syn::punctuated::IntoIter<CommandAttr>;
|
||||
type IntoIter = std::vec::IntoIter<CommandAttr>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
fn is_command_attribute(a: &&Attribute) -> bool {
|
||||
match a.path.get_ident() {
|
||||
Some(ident) => ident == "command",
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
attr::{CommandAttr, CommandAttrName},
|
||||
attr::{self, CommandAttr, CommandAttrName},
|
||||
command_enum::CommandEnum,
|
||||
fields_parse::ParserType,
|
||||
rename_rules::RenameRule,
|
||||
|
@ -14,7 +14,7 @@ pub(crate) struct Command {
|
|||
}
|
||||
|
||||
impl Command {
|
||||
pub fn try_from(attrs: &[CommandAttr], name: &str) -> Result<Self> {
|
||||
pub fn try_from(attrs: attr::CommandAttrs, name: &str) -> Result<Self> {
|
||||
let attrs = parse_attrs(attrs)?;
|
||||
let CommandAttrs {
|
||||
prefix,
|
||||
|
@ -65,7 +65,7 @@ pub(crate) struct CommandAttrs {
|
|||
pub separator: Option<String>,
|
||||
}
|
||||
|
||||
pub(crate) fn parse_attrs(attrs: &[CommandAttr]) -> Result<CommandAttrs> {
|
||||
pub(crate) fn parse_attrs(attrs: attr::CommandAttrs) -> Result<CommandAttrs> {
|
||||
let mut prefix = None;
|
||||
let mut description = None;
|
||||
let mut rename_rule = RenameRule::Identity;
|
||||
|
@ -74,13 +74,13 @@ pub(crate) fn parse_attrs(attrs: &[CommandAttr]) -> Result<CommandAttrs> {
|
|||
|
||||
for CommandAttr { name, value } in attrs {
|
||||
match name {
|
||||
CommandAttrName::Prefix => prefix = Some(value.clone()),
|
||||
CommandAttrName::Description => description = Some(value.clone()),
|
||||
CommandAttrName::Rename => rename_rule = RenameRule::parse(value)?,
|
||||
CommandAttrName::Prefix => prefix = Some(value),
|
||||
CommandAttrName::Description => description = Some(value),
|
||||
CommandAttrName::Rename => rename_rule = RenameRule::parse(&value)?,
|
||||
CommandAttrName::ParseWith => {
|
||||
parser = Some(ParserType::parse(value))
|
||||
parser = Some(ParserType::parse(&value))
|
||||
}
|
||||
CommandAttrName::Separator => separator = Some(value.clone()),
|
||||
CommandAttrName::Separator => separator = Some(value),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
attr::CommandAttr, command::parse_attrs, fields_parse::ParserType,
|
||||
attr, command::parse_attrs, fields_parse::ParserType,
|
||||
rename_rules::RenameRule, Result,
|
||||
};
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub(crate) struct CommandEnum {
|
|||
}
|
||||
|
||||
impl CommandEnum {
|
||||
pub fn try_from(attrs: &[CommandAttr]) -> Result<Self> {
|
||||
pub fn try_from(attrs: attr::CommandAttrs) -> Result<Self> {
|
||||
let attrs = parse_attrs(attrs)?;
|
||||
|
||||
let prefix = attrs.prefix;
|
||||
|
|
48
src/lib.rs
48
src/lib.rs
|
@ -11,7 +11,7 @@ extern crate proc_macro;
|
|||
extern crate quote;
|
||||
extern crate syn;
|
||||
use crate::{
|
||||
attr::{CommandAttr, CommandAttrs},
|
||||
attr::CommandAttrs,
|
||||
command::Command,
|
||||
command_enum::CommandEnum,
|
||||
fields_parse::{impl_parse_args_named, impl_parse_args_unnamed},
|
||||
|
@ -31,28 +31,23 @@ 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 enum_attrs: Vec<CommandAttr> = parse_attributes(&input.attrs)?;
|
||||
let command_enum = CommandEnum::try_from(enum_attrs.as_slice())?;
|
||||
let enum_attrs = CommandAttrs::from_attributes(&input.attrs)?;
|
||||
let command_enum = CommandEnum::try_from(enum_attrs)?;
|
||||
|
||||
let variants: Vec<&syn::Variant> = data_enum.variants.iter().collect();
|
||||
let variant_infos = data_enum
|
||||
.variants
|
||||
.iter()
|
||||
.map(|variant| {
|
||||
let attrs = CommandAttrs::from_attributes(&variant.attrs)?;
|
||||
let command = Command::try_from(attrs, &variant.ident.to_string())?;
|
||||
|
||||
let mut variant_infos = vec![];
|
||||
for variant in variants.iter() {
|
||||
let mut attrs = Vec::new();
|
||||
for attr in &variant.attrs {
|
||||
let attrs_ = attr
|
||||
.parse_args::<CommandAttrs>()
|
||||
.map_err(|e| compile_error(e.to_compile_error()))?;
|
||||
attrs.extend(attrs_);
|
||||
}
|
||||
let command =
|
||||
Command::try_from(attrs.as_slice(), &variant.ident.to_string())?;
|
||||
|
||||
variant_infos.push(command);
|
||||
}
|
||||
Ok(command)
|
||||
})
|
||||
.collect::<Result<Vec<_>, Error>>()?;
|
||||
|
||||
let mut vec_impl_create = vec![];
|
||||
for (variant, info) in variants.iter().zip(variant_infos.iter()) {
|
||||
|
||||
for (variant, info) in data_enum.variants.iter().zip(variant_infos.iter()) {
|
||||
let var = &variant.ident;
|
||||
let variant_ = quote! { Self::#var };
|
||||
match &variant.fields {
|
||||
|
@ -182,18 +177,3 @@ fn get_enum_data(input: &DeriveInput) -> Result<&syn::DataEnum> {
|
|||
_ => Err(compile_error("TelegramBotCommand allowed only for enums")),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_attributes(input: &[syn::Attribute]) -> Result<Vec<CommandAttr>> {
|
||||
let mut enum_attrs = Vec::new();
|
||||
for attr in input.iter() {
|
||||
match attr.parse_args::<CommandAttrs>() {
|
||||
Ok(attrs) => {
|
||||
enum_attrs.extend(attrs);
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(compile_error(e.to_compile_error()));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(enum_attrs)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue