unreact/
macros.rs

1/// Create a json-like 'object':
2/// A map of string keys to json values
3///
4/// `unreact::Object` is a type alias for `serde_json::Map<String, serde_json::Value>`
5///
6/// Similar to `serde_json::json!` macro, but must be an object
7///
8/// # Examples
9///
10/// ```
11/// # use unreact::object;
12/// let my_key = "Hello!";
13/// object! {
14///     foo: 123,
15///     bar: vec![4, 5, 6],
16///     // Use variable with same name as key
17///     my_key,
18///     // Nested objects must also use `object!` macro
19///     nested: object! {
20///         key: "value"
21///     }
22/// };
23/// ```
24///
25/// The above code is equivalent to this json:
26///
27/// ```json
28/// {
29///     "foo": 123,
30///     "bar": [4, 5, 6],
31///     "my_key": "Hello!",
32///     "nested": {
33///         "key": "value"
34///     }
35/// }
36/// ```
37#[macro_export]
38macro_rules! object {
39    // Empty object
40    {} => { $crate::Object::new() };
41
42    // Object
43    {
44        $( $key: ident $(: $value: expr)? ),* $(,)?
45    } => {{
46        let mut hm = $crate::Object::new();
47        $(
48            object!(@entry hm, $key $(: $value)?);
49        )*
50        hm
51    }};
52
53    // Key, no value
54    (@entry $hm: expr,
55        $key: ident
56    ) => {
57        $hm.insert(String::from(stringify!($key)), $crate::json!($key));
58    };
59
60    // Key and value
61    (@entry $hm: expr,
62        $key: ident : $value: expr
63    ) => {
64        $hm.insert(String::from(stringify!($key)), $crate::json!($value));
65    };
66}
67
68/// Private macro
69///
70/// Try to unwrap a `Result`, returns value in `Ok` variant
71///
72/// If result is `Err`, then run code block
73/// Similar to a `let else` statement, but captures the value inside the `Err` variant
74macro_rules! try_unwrap {
75    (
76        $option: expr,
77        else Err($err: ident) => $block: block
78        $(,)?
79    ) => {
80        match $option {
81            Ok(value) => value,
82            Err($err) => $block,
83        }
84    };
85
86    (
87        $option: expr,
88        else Err($err: ident) => $stmt: stmt
89        $(,)?
90    ) => {
91        match $option {
92            Ok(value) => value,
93            // Brackets cannot be removed
94            #[rustfmt::skip] Err($err) => { $stmt },
95        }
96    };
97}
98
99/// Private macro
100///
101/// Shorthand for `Err(crate::Error...)`
102macro_rules! fail {
103    ( $kind: ident ) => {
104        Err($crate::Error::$kind)
105    };
106    ( $kind: ident, $( $arg: expr ),* ) => {
107        Err($crate::Error::$kind( $( $arg ),* ))
108    };
109}
110
111/// Private macro
112///
113/// Shorthand for `Err(crate::Error::IoFail(crate::IoError...))`
114macro_rules! io_fail {
115    ( $kind: ident ) => {
116        Err($crate::Error::IoFail($crate::IoError::$kind))
117    };
118    ( $kind: ident, $( $arg: expr ),* ) => {
119        Err($crate::Error::IoFail($crate::IoError::$kind( $( $arg ),* )))
120    };
121}
122
123#[cfg(test)]
124mod tests {
125    use crate::{Object, Value};
126
127    #[test]
128    fn object_macro_works() {
129        let my_key = "hello!";
130
131        let mut obj = Object::new();
132        obj.insert("abc".to_string(), Value::from(123));
133        obj.insert("array".to_string(), Value::from(vec![4, 5, 6]));
134        obj.insert("my_key".to_string(), Value::from(my_key));
135
136        assert_eq!(
137            object! {
138                abc: 123,
139                array: Value::from(vec![4, 5, 6]),
140                my_key,
141            },
142            obj
143        );
144
145        let mut obj = Object::new();
146        obj.insert("abc".to_string(), Value::from("abcdef"));
147
148        let mut obj2 = Object::new();
149        obj2.insert("ghi".to_string(), Value::from(456));
150
151        obj.insert("def".to_string(), Value::Object(obj2));
152
153        assert_eq!(
154            object! {
155                abc: Value::from("abcdef"),
156                def: Value::from(object!{
157                    ghi: 456,
158                }),
159            },
160            obj
161        );
162    }
163
164    #[test]
165    fn try_unwrap_works() {
166        let result: Result<i32, &str> = Ok(123);
167        let value = try_unwrap!( result,
168            else Err(_err) => {
169                panic!("Should not be Err")
170            }
171        );
172        assert_eq!(value, 123);
173
174        let result: Result<i32, &str> = Err("oh no!");
175        let value = try_unwrap!( result,
176            else Err(_err) => {
177                456
178            }
179        );
180        assert_eq!(value, 456);
181
182        let result: Result<i32, &str> = Err("oh no!");
183        let _value = try_unwrap!( result,
184            else Err(_err) => {
185                return;
186            }
187        );
188        panic!("Should not have been Ok");
189    }
190}