modulink_rs/macros.rs
1//! Modulink-RS Macro Implementations
2//
3// This file implements all macros and patterns described in the macro reference and documentation.
4// Each macro is annotated with usage and rationale. See docs/MODULINK_MACROS.md for details.
5
6// ---
7// 1. Context Macro
8//
9// Purpose: Define or initialize a context (can be `Context`, `MutableContext`, or custom type).
10//
11/*
12/// Macro to define a context struct with named fields.
13///
14/// # Example
15/// ```rust
16/// define_context! {
17/// user_id: u64,
18/// data: String,
19/// }
20/// let ctx = Context::new();
21/// ```
22///
23/// Use this macro to quickly define a context type for your chain.
24#[macro_export]
25macro_rules! define_context {
26 ( $( $field:ident : $ty:ty ),* $(,)? ) => {
27 #[derive(Debug, Clone, Default)]
28 pub struct Context {
29 $( pub $field: $ty, )*
30 }
31 impl Context {
32 pub fn new() -> Self { Self { $( $field: Default::default(), )* } }
33 }
34 };
35}
36*/
37
38// ---
39// 2. Link Macro
40//
41// Purpose: Define a link as a pure async function or closure.
42//
43/*
44/// Macro to define a link as a pure async function or closure.
45///
46/// # Function-style Example
47/// ```rust
48/// link! {
49/// fn add_user_id(ctx: Context) -> Context {
50/// ctx.insert("user_id", 42)
51/// }
52/// }
53/// ```
54///
55/// # Closure-style Example
56/// ```rust
57/// let link = link!(|ctx: Context| async move { ctx.insert("user_id", 42) });
58/// ```
59///
60/// Use this macro to define composable steps in your chain.
61#[macro_export]
62macro_rules! link {
63 // Function-style link
64 (fn $name:ident ( $ctx:ident : $ctx_ty:ty ) -> $ret:ty $body:block) => {
65 pub async fn $name($ctx: $ctx_ty) -> $ret $body
66 };
67 // Closure-style link
68 (|$ctx:ident : $ctx_ty:ty| $body:expr) => {
69 Box::new(move |$ctx: $ctx_ty| Box::pin(async move { $body }))
70 };
71}
72*/
73
74// ---
75// 3. Chain Macro (active)
76//
77// Purpose: Compose a sequence of links into a chain.
78//
79/// Macro to compose a sequence of links into a chain.
80///
81/// # Example
82/// ```rust
83/// use modulink_rs::chain;
84/// use std::sync::Arc;
85/// use std::future::Future;
86/// use std::pin::Pin;
87/// use modulink_rs::context::Context;
88/// // Example async link type for Chain
89/// let link1: Arc<dyn Fn(Context) -> Pin<Box<dyn Future<Output = Context> + Send>> + Send + Sync> = Arc::new(|ctx: Context| Box::pin(async move { ctx }));
90/// let link2 = link1.clone();
91/// let link3 = link1.clone();
92/// // Comma-separated syntax
93/// let my_chain = chain!(link1.clone(), link2.clone(), link3.clone());
94/// // Array-like syntax
95/// let my_chain2 = chain![link1.clone(), link2.clone(), link3.clone()];
96/// // my_chain can now be executed with .run(ctx).await
97/// ```
98///
99/// Use this macro to build a pipeline of links.
100#[macro_export]
101macro_rules! chain {
102 // Generic: explicit type parameter (array syntax)
103 [type = $ty:ty; $( $link:expr ),* $(,)? ] => {
104 {
105 let mut c = ::modulink_rs::chains::ChainGeneric::<$ty>::new();
106 $( c.add_link($link); )*
107 c
108 }
109 };
110 // Generic: explicit type parameter (comma syntax)
111 (type = $ty:ty; $( $link:expr ),* $(,)? ) => {
112 {
113 let mut c = ::modulink_rs::chains::ChainGeneric::<$ty>::new();
114 $( c.add_link($link); )*
115 c
116 }
117 };
118 // Ergonomic: default Context (comma-separated list)
119 ( $( $link:expr ),* $(,)? ) => {
120 {
121 let mut c = ::modulink_rs::chains::Chain::new();
122 $( c.add_link($link); )*
123 c
124 }
125 };
126 // Ergonomic: default Context (array-like syntax)
127 [ $( $link:expr ),* $(,)? ] => {
128 {
129 let mut c = ::modulink_rs::chains::Chain::new();
130 $( c.add_link($link); )*
131 c
132 }
133 };
134}
135
136// ---
137// 4. Add Link Macro (method pattern)
138//
139// Purpose: Add a link to an existing chain.
140//
141// Usage:
142// my_chain.add_link(link!(|ctx| async move { ctx }));
143//
144// Rationale: Enables dynamic or incremental chain construction.
145
146// ---
147// 5. Use Middleware Macro (method pattern)
148//
149// Purpose: Attach middleware for logging, metrics, or side effects.
150//
151// Usage:
152// my_chain.use_middleware(middleware!(Logging));
153//
154// Rationale: Middleware provides observability and cross-cutting concerns.
155
156// ---
157// 6. Connect Macro (Branching)
158//
159// Purpose: Add conditional branches between links or chains, using a macro syntax that clarifies intent and supports both link and chain connections.
160//
161/*
162/// Macro to add conditional branches between links or chains.
163///
164/// # Syntax
165/// - Connect a link:
166/// ```rust
167/// my_chain.connect![
168/// link: my_link,
169/// to: link_in_og_chain,
170/// when: condition!(|ctx| ctx.get::<bool>("skip").unwrap_or(false)),
171/// ]
172/// ```
173/// - Connect a chain:
174/// ```rust
175/// my_chain.connect![
176/// chain: my_other_chain,
177/// to: link_in_og_chain,
178/// when: condition!(|ctx| ctx.get::<bool>("should_branch").unwrap_or(false)),
179/// ]
180/// ```
181///
182/// Use this macro to enable advanced graph topologies, error routing, and dynamic control flow.
183#[macro_export]
184macro_rules! connect {
185 (
186 link: $link:expr,
187 to: $to:expr,
188 when: $when:expr $(,)?
189 ) => {
190 .connect_link($link, $to, $when)
191 };
192 (
193 chain: $chain:expr,
194 to: $to:expr,
195 when: $when:expr $(,)?
196 ) => {
197 .connect_chain($chain, $to, $when)
198 };
199}
200*/
201
202// ---
203// 7. Run Macro (method pattern)
204//
205// Purpose: Execute the chain with a given context.
206//
207// Usage:
208// let result = my_chain.run(ctx).await;
209//
210// Rationale: Runs the pipeline. Async for concurrency.
211
212// ---
213// 8. Condition Macro
214//
215// Purpose: Define a branching condition as a closure.
216//
217/*
218/// Macro to define a branching condition as a closure.
219///
220/// # Example
221/// ```rust
222/// let cond = condition!(|ctx: &Context| ctx.get::<bool>("flag").unwrap_or(false));
223/// ```
224///
225/// Use this macro for branching and control flow in chains.
226#[macro_export]
227macro_rules! condition {
228 (|$ctx:ident : $ctx_ty:ty| $body:expr) => {
229 Box::new(move |$ctx: &$ctx_ty| $body)
230 };
231 (|$ctx:ident| $body:expr) => {
232 Box::new(move |$ctx| $body)
233 };
234}
235*/
236
237// ---
238// 9. Middleware Macro
239//
240// Purpose: Define custom middleware with before/after hooks.
241//
242/*
243/// Macro to define custom middleware with before/after hooks.
244///
245/// # Example
246/// ```rust
247/// middleware! {
248/// struct MyLogger;
249/// impl Middleware for MyLogger {
250/// async fn before(&self, ctx: &dyn std::any::Any) {
251/// println!("Before link");
252/// }
253/// async fn after(&self, ctx: &dyn std::any::Any) {
254/// println!("After link");
255/// }
256/// }
257/// }
258/// ```
259///
260/// Use this macro to add observability, metrics, or side effects.
261#[macro_export]
262macro_rules! middleware {
263 // Struct + impl block
264 (struct $name:ident; impl Middleware for $name2:ident { $($body:tt)* }) => {
265 pub struct $name;
266 #[async_trait::async_trait]
267 impl ::modulink_rs::middleware::Middleware for $name2 {
268 $($body)*
269 }
270 };
271}
272*/
273
274// ---
275// 10. Listener Macro
276//
277// Purpose: Define a listener for triggers (HTTP, CLI, etc.).
278//
279/*
280/// Macro to define a listener for triggers (HTTP, CLI, etc.).
281///
282/// # Example
283/// ```rust
284/// listener! {
285/// struct MyHttpListener;
286/// // ... implement listener trait ...
287/// }
288/// ```
289///
290/// Use this macro to integrate chains with external systems.
291#[macro_export]
292macro_rules! listener {
293 (struct $name:ident; $($body:tt)*) => {
294 pub struct $name;
295 $($body)*
296 };
297}
298*/
299
300// ---
301// Notes:
302// - All macros are sketches; adapt as needed for your codebase.
303// - Use shadowing (`let ctx = ...`) for ergonomic APIs; use `mut` only for advanced/generic APIs and document the tradeoff.
304// - Maximize type safety, extensibility, and modularity as God wills.
305// - See docs/CHAIN_MACRO_PATTERNS.md and docs/CHEATSHEET_ADVANCED.md for more.