capnweb_client/
macros.rs

1//! Procedural macros for ergonomic recorder usage
2
3/// Macro for creating parameter sources with less boilerplate
4///
5/// # Example
6///
7/// ```rust
8/// use capnweb_client::params;
9/// let args = params![5, "hello", true];
10/// ```
11#[macro_export]
12macro_rules! params {
13    [$($expr:expr),* $(,)?] => {
14        vec![$(
15            $crate::recorder::Param::value(serde_json::json!($expr))
16        ),*]
17    };
18}
19
20/// Macro for object construction with natural syntax
21///
22/// # Example
23///
24/// ```rust
25/// use capnweb_client::{record_object, Recorder};
26/// use capnweb_core::CapId;
27/// let recorder = Recorder::new();
28/// let cap = recorder.capture("api", CapId::new(1));
29/// let name_result = cap.call("getName", vec![]);
30/// let age_result = cap.call("getAge", vec![]);
31/// let obj = record_object!(recorder; {
32///     "name" => name_result,
33///     "age" => age_result,
34/// });
35/// ```
36#[macro_export]
37macro_rules! record_object {
38    ($recorder:expr; { $($key:expr => $value:expr),* $(,)? }) => {{
39        let mut fields = std::collections::BTreeMap::new();
40        $(
41            fields.insert($key.to_string(), $value.as_source());
42        )*
43        $recorder.object(fields)
44    }};
45}
46
47/// Macro for array construction with natural syntax
48///
49/// # Example
50///
51/// ```rust
52/// use capnweb_client::{record_array, Recorder};
53/// use capnweb_core::CapId;
54/// let recorder = Recorder::new();
55/// let cap = recorder.capture("api", CapId::new(1));
56/// let item1 = cap.call("getValue", vec![]);
57/// let item2 = cap.call("getValue", vec![]);
58/// let arr = record_array!(recorder; [item1, item2]);
59/// ```
60#[macro_export]
61macro_rules! record_array {
62    ($recorder:expr; [$($item:expr),* $(,)?]) => {{
63        let items = vec![$($item.as_source()),*];
64        $recorder.array(items)
65    }};
66}
67
68/// Macro for creating recorded plans with fluent syntax
69///
70/// # Example
71///
72/// ```rust
73/// use capnweb_client::{record_plan, Recorder, params};
74/// use capnweb_core::CapId;
75/// let cap_id = CapId::new(1);
76/// let plan = record_plan! {
77///     {
78///         let recorder = Recorder::new();
79///         let calc = recorder.capture("calculator", cap_id);
80///         let sum = calc.call("add", params![5, 3]);
81///         recorder.build(sum.as_source())
82///     }
83/// };
84/// ```
85#[macro_export]
86macro_rules! record_plan {
87    ($body:expr) => {
88        $body
89    };
90}
91
92#[cfg(test)]
93mod tests {
94    use crate::recorder::Recorder;
95    use capnweb_core::CapId;
96
97    #[test]
98    fn test_params_macro() {
99        let args = params![5, "hello", true];
100        assert_eq!(args.len(), 3);
101    }
102
103    #[test]
104    fn test_record_object_macro() {
105        let recorder = Recorder::new();
106        let cap = recorder.capture("api", CapId::new(1));
107        let name = cap.call("getName", vec![]);
108        let age = cap.call("getAge", vec![]);
109
110        let obj = record_object!(recorder; {
111            "name" => name,
112            "age" => age,
113        });
114
115        // Verify the object was created
116        let plan = recorder.build(obj.as_source());
117        assert_eq!(plan.ops.len(), 3); // 2 calls + 1 object
118    }
119
120    #[test]
121    fn test_record_array_macro() {
122        let recorder = Recorder::new();
123        let cap = recorder.capture("api", CapId::new(1));
124        let item1 = cap.call("getValue", params![1]);
125        let item2 = cap.call("getValue", params![2]);
126
127        let arr = record_array!(recorder; [item1, item2]);
128
129        let plan = recorder.build(arr.as_source());
130        assert_eq!(plan.ops.len(), 3); // 2 calls + 1 array
131    }
132
133    #[test]
134    fn test_complex_recording() {
135        let recorder = Recorder::new();
136
137        // Simulate a complex plan
138        let calc = recorder.capture("calculator", CapId::new(1));
139        let api = recorder.capture("api", CapId::new(2));
140
141        let sum = calc.call("add", params![5, 3]);
142        let user = api.call("getUser", params![123]);
143        let name = user.call("getName", vec![]);
144
145        let result = record_object!(recorder; {
146            "sum" => sum,
147            "userName" => name,
148        });
149
150        let plan = recorder.build(result.as_source());
151        assert_eq!(plan.captures.len(), 2);
152        assert_eq!(plan.ops.len(), 4); // 3 calls + 1 object
153    }
154}