2022-08-28 13:07:19 +02:00
|
|
|
use crate::{
|
|
|
|
attr::{fold_attrs, Attr},
|
|
|
|
error::compile_error_at,
|
|
|
|
fields_parse::ParserType,
|
|
|
|
rename_rules::RenameRule,
|
|
|
|
Result,
|
|
|
|
};
|
|
|
|
|
|
|
|
use proc_macro2::Span;
|
|
|
|
use syn::Attribute;
|
|
|
|
|
2022-10-02 16:03:10 +02:00
|
|
|
/// All attributes that can be used for `derive(BotCommands)`
|
2022-08-28 13:07:19 +02:00
|
|
|
pub(crate) struct CommandAttrs {
|
2022-10-02 16:03:10 +02:00
|
|
|
pub prefix: Option<(String, Span)>,
|
|
|
|
pub description: Option<(String, Span)>,
|
|
|
|
pub rename_rule: Option<(RenameRule, Span)>,
|
|
|
|
pub parser: Option<(ParserType, Span)>,
|
|
|
|
pub separator: Option<(String, Span)>,
|
2022-08-28 13:07:19 +02:00
|
|
|
}
|
|
|
|
|
2022-10-02 16:03:10 +02:00
|
|
|
/// A single k/v attribute for `BotCommands` derive macro.
|
|
|
|
///
|
|
|
|
/// For example:
|
|
|
|
/// ```text
|
|
|
|
/// #[command(prefix = "!", rename_rule = "snake_case")]
|
|
|
|
/// /^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^---- CommandAttr { kind: RenameRule(SnakeCase) }
|
|
|
|
/// |
|
|
|
|
/// CommandAttr { kind: Prefix("!") }
|
|
|
|
/// ```
|
|
|
|
struct CommandAttr {
|
2022-08-28 13:07:19 +02:00
|
|
|
kind: CommandAttrKind,
|
|
|
|
sp: Span,
|
|
|
|
}
|
|
|
|
|
2022-10-02 16:03:10 +02:00
|
|
|
/// Kind of [`CommandAttr`].
|
|
|
|
enum CommandAttrKind {
|
2022-08-28 13:07:19 +02:00
|
|
|
Prefix(String),
|
|
|
|
Description(String),
|
2022-10-02 14:24:28 +02:00
|
|
|
RenameRule(RenameRule),
|
2022-08-28 13:07:19 +02:00
|
|
|
ParseWith(ParserType),
|
|
|
|
Separator(String),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CommandAttrs {
|
|
|
|
pub fn from_attributes(attributes: &[Attribute]) -> Result<Self> {
|
|
|
|
use CommandAttrKind::*;
|
|
|
|
|
|
|
|
fold_attrs(
|
|
|
|
attributes,
|
|
|
|
is_command_attribute,
|
|
|
|
CommandAttr::parse,
|
|
|
|
Self {
|
|
|
|
prefix: None,
|
|
|
|
description: None,
|
|
|
|
rename_rule: None,
|
|
|
|
parser: None,
|
|
|
|
separator: None,
|
|
|
|
},
|
|
|
|
|mut this, attr| {
|
|
|
|
fn insert<T>(
|
2022-10-02 16:03:10 +02:00
|
|
|
opt: &mut Option<(T, Span)>,
|
2022-08-28 13:07:19 +02:00
|
|
|
x: T,
|
|
|
|
sp: Span,
|
|
|
|
) -> Result<()> {
|
|
|
|
match opt {
|
|
|
|
slot @ None => {
|
2022-10-02 16:03:10 +02:00
|
|
|
*slot = Some((x, sp));
|
2022-08-28 13:07:19 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
Some(_) => {
|
|
|
|
Err(compile_error_at("duplicate attribute", sp))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match attr.kind {
|
|
|
|
Prefix(p) => insert(&mut this.prefix, p, attr.sp),
|
|
|
|
Description(d) => insert(&mut this.description, d, attr.sp),
|
2022-10-02 14:24:28 +02:00
|
|
|
RenameRule(r) => insert(&mut this.rename_rule, r, attr.sp),
|
2022-08-28 13:07:19 +02:00
|
|
|
ParseWith(p) => insert(&mut this.parser, p, attr.sp),
|
|
|
|
Separator(s) => insert(&mut this.separator, s, attr.sp),
|
|
|
|
}?;
|
|
|
|
|
|
|
|
Ok(this)
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CommandAttr {
|
|
|
|
fn parse(attr: Attr) -> Result<Self> {
|
|
|
|
use CommandAttrKind::*;
|
|
|
|
|
|
|
|
let sp = attr.span();
|
|
|
|
let Attr { key, value } = attr;
|
|
|
|
let kind = match &*key.to_string() {
|
|
|
|
"prefix" => Prefix(value.expect_string()?),
|
|
|
|
"description" => Description(value.expect_string()?),
|
2022-10-02 14:24:28 +02:00
|
|
|
"rename_rule" => RenameRule(
|
|
|
|
value
|
|
|
|
.expect_string()
|
|
|
|
.and_then(|r| self::RenameRule::parse(&r))?,
|
2022-08-28 13:07:19 +02:00
|
|
|
),
|
|
|
|
"parse_with" => {
|
|
|
|
ParseWith(value.expect_string().map(|p| ParserType::parse(&p))?)
|
|
|
|
}
|
|
|
|
"separator" => Separator(value.expect_string()?),
|
|
|
|
_ => {
|
|
|
|
return Err(compile_error_at(
|
|
|
|
"unexpected attribute name (expected one of `prefix`, \
|
|
|
|
`description`, `rename`, `parse_with` and `separator`",
|
|
|
|
key.span(),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Self { kind, sp })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_command_attribute(a: &Attribute) -> bool {
|
|
|
|
match a.path.get_ident() {
|
|
|
|
Some(ident) => ident == "command",
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|