Skip to main content

layer_client/
macros.rs

1//! The [`dispatch!`] macro — ergonomic, pattern-matching update handler.
2//!
3//! Instead of writing giant `match` blocks, `dispatch!` lets you register
4//! named handlers with optional guard clauses:
5//!
6//! ```rust,no_run
7//! use layer_client::{Client, dispatch};
8//! use layer_client::update::Update;
9//!
10//! # async fn example(client: Client, update: Update) -> Result<(), Box<dyn std::error::Error>> {
11//! dispatch!(client, update,
12//!     NewMessage(msg) if !msg.outgoing() => {
13//!         println!("Got: {:?}", msg.text());
14//!     },
15//!     MessageEdited(msg) => {
16//!         println!("Edited: {:?}", msg.text());
17//!     },
18//!     CallbackQuery(cb) => {
19//!         client.answer_callback_query(cb.query_id, Some("✓"), false).await?;
20//!     },
21//!     _ => {} // catch-all for unhandled variants
22//! );
23//! # Ok(()) }
24//! ```
25//!
26//! Each arm is `VariantName(binding) [if guard] => { body }`.
27//! The macro expands to a plain `match` statement — zero overhead.
28
29/// Route a [`crate::update::Update`] to the first matching arm.
30///
31/// # Syntax
32/// ```text
33/// dispatch!(client, update,
34///     VariantName(binding) [if guard] => { body },
35///     ...
36///     [_ => { fallback }]
37/// );
38/// ```
39///
40/// - `client`  — a `layer_client::Client` (available inside every arm body)
41/// - `update`  — the `Update` value to dispatch
42/// - Each arm mirrors a variant of [`crate::update::Update`]
43/// - Guards (`if expr`) are optional
44/// - A catch-all `_ => {}` arm is optional but recommended to avoid warnings
45#[macro_export]
46macro_rules! dispatch {
47    // Entry point: client, update, then one or more arms
48    ($client:expr, $update:expr, $( $pattern:tt )+ ) => {
49        match $update {
50            $crate::__dispatch_arms!($client; $( $pattern )+ )
51        }
52    };
53}
54
55/// Internal helper — do not use directly.
56#[macro_export]
57#[doc(hidden)]
58macro_rules! __dispatch_arms {
59    // Catch-all arm
60    ($client:expr; _ => $body:block $( , $( $rest:tt )* )? ) => {
61        _ => $body
62    };
63
64    // Variant arm WITH guard
65    ($client:expr;
66        $variant:ident ( $binding:pat ) if $guard:expr => $body:block
67        $( , $( $rest:tt )* )?
68    ) => {
69        $crate::update::Update::$variant($binding) if $guard => $body,
70        $( $crate::__dispatch_arms!($client; $( $rest )* ) )?
71    };
72
73    // Variant arm WITHOUT guard
74    ($client:expr;
75        $variant:ident ( $binding:pat ) => $body:block
76        $( , $( $rest:tt )* )?
77    ) => {
78        $crate::update::Update::$variant($binding) => $body,
79        $( $crate::__dispatch_arms!($client; $( $rest )* ) )?
80    };
81
82    // Trailing comma / empty — emit wildcard to ensure exhaustiveness
83    ($client:expr; $(,)?) => {
84        _ => {}
85    };
86}