telegram_bot2_macros/
lib.rs

1use crate::bot_main::try_bot_main;
2use crate::builder::try_derive_builder;
3use crate::command::try_command;
4use crate::command::try_commands;
5use crate::daemon::{try_daemon, try_daemons};
6use crate::file_holder::try_derive_file_holder;
7use crate::handler::{try_handler, try_handlers};
8use proc_macro::TokenStream;
9use proc_macro_error::proc_macro_error;
10
11mod bot_main;
12mod builder;
13mod command;
14mod constants;
15mod daemon;
16mod file_holder;
17mod handler;
18
19/// Creates a builder for the structure.
20/// It will have the following properties:
21/// - A new() function, with parameters for each non-optional field of the structure
22/// - A method for each optional parameter to initialize that field. It returns self to allow chained calls
23#[proc_macro_derive(Builder)]
24#[proc_macro_error]
25pub fn derive_buildable(item: TokenStream) -> TokenStream {
26    try_derive_builder(item).unwrap()
27}
28
29/// Builds a main around the function.
30/// It should return a BotBuilder, which will be launched by the main.
31///
32/// The return type of the function does not have to be specified and can be `_`
33///
34/// ## Example
35/// ```
36/// #[bot]
37/// async fn bot() -> _ {
38///     BotBuilder::new()
39///         .interval(Duration::from_secs(0))
40///         .timeout(5)
41///         .handler(handlers![handler])
42///         .commands(commands![soup])
43/// }
44/// ```
45#[proc_macro_attribute]
46#[proc_macro_error]
47pub fn bot(attr: TokenStream, item: TokenStream) -> TokenStream {
48    try_bot_main(attr, item).unwrap()
49}
50
51/// Define a command handler
52///
53/// It requires a single parameter, a string literal for the syntax of the command. It should have the following format: `"/command [static|<dynamic>]"`
54///
55/// ## Static parameters
56/// Static parameters must be exact matches, at the specified position
57///
58/// ## Dynamic parameters
59/// Dynamic parameters are surrounded by angle brackets in the syntax. They are parsed from the command message and passed to the handler.
60///
61/// The handler function must have parameters with the same names. They are parsed using the [FromStr](std::str::FromStr) trait.
62///
63/// The Option and Vec types have specific behaviors:\
64/// They must appear in the following order in the syntax : Neither => Option => Vec (once)\
65/// When all classic parameters are parsed, if they are remaining arguments in the command call, they are parsed regarding the contained type of the options/vec (in order)
66///
67/// ## Example
68/// ```
69/// #[bot_command("/soup <id>")]
70/// async fn soup(bot: &Bot, chat: ChatId, id: i64) -> Result<(), ()> {
71///     bot.send_message(SendMessageBuilder::new(chat, format!("Soup {} requested", id)).build()).await.unwrap();
72///     Ok(())
73/// }
74/// ```
75///
76/// ### Option
77/// Given the following handler:
78/// ```
79/// #[bot_command("/soup <id> <name>")]
80/// async fn soup(bot: &Bot, chat: ChatId, id: Option<i64>, name: Option<String>) -> Result<(), ()> {
81///     bot.send_message(SendMessageBuilder::new(chat, format!("Soup {}@{} requested", name.unwrap_or("None".to_string()), id.unwrap_or(0))).build()).await.unwrap();
82///     Ok(())
83/// }
84/// ```
85/// Issuing the command `/soup 10 roulottes` will result in the message `"Soup roulottes@10 requested"`, while `"/soup 10"` will yield `"Soup None@10 requested"`. `"/soup roulottes"` won't be parsed successfully
86#[proc_macro_attribute]
87#[proc_macro_error]
88pub fn command(attr: TokenStream, item: TokenStream) -> TokenStream {
89    try_command(attr, item).unwrap()
90}
91
92/// Return a map of commands to be used by `BotBuilder::commands`
93#[proc_macro]
94#[proc_macro_error]
95pub fn commands(item: TokenStream) -> TokenStream {
96    try_commands(item).unwrap()
97}
98
99#[proc_macro_derive(FileHolder)]
100#[proc_macro_error]
101pub fn derive_file_holder(item: TokenStream) -> TokenStream {
102    try_derive_file_holder(item).unwrap()
103}
104/// Creates a generic update handler for the function
105///
106/// All parameters must implement the FromUpdate trait
107///
108/// The macro may take those parameters:
109/// - `rank`(usize):  the priority of this handler, 0 being the lowest
110/// - `restrict` (list of `UpdateType`): the updates that may be passed to the handler
111#[proc_macro_attribute]
112#[proc_macro_error]
113pub fn handler(attr: TokenStream, item: TokenStream) -> TokenStream {
114    try_handler(attr, item).unwrap()
115}
116
117/// Returns the handler for the given function
118#[proc_macro]
119#[proc_macro_error]
120pub fn handlers(item: TokenStream) -> TokenStream {
121    try_handlers(item).unwrap()
122}
123
124/// You can setup daemons that run in the background and have access to the BotState. Daemon function are annotated with [`#[daemon]`][macro@crate::daemon] and require a `interval` parameter, which specifies the time between two calls (in seconds).
125///
126/// The interval time is the time between calls, it does not starts at the end of the last call. For example, if the interval is set to 60s and the daemon takes 5s to complete, the next call will proceeds 55s after the first one ends.\
127/// The timer is precise at a millisecond order. If no interval is specified, the daemon is ran once at the start of the bot (useful for dynamically scheduled tasks).
128///
129/// The parameters of the function are parsed by the `FromDaemon` trait, at each call
130/// ```rust
131/// #[daemon(interval = 5)]
132/// async fn hello(state: &BotState<Mutex<usize>>) {
133///     let mut lock = state.lock().unwrap();
134///     *lock += 1;
135///     println!("Increasing counter to {}", lock);
136/// }
137/// ```
138#[proc_macro_attribute]
139#[proc_macro_error]
140pub fn daemon(attr: TokenStream, item: TokenStream) -> TokenStream {
141    try_daemon(attr, item).unwrap()
142}
143
144/// Returns the daemons associated to the given functions
145#[proc_macro]
146#[proc_macro_error]
147pub fn daemons(item: TokenStream) -> TokenStream {
148    try_daemons(item).unwrap()
149}