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}