mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-03 09:49:07 +01:00
Clean up attribute handling a bit
This commit is contained in:
parent
ddacee966e
commit
66ad49ab7c
4 changed files with 58 additions and 62 deletions
72
src/attr.rs
72
src/attr.rs
|
@ -1,38 +1,47 @@
|
|||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
punctuated::Punctuated,
|
||||
LitStr, Token,
|
||||
};
|
||||
|
||||
pub(crate) enum BotCommandAttribute {
|
||||
pub(crate) enum CommandAttrName {
|
||||
Prefix,
|
||||
Description,
|
||||
RenameRule,
|
||||
CustomParser,
|
||||
Rename,
|
||||
ParseWith,
|
||||
Separator,
|
||||
}
|
||||
|
||||
impl Parse for BotCommandAttribute {
|
||||
fn parse(input: ParseStream) -> Result<Self, syn::Error> {
|
||||
impl Parse for CommandAttrName {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let name_arg: syn::Ident = input.parse()?;
|
||||
|
||||
match name_arg.to_string().as_str() {
|
||||
"prefix" => Ok(BotCommandAttribute::Prefix),
|
||||
"description" => Ok(BotCommandAttribute::Description),
|
||||
"rename" => Ok(BotCommandAttribute::RenameRule),
|
||||
"parse_with" => Ok(BotCommandAttribute::CustomParser),
|
||||
"separator" => Ok(BotCommandAttribute::Separator),
|
||||
_ => Err(syn::Error::new(name_arg.span(), "unexpected argument")),
|
||||
"prefix" => Ok(CommandAttrName::Prefix),
|
||||
"description" => Ok(CommandAttrName::Description),
|
||||
"rename" => Ok(CommandAttrName::Rename),
|
||||
"parse_with" => Ok(CommandAttrName::ParseWith),
|
||||
"separator" => Ok(CommandAttrName::Separator),
|
||||
_ => Err(syn::Error::new(
|
||||
name_arg.span(),
|
||||
"unexpected attribute name (expected one of `prefix`, \
|
||||
`description`, `rename`, `parse_with`, `separator`",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Attr {
|
||||
name: BotCommandAttribute,
|
||||
value: String,
|
||||
pub(crate) struct CommandAttr {
|
||||
pub name: CommandAttrName,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
impl Parse for Attr {
|
||||
fn parse(input: ParseStream) -> Result<Self, syn::Error> {
|
||||
let name = input.parse::<BotCommandAttribute>()?;
|
||||
impl Parse for CommandAttr {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let name = input.parse::<CommandAttrName>()?;
|
||||
|
||||
// FIXME: this should support value-less attrs, as well as
|
||||
// non-string-literal values
|
||||
input.parse::<Token![=]>()?;
|
||||
let value = input.parse::<LitStr>()?.value();
|
||||
|
||||
|
@ -40,29 +49,20 @@ impl Parse for Attr {
|
|||
}
|
||||
}
|
||||
|
||||
impl Attr {
|
||||
pub fn name(&self) -> &BotCommandAttribute {
|
||||
&self.name
|
||||
}
|
||||
pub(crate) struct CommandAttrs(Punctuated<CommandAttr, Token![,]>);
|
||||
|
||||
pub fn value(&self) -> String {
|
||||
self.value.clone()
|
||||
impl Parse for CommandAttrs {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
input.parse_terminated(CommandAttr::parse).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct VecAttrs {
|
||||
pub data: Vec<Attr>,
|
||||
}
|
||||
impl IntoIterator for CommandAttrs {
|
||||
type Item = CommandAttr;
|
||||
|
||||
impl Parse for VecAttrs {
|
||||
fn parse(input: ParseStream) -> Result<Self, syn::Error> {
|
||||
let mut data = vec![];
|
||||
while !input.is_empty() {
|
||||
data.push(input.parse()?);
|
||||
if !input.is_empty() {
|
||||
input.parse::<Token![,]>()?;
|
||||
}
|
||||
}
|
||||
Ok(Self { data })
|
||||
type IntoIter = syn::punctuated::IntoIter<CommandAttr>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
attr::{Attr, BotCommandAttribute},
|
||||
attr::{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: &[Attr], name: &str) -> Result<Self> {
|
||||
pub fn try_from(attrs: &[CommandAttr], name: &str) -> Result<Self> {
|
||||
let attrs = parse_attrs(attrs)?;
|
||||
let CommandAttrs {
|
||||
prefix,
|
||||
|
@ -65,26 +65,22 @@ pub(crate) struct CommandAttrs {
|
|||
pub separator: Option<String>,
|
||||
}
|
||||
|
||||
pub(crate) fn parse_attrs(attrs: &[Attr]) -> Result<CommandAttrs> {
|
||||
pub(crate) fn parse_attrs(attrs: &[CommandAttr]) -> Result<CommandAttrs> {
|
||||
let mut prefix = None;
|
||||
let mut description = None;
|
||||
let mut rename_rule = RenameRule::Identity;
|
||||
let mut parser = None;
|
||||
let mut separator = None;
|
||||
|
||||
for attr in attrs {
|
||||
match attr.name() {
|
||||
BotCommandAttribute::Prefix => prefix = Some(attr.value()),
|
||||
BotCommandAttribute::Description => {
|
||||
description = Some(attr.value())
|
||||
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::ParseWith => {
|
||||
parser = Some(ParserType::parse(value))
|
||||
}
|
||||
BotCommandAttribute::RenameRule => {
|
||||
rename_rule = RenameRule::parse(&attr.value())?
|
||||
}
|
||||
BotCommandAttribute::CustomParser => {
|
||||
parser = Some(ParserType::parse(&attr.value()))
|
||||
}
|
||||
BotCommandAttribute::Separator => separator = Some(attr.value()),
|
||||
CommandAttrName::Separator => separator = Some(value.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
attr::Attr, command::parse_attrs, fields_parse::ParserType,
|
||||
attr::CommandAttr, 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: &[Attr]) -> Result<Self> {
|
||||
pub fn try_from(attrs: &[CommandAttr]) -> Result<Self> {
|
||||
let attrs = parse_attrs(attrs)?;
|
||||
|
||||
let prefix = attrs.prefix;
|
||||
|
|
18
src/lib.rs
18
src/lib.rs
|
@ -11,7 +11,7 @@ extern crate proc_macro;
|
|||
extern crate quote;
|
||||
extern crate syn;
|
||||
use crate::{
|
||||
attr::{Attr, VecAttrs},
|
||||
attr::{CommandAttr, CommandAttrs},
|
||||
command::Command,
|
||||
command_enum::CommandEnum,
|
||||
fields_parse::{impl_parse_args_named, impl_parse_args_unnamed},
|
||||
|
@ -31,7 +31,7 @@ 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<Attr> = parse_attributes(&input.attrs)?;
|
||||
let enum_attrs: Vec<CommandAttr> = parse_attributes(&input.attrs)?;
|
||||
let command_enum = CommandEnum::try_from(enum_attrs.as_slice())?;
|
||||
|
||||
let variants: Vec<&syn::Variant> = data_enum.variants.iter().collect();
|
||||
|
@ -40,10 +40,10 @@ fn bot_commands_impl(tokens: TokenStream) -> Result<TokenStream, Error> {
|
|||
for variant in variants.iter() {
|
||||
let mut attrs = Vec::new();
|
||||
for attr in &variant.attrs {
|
||||
let mut attrs_ = attr
|
||||
.parse_args::<VecAttrs>()
|
||||
let attrs_ = attr
|
||||
.parse_args::<CommandAttrs>()
|
||||
.map_err(|e| compile_error(e.to_compile_error()))?;
|
||||
attrs.append(attrs_.data.as_mut());
|
||||
attrs.extend(attrs_);
|
||||
}
|
||||
let command =
|
||||
Command::try_from(attrs.as_slice(), &variant.ident.to_string())?;
|
||||
|
@ -183,12 +183,12 @@ fn get_enum_data(input: &DeriveInput) -> Result<&syn::DataEnum> {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_attributes(input: &[syn::Attribute]) -> Result<Vec<Attr>> {
|
||||
fn parse_attributes(input: &[syn::Attribute]) -> Result<Vec<CommandAttr>> {
|
||||
let mut enum_attrs = Vec::new();
|
||||
for attr in input.iter() {
|
||||
match attr.parse_args::<VecAttrs>() {
|
||||
Ok(mut attrs_) => {
|
||||
enum_attrs.append(attrs_.data.as_mut());
|
||||
match attr.parse_args::<CommandAttrs>() {
|
||||
Ok(attrs) => {
|
||||
enum_attrs.extend(attrs);
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(compile_error(e.to_compile_error()));
|
||||
|
|
Loading…
Reference in a new issue