Skip to main content

shrimple_telegram_proc_macro/
lib.rs

1mod request;
2mod r#type;
3mod utils;
4
5use {
6    proc_macro2::{TokenStream, TokenTree},
7    quote_into::ToTokens,
8    std::ops::BitOrAssign,
9    syn::{parse::Parser, spanned::Spanned, Attribute},
10};
11
12fn to_snake_case(src: &str) -> String {
13    let mut res = String::new();
14    for c in src.chars() {
15        if c.is_ascii_uppercase() {
16            if !res.is_empty() {
17                res.push('_');
18            }
19            res.extend(c.to_lowercase().next());
20        } else {
21            res.push(c);
22        }
23    }
24    res
25}
26
27trait ParseAttrMeta: Sized + BitOrAssign {
28    const NAME: &'static str;
29
30    fn parse(tokens: TokenStream) -> syn::Result<Self>;
31    fn from_attr(attr: Attribute) -> RequestAttrParseResult<Self> {
32        if !attr.path.is_ident(Self::NAME) {
33            return RequestAttrParseResult::WrongAttr(attr);
34        }
35
36        let tokens = match attr.tokens.into_iter().next() {
37            Some(TokenTree::Group(group)) => group.stream(),
38            None => TokenStream::new(),
39            Some(x) => {
40                return RequestAttrParseResult::Error(syn::Error::new(
41                    x.span(),
42                    "expected args wrapped in parens",
43                ))
44            }
45        };
46
47        if tokens.is_empty() {
48            return RequestAttrParseResult::Error(syn::Error::new(
49                attr.path.span(),
50                "no arguments found",
51            ));
52        }
53
54        match Self::parse(tokens) {
55            Ok(x) => RequestAttrParseResult::Ok(x),
56            Err(e) => RequestAttrParseResult::Error(e),
57        }
58    }
59
60    fn from_attrs(
61        attrs: impl IntoIterator<Item = Attribute>,
62    ) -> syn::Result<(Vec<Attribute>, Option<Self>)> {
63        let mut res = None;
64        let mut rest = vec![];
65
66        for attr in attrs {
67            match Self::from_attr(attr) {
68                RequestAttrParseResult::WrongAttr(a) => rest.push(a),
69                RequestAttrParseResult::Error(e) => return Err(e),
70                RequestAttrParseResult::Ok(x) => match &mut res {
71                    Some(old_x) => *old_x |= x,
72                    None => res = Some(x),
73                },
74            }
75        }
76
77        Ok((rest, res))
78    }
79}
80
81enum RequestAttrParseResult<T> {
82    WrongAttr(Attribute),
83    Error(syn::Error),
84    Ok(T),
85}
86
87#[proc_macro_attribute]
88pub fn telegram_request(
89    attr: proc_macro::TokenStream,
90    tokens: proc_macro::TokenStream,
91) -> proc_macro::TokenStream {
92    match request::Input::parse(attr.into()).parse(tokens) {
93        Ok(input) => input.to_token_stream(),
94        Err(e) => e.to_compile_error(),
95    }
96    .into()
97}
98
99#[proc_macro_attribute]
100pub fn telegram_type(
101    attr: proc_macro::TokenStream,
102    tokens: proc_macro::TokenStream,
103) -> proc_macro::TokenStream {
104    match r#type::Input::parse(attr.into()).parse(tokens) {
105        Ok(input) => input.to_token_stream(),
106        Err(e) => e.to_compile_error(),
107    }
108    .into()
109}