1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
#[macro_export] macro_rules! or { ($head:expr $(=> $tail:expr)*) => ( $head $( .or_else(|| $tail) )* ) } #[macro_export] macro_rules! and { ($head:expr $(=> $tail:expr)*) => ( ( || -> Option<_> { Some(($head?, $($tail? ),*)) } )() ) } #[macro_export] macro_rules! try_opt { ($($body:stmt);*) => ( ( || -> Option<_> { Some({$($body);*}) } )() ) } #[cfg(test)] mod tests { #[test] fn or_works() { assert_eq!(Some(1), or!(Some(1) => Some(2) => Some(3))); assert_eq!(Some(2), or!(None => Some(2) => Some(3))); assert_eq!(Some(3), or!(None => None => Some(3))); assert_eq!(None::<()>, or!(None => None => None)); } #[test] fn and_works() { assert_eq!(Some((1, 2, 3)), and!(Some(1) => Some(2) => Some(3))); assert_eq!(None, and!(None => Some(2) => Some(3))); assert_eq!(None, and!(None => None => Some(3))); assert_eq!(None, and!(None => None => None)); } struct Config { log: Option<LogConfig>, } struct LogConfig { level: Option<String>, } #[test] fn try_works() { assert_eq!( Some(6), try_opt! { let x = Some(3); let y = Some(2); x? * y? } ); let config = Config { log: Some(LogConfig { level: Some("debug".to_owned()), }), }; let x = try_opt! { config.log?.level? }.unwrap_or("foo".to_owned()); assert_eq!(x, "debug"); } }