Skip to main content

rustigram_macros/
lib.rs

1#![warn(missing_docs)]
2//! Procedural macros for the rustigram framework.
3//!
4//! - [`handler`] — marks an async function as a rustigram handler
5//! - [`DialogueState`] — derive macro for FSM state enums
6
7use proc_macro::TokenStream;
8use quote::quote;
9use syn::{parse_macro_input, ItemFn};
10
11/// Marks an async function as a rustigram handler.
12///
13/// Generates an impl of the `Handler` trait and a `handler_fn` wrapper.
14///
15/// # Example
16///
17/// ```rust,ignore
18/// #[rustigram::handler]
19/// async fn start(ctx: Context) -> BotResult<()> {
20///     ctx.reply("Hello!").unwrap().await?;
21///     Ok(())
22/// }
23/// ```
24#[proc_macro_attribute]
25pub fn handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
26    let input = parse_macro_input!(item as ItemFn);
27    let name = &input.sig.ident;
28    let block = &input.block;
29    let _inputs = &input.sig.inputs;
30    let _asyncness = &input.sig.asyncness;
31
32    let expanded = quote! {
33        #[allow(non_camel_case_types)]
34        pub struct #name;
35
36        impl rustigram_bot::handler::Handler for #name {
37            fn handle<'life0, 'async_trait>(
38                &'life0 self,
39                ctx: rustigram_bot::Context,
40            ) -> ::std::pin::Pin<Box<dyn ::std::future::Future<Output = rustigram_bot::BotResult<()>> + Send + 'async_trait>>
41            where
42                'life0: 'async_trait,
43                Self: 'async_trait,
44            {
45                Box::pin(async move {
46                    let ctx = ctx;
47                    #block
48                })
49            }
50        }
51    };
52
53    TokenStream::from(expanded)
54}
55
56/// Derives a typed FSM state enum for use with `DialogueStorage`.
57///
58/// # Example
59///
60/// ```rust,ignore
61/// #[derive(DialogueState, Clone)]
62/// pub enum OrderState {
63///     Start,
64///     AwaitingName,
65///     AwaitingAddress { name: String },
66///     Confirming { name: String, address: String },
67/// }
68/// ```
69#[proc_macro_derive(DialogueState)]
70pub fn dialogue_state_derive(input: TokenStream) -> TokenStream {
71    let input = parse_macro_input!(input as syn::DeriveInput);
72    let name = &input.ident;
73
74    let expanded = quote! {
75        impl #name {
76            /// Returns the type name of this dialogue state as a static string.
77            pub fn type_name() -> &'static str {
78                stringify!(#name)
79            }
80        }
81    };
82
83    TokenStream::from(expanded)
84}