diff --git a/src/lib.rs b/src/lib.rs index 6996ead..5ff9c9a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,3 @@ -#![feature(try_trait, alloc_layout_extra)] #![forbid(missing_docs)] /*! @@ -172,7 +171,9 @@ impl Drop for OnDrop { } mod boxed; +mod r#try; mod vec; pub use self::boxed::*; +pub use self::r#try::*; pub use self::vec::*; diff --git a/src/try.rs b/src/try.rs new file mode 100644 index 0000000..9acd9e6 --- /dev/null +++ b/src/try.rs @@ -0,0 +1,68 @@ +/// A stable version of [`core::ops::Try`]. +pub trait Try { + /// The type of this value when viewed as successful. + type Ok; + /// The type of this value when viewed as failed. + type Error; + + /// A return of `Ok(t)` means that the + /// execution should continue normally, and the result of `?` is the + /// value `t`. A return of `Err(e)` means that execution should branch + /// to the innermost enclosing `catch`, or return from the function. + fn into_result(self) -> Result; + + /// Wrap an error value to construct the composite result. For example, + /// `Result::Err(x)` and `Result::from_error(x)` are equivalent. + fn from_error(v: Self::Error) -> Self; + + /// Wrap an OK value to construct the composite result. For example, + /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent. + fn from_ok(v: Self::Ok) -> Self; +} + +impl Try for Result { + type Ok = T; + type Error = E; + + fn into_result(self) -> Result<::Ok, ::Error> { + self + } + fn from_error(v: ::Error) -> Self { + Err(v) + } + fn from_ok(v: ::Ok) -> Self { + Ok(v) + } +} + +/// The error type that results from applying the try operator (`?`) to a `None` value. +pub struct NoneError; + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + fn into_result(self) -> Result<::Ok, ::Error> { + self.ok_or(NoneError) + } + fn from_error(_v: ::Error) -> Self { + None + } + fn from_ok(v: ::Ok) -> Self { + Some(v) + } +} + +/// Unwraps a result or propagates its error. +#[macro_export] +macro_rules! r#try { + ($expr:expr) => { + match $crate::Try::into_result($expr) { + Ok(val) => val, + Err(err) => return $crate::Try::from_error(::core::convert::From::from(err)), + } + }; + ($expr:expr,) => { + $crate::r#try!($expr) + }; +} diff --git a/src/vec.rs b/src/vec.rs index 3356f67..1557eac 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -1,8 +1,8 @@ +use std::alloc::Layout; use std::marker::PhantomData; use std::mem::ManuallyDrop; -use std::ops::Try; -use std::alloc::Layout; +use super::{r#try, Try}; mod general_zip; @@ -214,7 +214,7 @@ impl MapIter { // does a pointer walk, easy for LLVM to optimize while self.init_len < self.data.len { unsafe { - let value = f(self.data.ptr.read())?; + let value = r#try!(f(self.data.ptr.read())); (self.data.ptr as *mut U).write(value); @@ -303,7 +303,7 @@ impl ZipWithIter { self.left.ptr = self.left.ptr.add(1); self.right.ptr = self.right.ptr.add(1); - let value = f(left.read(), right.read())?; + let value = r#try!(f(left.read(), right.read())); out.write(value); } diff --git a/src/vec/general_zip.rs b/src/vec/general_zip.rs index 411a900..1b59b7d 100644 --- a/src/vec/general_zip.rs +++ b/src/vec/general_zip.rs @@ -1,9 +1,7 @@ -use super::{Input, Output}; - -#[doc(hidden)] -pub use std::ops::Try; use std::alloc::Layout; +use super::{r#try, Input, Output, Try}; + use seal::Seal; mod seal { use super::*; @@ -402,7 +400,7 @@ impl ZipWithIter { let input = In::next_unchecked(&mut self.input); - self.output.ptr.write(f(input)?); + self.output.ptr.write(r#try!(f(input))); self.output.ptr = self.output.ptr.add(1); }