molt_ng/
macros.rs

1//! Convenience Macros
2//!
3//! This module contains macros for use by command authors.
4
5/// Returns an `Ok` `MoltResult`.
6///
7/// If called with no arguments, returns an empty value as the `Ok` result.
8/// If called with one argument, returns the argument as the `Ok` result, converting it
9/// to a value automatically.
10/// If called with two or more arguments, computes the `Ok` result using
11/// `format!()`; the first argument is naturally the format string.
12///
13/// # Examples
14///
15/// ```
16/// use molt::*;
17///
18/// // Return the empty result
19/// fn func1() -> MoltResult {
20///     // ...
21///     molt_ok!()
22/// }
23///
24/// assert_eq!(func1(), Ok(Value::empty()));
25///
26/// // Return an arbitrary value
27/// fn func2() -> MoltResult {
28///     // ...
29///     molt_ok!(17)
30/// }
31///
32/// assert_eq!(func2(), Ok(17.into()));
33///
34/// // Return a formatted value
35/// fn func3() -> MoltResult {
36///     // ...
37///     molt_ok!("The answer is {}", 17)
38/// }
39///
40/// assert_eq!(func3(), Ok("The answer is 17".into()));
41/// ```
42#[macro_export]
43macro_rules! molt_ok {
44    () => (
45        Ok($crate::Value::empty())
46    );
47    ($arg:expr) => (
48        Ok($crate::Value::from($arg))
49    );
50    ($($arg:tt)*) => (
51        Ok($crate::Value::from(format!($($arg)*)))
52    )
53}
54
55/// Returns an `Error` `MoltResult`.  The error message is formatted
56/// as with `format!()`.
57///
58/// If called with one argument, the single argument is used as the error message.
59/// If called with more than one argument, the first is a `format!()` format string,
60/// and the remainder are the values to format.
61///
62/// This macro wraps the [`Exception::molt_err`](types/struct.Exception.html#method.molt_err)
63/// method.
64///
65/// # Examples
66///
67/// ```
68/// use molt::*;
69///
70/// // Return a simple error message
71/// fn err1() -> MoltResult {
72///     // ...
73///     molt_err!("error message")
74/// }
75///
76/// let result = err1();
77/// assert!(result.is_err());
78///
79/// let exception = result.err().unwrap();
80/// assert!(exception.is_error());
81/// assert_eq!(exception.value(), "error message".into());
82///
83/// // Return a formatted error
84/// fn err2() -> MoltResult {
85///    // ...
86///    molt_err!("invalid value: {}", 17)
87/// }
88///
89/// let result = err2();
90/// assert!(result.is_err());
91///
92/// let exception = result.err().unwrap();
93/// assert!(exception.is_error());
94/// assert_eq!(exception.value(), "invalid value: 17".into());
95/// ```
96#[macro_export]
97macro_rules! molt_err {
98    ($arg:expr) => (
99        Err($crate::Exception::molt_err($crate::Value::from($arg)))
100    );
101    ($($arg:tt)*) => (
102        Err($crate::Exception::molt_err($crate::Value::from(format!($($arg)*))))
103    )
104}
105
106/// Returns an `Error` `MoltResult` with a specific error code.  The error message is formatted
107/// as with `format!()`.
108///
109/// The macro requires two or more arguments.  The first argument is always the error code.
110/// If called with two arguments, the second is the error message.
111/// If called with more than two arguments, the second is a `format!()` format string and
112/// the remainder are the values to format.
113///
114/// This macro wraps
115/// the [`Exception::molt_err2`](types/struct.Exception.html#method.molt_err2)
116/// method.
117///
118/// # Examples
119///
120/// ```
121/// use molt::*;
122///
123/// // Throw a simple error
124/// fn throw1() -> MoltResult {
125///     // ...
126///     molt_throw!("MYCODE", "error message")
127/// }
128///
129/// let result = throw1();
130/// assert!(result.is_err());
131///
132/// let exception = result.err().unwrap();
133/// assert!(exception.is_error());
134/// assert_eq!(exception.value(), "error message".into());
135/// assert_eq!(exception.error_code(), "MYCODE".into());
136///
137/// // Return a formatted error
138/// fn throw2() -> MoltResult {
139///    // ...
140///    molt_throw!("MYCODE", "invalid value: {}", 17)
141/// }
142///
143/// let result = throw2();
144/// assert!(result.is_err());
145///
146/// let exception = result.err().unwrap();
147/// assert!(exception.is_error());
148/// assert_eq!(exception.value(), "invalid value: 17".into());
149/// assert_eq!(exception.error_code(), "MYCODE".into());
150/// ```
151#[macro_export]
152macro_rules! molt_throw {
153    ($code:expr, $msg:expr) => (
154        Err($crate::Exception::molt_err2($crate::Value::from($code), $crate::Value::from($msg)))
155    );
156    ($code:expr, $($arg:tt)*) => (
157        Err($crate::Exception::molt_err2($crate::Value::from($code), $crate::Value::from(format!($($arg)*))))
158    )
159}
160
161#[cfg(test)]
162mod tests {
163    use crate::*;
164
165    #[test]
166    fn test_molt_ok() {
167        let result: MoltResult = molt_ok!();
168        assert_eq!(Ok(Value::empty()), result);
169
170        let result: MoltResult = molt_ok!(5);
171        assert_eq!(Ok(Value::from(5)), result);
172
173        let result: MoltResult = molt_ok!("Five");
174        assert_eq!(Ok(Value::from("Five")), result);
175
176        let result: MoltResult = molt_ok!("The answer is {}.", 5);
177        assert_eq!(Ok(Value::from("The answer is 5.")), result);
178    }
179
180    #[test]
181    fn test_molt_err() {
182        check_err(molt_err!("error message"), "error message");
183        check_err(molt_err!("error {}", 5), "error 5");
184    }
185
186    #[test]
187    fn test_molt_throw() {
188        check_throw(
189            molt_throw!("MYERR", "error message"),
190            "MYERR",
191            "error message",
192        );
193        check_throw(molt_throw!("MYERR", "error {}", 5), "MYERR", "error 5");
194    }
195
196    fn check_err(result: MoltResult, msg: &str) -> bool {
197        match result {
198            Err(exception) => exception.is_error() && exception.value() == msg.into(),
199            _ => false,
200        }
201    }
202
203    fn check_throw(result: MoltResult, code: &str, msg: &str) -> bool {
204        match result {
205            Err(exception) => {
206                exception.is_error()
207                    && exception.value() == msg.into()
208                    && exception.error_code() == code.into()
209            }
210            _ => false,
211        }
212    }
213}