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 80 81 82 83 84 85 86 87 88 89 90 91 92 93
#![no_std]
//! Macro for stable try blocks that performs Ok-wrapping, and otherwise tries to
//! achieve feature parity with RFC 1859. The macro is compatible with any type
//! that implements the unstable `Any` trait through the use of type magic.
//!
//! This crate is a fork of `try-block`, which has not been updated in four years at
//! the time of writing this. This fork adds Ok-wrapping and the promise of future
//! updates.
//!
//! This crate is `no_std` compatible.
/// Macro for ok-wrapping any `Try` type. This works on stable through dark type magic.
///
/// Note that type inference is very finicky; you should give this a type ascription ASAP.
/// ```
/// # use try_blocks::wrap_ok;
/// let r: Result<_, ()> = wrap_ok!(1);
/// assert_eq!(r, Ok(1));
/// ```
#[macro_export]
macro_rules! wrap_ok {
($e:expr) => {{
::core::iter::empty().try_fold($e, |_, x: core::convert::Infallible| match x {})
}};
}
/// Macro for the recieving end of a `?` operation.
/// Right now, type inference is quite finicky so you usually have to declare a concrete type somewhere.
///
/// ```
/// # use try_blocks::try_block;
/// // Note: this fails without explicitly specifying the error type.
/// let y: Result<_, std::num::ParseIntError> = try_block! {
/// "1".parse::<i32>()? + "2".parse::<i32>()?
/// };
/// # assert_eq!(y, Ok(3));
/// ```
/// ## Alternative
/// The only other way to emulate try blocks is with closures, which is very ugly.
///
/// #### Before:
/// ```ignore
/// let result: Result<T, E> = (|| {
/// let a = do_one(x)?;
/// let b = do_two(a)?;
/// Ok(b)
/// })();
/// ```
///
/// #### After:
/// ```
/// # use try_blocks::try_block;
/// # type T = (); type E = ();
/// # fn do_one((): T) -> Result<T, E> { Ok(()) }
/// # fn do_two((): T) -> Result<T, E> { Ok(()) }
/// # let x = ();
/// let result: Result<T, E> = try_block! {
/// let a = do_one(x)?;
/// let b = do_two(a)?;
/// b
/// };
/// ```
#[macro_export]
macro_rules! try_block {
{ $($token:tt)* } => {{
( || $crate::wrap_ok!(
{ $($token)* }
))()
}}
}
#[cfg(test)]
mod tests {
#[test]
fn parse_sum() {
let result: Result<_, core::num::ParseIntError> = try_block! {
let x = "1".parse::<i32>()?;
let x = "2".parse::<i32>()? + x * 10;
"3".parse::<i32>()? + x * 10
};
assert_eq!(result, Ok(123));
}
#[test]
fn option() {
assert_eq!(
Some(520),
try_block! {
"400".parse::<i32>().ok()? + "20".parse::<i32>().ok()? * "6".parse::<i32>().ok()?
},
);
}
}