shrimple_telegram_proc_macro/
lib.rs1mod 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}