#[doc(hidden)]
#[macro_export]
macro_rules! em_if {
( $i:expr, $p:pat, $t:expr, $f:expr ) => {
if let $p = $i {
$t
} else {
$f
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! get {
( $i:expr, $p:path, $pp:tt, $r:expr ) => {
$crate::em_if!($i, $p$pp, Some($r), None)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! is {
( $i:expr, $p:path, $pp:tt, $r:expr ) => {
$crate::em_if!($i, $p$pp, true, false)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! map {
( $i:ident, $p:path, $pp:tt, $r:expr, $f:expr ) => {
$crate::em_if!($i, $p$pp, $p($f($r)), $i)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! and_then {
( $i:ident, $p:path, $pp:tt, ($($r:ident,)+), $f:expr ) => {
$crate::em_if!($i, $p$pp, $f($($r,)+), $i)
};
( $i:ident, $p:path, $pp:tt, $r:ident, $f:expr ) => {
$crate::em_if!($i, $p$pp, $f($r), $i)
};
}
#[macro_export]
macro_rules! em {
( $i:ident.$m:ident $p:path $(> $($a:expr),+)? ) => {
$crate::$m!($i, $p, (_x), _x $(, $($a),+)?)
};
( $i:ident.$m:ident $p:path[$(..)?] $(> $($a:expr),+)? ) => {
$crate::$m!($i, $p, (..), () $(, $($a),+)?)
};
( $i:ident.$m:ident $p:path[$($x:ident),+] $(> $($a:expr),+)? ) => {
$crate::$m!($i, $p, ($($x,)+), ($($x,)+) $(, $($a),+)?)
};
( $i:ident.$m:ident $p:path{$($($x:ident),+$(,)?)? $(..)?} $(> $($a:expr),+)? ) => {
$crate::$m!($i, $p, { $($($x,)+)? .. }, ($($($x,)+)?) $(, $($a),+)?)
};
( $i:expr => $m:ident $p:path $(> $($a:expr),+)? ) => {
$crate::$m!($i, $p, (_x), _x $(, $($a),+)?)
};
( $i:expr => $m:ident $p:path[$(..)?] $(> $($a:expr),+)? ) => {
$crate::$m!($i, $p, (..), () $(, $($a),+)?)
};
( $i:expr => $m:ident $p:path[$($x:ident),+] $(> $($a:expr),+)? ) => {
$crate::$m!($i, $p, ($($x,)+), ($($x,)+) $(, $($a),+)?)
};
( $i:expr => $m:ident $p:path{$($($x:ident),+$(,)?)? $(..)?} $(> $($a:expr),+)? ) => {
$crate::$m!($i, $p, { $($($x,)+)? .. }, ($($($x,)+)?) $(, $($a),+)?)
};
}
#[cfg(test)]
mod tests {
#[derive(Debug, PartialEq)]
enum Enum {
A(i32),
B(i32, i32),
C { x: i32, y: i32 },
}
fn init() -> (Enum, Enum, Enum) {
let a = Enum::A(1);
let b = Enum::B(2, 3);
let c = Enum::C { x: 4, y: 5 };
(a, b, c)
}
#[test]
fn get() {
let (a, b, c) = init();
assert_eq!(em!(a.get Enum::A), Some(1));
assert_eq!(em!(Enum::A(1) => get Enum::A), Some(1));
assert_eq!(em!(b.get Enum::B[i, j]), Some((2, 3)));
assert_eq!(em!(c.get Enum::C{x, y}), Some((4, 5)));
assert_eq!(em!(c.get Enum::C{x, ..}), Some((4,)));
}
#[test]
fn not_get() {
let (a, b, c) = init();
assert_eq!(em!(a.get Enum::C{x, y}), None);
assert_eq!(em!(b.get Enum::A), None);
assert_eq!(em!(c.get Enum::B[i, j]), None);
}
#[test]
fn is() {
let (a, b, c) = init();
assert_eq!(em!(a.is Enum::A), true);
assert_eq!(em!(b.is Enum::B[]), true);
assert_eq!(em!(c.is Enum::C{}), true);
}
#[test]
fn isnt() {
let (a, b, c) = init();
assert_eq!(em!(a.is Enum::C{}), false);
assert_eq!(em!(b.is Enum::A), false);
assert_eq!(em!(c.is Enum::B[]), false);
}
#[test]
fn map() {
let (a, b, _c) = init();
assert_eq!(em!(a.map Enum::A > |x| x + 1), Enum::A(2));
assert_eq!(em!(b.map Enum::A > |x| x + 1), Enum::B(2, 3));
}
#[test]
fn and_then() {
let (a, b, c) = init();
assert_eq!(
em!(a.and_then Enum::A > |x| Enum::B(x + 1, 0)),
Enum::B(2, 0)
);
assert_eq!(
em!(b.and_then Enum::B[x, y] > |x, y| Enum::C {x, y}),
Enum::C { x: 2, y: 3 }
);
assert_eq!(
em!(c.and_then Enum::A > |x| Enum::B(x - 1, 0)),
Enum::C { x: 4, y: 5 }
);
}
}