Refactor attributes some more

This commit is contained in:
Maybe Waffle 2022-08-22 18:59:25 +04:00
parent 59b8aa21b5
commit cfe75ae844
4 changed files with 60 additions and 52 deletions

View file

@ -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,
}
}

View file

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

View file

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

View file

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