enum_macro/
lib.rs

1//! Use `use enum_macro::em;` or `#[macro_use(em)]`
2//! to import `em!` macro,.
3//!
4//! Notice: DO NOT import all macro,
5//! there's are some helper macro in the crate.
6//!
7//! For more information about usage, see [em]
8
9#[doc(hidden)]
10#[macro_export]
11macro_rules! em_if {
12    ( $i:expr, $p:pat, $t:expr, $f:expr ) => {
13        if let $p = $i {
14            $t
15        } else {
16            $f
17        }
18    };
19}
20
21#[doc(hidden)]
22#[macro_export]
23macro_rules! get {
24    ( $i:expr, $p:path, $pp:tt, $r:expr ) => {
25        $crate::em_if!($i, $p$pp, Some($r), None)
26    };
27    ( $i:expr, $p:path ) => {
28        $crate::em_if!($i, $p, Some(()), None)
29    };
30}
31
32#[doc(hidden)]
33#[macro_export]
34macro_rules! is {
35    ( $i:expr, $p:path, $pp:tt, $r:expr ) => {
36        $crate::em_if!($i, $p$pp, true, false)
37    };
38    ( $i:expr, $p:path ) => {
39        $crate::em_if!($i, $p, true, false)
40    };
41}
42
43#[doc(hidden)]
44#[macro_export]
45macro_rules! map {
46    ( $i:ident, $p:path, $pp:tt, $r:expr, $f:expr ) => {
47        $crate::em_if!($i, $p$pp, $p($f($r)), $i)
48    };
49}
50
51#[doc(hidden)]
52#[macro_export]
53macro_rules! and_then {
54    ( $i:ident, $p:path, $pp:tt, ($($r:ident,)+), $f:expr ) => {
55        $crate::em_if!($i, $p$pp, $f($($r,)+), $i)
56    };
57    ( $i:ident, $p:path, $pp:tt, $r:ident, $f:expr ) => {
58        $crate::em_if!($i, $p$pp, $f($r), $i)
59    };
60}
61
62/// enum helper macro
63///
64/// ```
65/// use enum_macro::em;
66///
67/// #[derive(Clone, Debug, PartialEq)]
68/// enum Enum {
69///     A(i32),
70///     B(i32, i32),
71///     C { x: i32, y: i32 },
72///     D, // Note: Unit variant must follow by '|'
73/// }
74///
75/// let a = Enum::A(1);
76/// let b = Enum::B(2, 3);
77/// let c = Enum::C { x: 4, y: 5 };
78/// let d = Enum::D;
79///
80/// // Get Inner Value
81///
82/// assert_eq!(em!(a.get Enum::A), Some(1));
83/// assert_eq!(em!(Enum::A(1) => get Enum::A), Some(1));
84/// assert_eq!(em!(b.get Enum::B[i, j]), Some((2, 3)));
85/// assert_eq!(em!(c.get Enum::C{x, y}), Some((4, 5)));
86/// assert_eq!(em!(c.get Enum::C{y, x}), Some((5, 4)));
87/// assert_eq!(em!(c.get Enum::C{x, ..}), Some((4,)));
88/// assert_eq!(em!(d.get Enum::D|), Some(())); // Unit variant must follow by '|'
89/// assert_eq!(em!(Enum::D => get Enum::D|), Some(()));
90///
91/// // Variants Detect
92///
93/// assert_eq!(em!(a.is Enum::A), true);
94/// assert_eq!(em!(Enum::A(1) => is Enum::A), true);
95///
96/// assert_eq!(em!(b.is Enum::C{x, y}), false);
97/// // or
98/// assert_eq!(em!(b.is Enum::C{..}), false);
99/// // or
100/// assert_eq!(em!(b.is Enum::C{}), false);
101///
102/// assert_eq!(em!(c.is Enum::B[i, j]), false);
103/// // or
104/// assert_eq!(em!(c.is Enum::B[..]), false);
105/// // or
106/// assert_eq!(em!(c.is Enum::B[]), false);
107///
108/// assert_eq!(em!(d.is Enum::D|), true); // Unit variant must follow by '|'
109/// // or
110/// assert_eq!(em!(Enum::D => is Enum::D|), true); // Unit variant must follow by '|'
111///
112/// // Map
113///
114/// let a2 = a.clone();
115/// let b2 = b.clone();
116/// assert_eq!(em!(a2.map Enum::A > |x| x + 1), Enum::A(2));
117/// assert_eq!(em!(b2.map Enum::A > |x| x + 1), Enum::B(2, 3));
118///
119/// // And Then
120///
121/// let a2 = a.clone();
122/// assert_eq!(em!(a2.and_then Enum::A > |x| Enum::B(x + 1, 0)), Enum::B(2, 0));
123///
124/// let b2 = b.clone();
125/// assert_eq!(em!(b2.and_then Enum::B[x, y] > |x, y| Enum::C {x, y}), Enum::C { x: 2, y: 3 });
126///
127/// let b2 = b.clone();
128/// // only care order
129/// assert_eq!(em!(b2.and_then Enum::B[x, y] > |i, j| Enum::C {x: i, y: j}), Enum::C { x: 2, y: 3 });
130/// ```
131#[macro_export]
132macro_rules! em {
133    ( $i:ident.$m:ident $p:path $(> $($a:expr),+)? ) => {
134        $crate::$m!($i, $p, (_x), _x $(, $($a),+)?)
135    };
136    ( $i:ident.$m:ident $p:path[$(..)?] $(> $($a:expr),+)? ) => {
137        $crate::$m!($i, $p, (..), () $(, $($a),+)?)
138    };
139    ( $i:ident.$m:ident $p:path[$($x:ident),+] $(> $($a:expr),+)? ) => {
140        $crate::$m!($i, $p, ($($x,)+), ($($x,)+) $(, $($a),+)?)
141    };
142    ( $i:ident.$m:ident $p:path{$($($x:ident),+$(,)?)? $(..)?} $(> $($a:expr),+)? ) => {
143        $crate::$m!($i, $p, { $($($x,)+)? .. }, ($($($x,)+)?) $(, $($a),+)?)
144    };
145    ( $i:expr => $m:ident $p:path $(> $($a:expr),+)? ) => {
146        $crate::$m!($i, $p, (_x), _x $(, $($a),+)?)
147    };
148    ( $i:expr => $m:ident $p:path[$(..)?] $(> $($a:expr),+)? ) => {
149        $crate::$m!($i, $p, (..), () $(, $($a),+)?)
150    };
151    ( $i:expr => $m:ident $p:path[$($x:ident),+] $(> $($a:expr),+)? ) => {
152        $crate::$m!($i, $p, ($($x,)+), ($($x,)+) $(, $($a),+)?)
153    };
154    ( $i:expr => $m:ident $p:path{$($($x:ident),+$(,)?)? $(..)?} $(> $($a:expr),+)? ) => {
155        $crate::$m!($i, $p, { $($($x,)+)? .. }, ($($($x,)+)?) $(, $($a),+)?)
156    };
157    ( $i:ident.$m:ident $p:path| $(> $($a:expr),+)? ) => {
158        $crate::$m!($i, $p $(, $($a),+)?)
159    };
160    ( $i:expr => $m:ident $p:path| $(> $($a:expr),+)? ) => {
161        $crate::$m!($i, $p $(, $($a),+)?)
162    };
163}
164
165#[cfg(test)]
166mod tests {
167    #[derive(Debug, PartialEq)]
168    enum Enum {
169        A(i32),
170        B(i32, i32),
171        C { x: i32, y: i32 },
172        D,
173    }
174
175    fn init() -> (Enum, Enum, Enum) {
176        let a = Enum::A(1);
177        let b = Enum::B(2, 3);
178        let c = Enum::C { x: 4, y: 5 };
179        (a, b, c)
180    }
181
182    #[test]
183    fn get() {
184        let (a, b, c) = init();
185        let d = Enum::D;
186        assert_eq!(em!(a.get Enum::A), Some(1));
187        assert_eq!(em!(Enum::A(1) => get Enum::A), Some(1));
188        assert_eq!(em!(b.get Enum::B[i, j]), Some((2, 3)));
189        assert_eq!(em!(c.get Enum::C{x, y}), Some((4, 5)));
190        assert_eq!(em!(c.get Enum::C{x, ..}), Some((4,)));
191        assert_eq!(em!(d.get Enum::D|), Some(()));
192        assert_eq!(em!(Enum::D => get Enum::D|), Some(()));
193    }
194
195    #[test]
196    fn not_get() {
197        let (a, b, c) = init();
198        assert_eq!(em!(a.get Enum::C{x, y}), None);
199        assert_eq!(em!(b.get Enum::A), None);
200        assert_eq!(em!(c.get Enum::B[i, j]), None);
201        assert_eq!(em!(Enum::A(1) => get Enum::D|), None);
202    }
203
204    #[test]
205    fn is() {
206        let (a, b, c) = init();
207        let d = Enum::D;
208        assert_eq!(em!(a.is Enum::A), true);
209        assert_eq!(em!(b.is Enum::B[]), true);
210        assert_eq!(em!(c.is Enum::C{}), true);
211        assert_eq!(em!(d.is Enum::D|), true);
212    }
213
214    #[test]
215    fn isnt() {
216        let (a, b, c) = init();
217        let d = Enum::D;
218        assert_eq!(em!(a.is Enum::D|), false);
219        assert_eq!(em!(b.is Enum::A), false);
220        assert_eq!(em!(c.is Enum::B[]), false);
221        assert_eq!(em!(d.is Enum::C{}), false);
222    }
223
224    #[test]
225    fn map() {
226        let (a, b, _c) = init();
227        assert_eq!(em!(a.map Enum::A > |x| x + 1), Enum::A(2));
228        assert_eq!(em!(b.map Enum::A > |x| x + 1), Enum::B(2, 3));
229    }
230
231    #[test]
232    fn and_then() {
233        let (a, b, c) = init();
234        assert_eq!(
235            em!(a.and_then Enum::A > |x| Enum::B(x + 1, 0)),
236            Enum::B(2, 0)
237        );
238        assert_eq!(
239            em!(b.and_then Enum::B[x, y] > |x, y| Enum::C {x, y}),
240            Enum::C { x: 2, y: 3 }
241        );
242        assert_eq!(
243            em!(c.and_then Enum::A > |x| Enum::B(x - 1, 0)),
244            Enum::C { x: 4, y: 5 }
245        );
246    }
247}