From 05d36fa6e5d065f81b5f2f6575519f2e5d79862f Mon Sep 17 00:00:00 2001 From: JoJoJet Date: Sun, 12 Dec 2021 16:41:52 -0500 Subject: [PATCH 1/3] perform Ok-wrapping in `try_block` macro --- examples/simple/src/main.rs | 2 +- src/lib.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/simple/src/main.rs b/examples/simple/src/main.rs index bacb8b8..25eb8da 100644 --- a/examples/simple/src/main.rs +++ b/examples/simple/src/main.rs @@ -14,7 +14,7 @@ fn main() { let result: Result<_, ()> = try_block! { let a = do_one(x)?; let b = do_two(a)?; - Ok(b) + b }; println!("{:?}", result); diff --git a/src/lib.rs b/src/lib.rs index fa4f1ff..68a1a20 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ /// Macro to make your error-handling blocks (appear) lambda-less +/// and perform Ok-wrapping on the final value. /// /// #### Before: /// ``` @@ -14,17 +15,16 @@ /// let result: Result = try_block! { /// let a = do_one(x)?; /// let b = do_two(a)?; -/// Ok(b) +/// b /// }; /// ``` #[macro_export] macro_rules! try_block { { $($token:tt)* } => {{ - let l = || { - $($token)* - }; - l() + ( || Ok ( + { $($token)* } + ))() }} } From 1754fd99ea7114a406e2558852951b53e82d0a5a Mon Sep 17 00:00:00 2001 From: JoJoJet Date: Sun, 12 Dec 2021 17:16:30 -0500 Subject: [PATCH 2/3] support `Option` and other arbitrary types for the `try_block` macro Any type which implements the `FromOk` trait can be used in the `try_block` macro. Another candidate for implementation is `std::ops::ControlFlow`. However, that would require bumping the MSV to rust 1.55. --- src/lib.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 68a1a20..4a76f53 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ /// and perform Ok-wrapping on the final value. /// /// #### Before: -/// ``` +/// ```ignore /// let result: Result = || { /// let a = do_one(x)?; /// let b = do_two(a)?; @@ -11,7 +11,7 @@ /// ``` /// /// #### After: -/// ``` +/// ```ignore /// let result: Result = try_block! { /// let a = do_one(x)?; /// let b = do_two(a)?; @@ -22,9 +22,55 @@ #[macro_export] macro_rules! try_block { { $($token:tt)* } => {{ - ( || Ok ( + ( || $crate::FromOk::from_ok( { $($token)* } ))() }} } +/// A type that can Ok-wrap some value, for use in the [`try_block`] macro. +pub trait FromOk { + type Ok; + /// Constructs the wrapped type from an ok value. + fn from_ok(val: Self::Ok) -> Self; +} + +impl FromOk for Result { + type Ok = T; + #[inline] + fn from_ok(val: T) -> Self { + Ok(val) + } +} + +impl FromOk for Option { + type Ok = T; + #[inline] + fn from_ok(val: T) -> Self { + Some(val) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn parse_sum() { + let result: Result<_, std::num::ParseIntError> = try_block! { + let x = "1".parse::()?; + let x = "2".parse::()? + x * 10; + let x = "3".parse::()? + x * 10; + x + }; + assert_eq!(result, Ok(123)); + } + + #[test] + fn option() { + assert_eq!( + Some(520), + try_block! { + "400".parse::().ok()? + "20".parse::().ok()? * "6".parse::().ok()? + }, + ); + } +} From 77a3e85ed5f75f2f11fa8dfb241a0ba6888e3e50 Mon Sep 17 00:00:00 2001 From: JoJoJet Date: Sat, 18 Jun 2022 18:03:31 -0400 Subject: [PATCH 3/3] remove `FromOk` trait using type magic Co-Authored-By: scottmcm <18526288+scottmcm@users.noreply.github.com> --- src/lib.rs | 48 ++++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4a76f53..fb7b845 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,18 @@ +/// 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_block::wrap_ok; +/// let r: Result<_, ()> = wrap_ok!(1); +/// assert_eq!(r, Ok(1)); +/// ``` +#[macro_export] +macro_rules! wrap_ok { + ($e:expr) => {{ + ::std::iter::empty().try_fold($e, |_, x: std::convert::Infallible| match x {}) + }}; +} + /// Macro to make your error-handling blocks (appear) lambda-less /// and perform Ok-wrapping on the final value. /// @@ -11,46 +26,27 @@ /// ``` /// /// #### After: -/// ```ignore +/// ``` +/// # use try_block::try_block; +/// # type T = (); type E = (); +/// # fn do_one((): T) -> Result { Ok(()) } +/// # fn do_two((): T) -> Result { Ok(()) } +/// # let x = (); /// let result: Result = try_block! { /// let a = do_one(x)?; /// let b = do_two(a)?; /// b /// }; /// ``` - #[macro_export] macro_rules! try_block { { $($token:tt)* } => {{ - ( || $crate::FromOk::from_ok( + ( || $crate::wrap_ok!( { $($token)* } ))() }} } -/// A type that can Ok-wrap some value, for use in the [`try_block`] macro. -pub trait FromOk { - type Ok; - /// Constructs the wrapped type from an ok value. - fn from_ok(val: Self::Ok) -> Self; -} - -impl FromOk for Result { - type Ok = T; - #[inline] - fn from_ok(val: T) -> Self { - Ok(val) - } -} - -impl FromOk for Option { - type Ok = T; - #[inline] - fn from_ok(val: T) -> Self { - Some(val) - } -} - #[cfg(test)] mod tests { #[test]