diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 0dfdabee03182..c3ef619d739c0 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -146,7 +146,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use iter::{FromIterator, FusedIterator, TrustedLen}; -use {mem, ops}; +use {mem, ops::{self, Deref}}; // Note that this is not a lang item per se, but it has a hidden dependency on // `Iterator`, which is one. The compiler assumes that the `next` method of @@ -914,7 +914,6 @@ fn expect_failed(msg: &str) -> ! { panic!("{}", msg) } - ///////////////////////////////////////////////////////////////////////////// // Trait implementations ///////////////////////////////////////////////////////////////////////////// @@ -979,6 +978,24 @@ impl From for Option { } } +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +/// Extension trait to get a reference of an Option via the Deref trait. +pub trait OptionDeref { + /// Converts from `&Option` to `Option<&T::Target>`. + /// + /// Leaves the original Option in-place, creating a new one with a reference + /// to the original one, additionally coercing the contents via `Deref`. + fn deref(&self) -> Option<&T::Target>; +} + +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +impl OptionDeref for Option +{ + fn deref(&self) -> Option<&T::Target> { + self.as_ref().map(|t| t.deref()) + } +} + ///////////////////////////////////////////////////////////////////////////// // The Option Iterators ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/result.rs b/src/libcore/result.rs index c152d4979b90e..9877a2001a0ff 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -242,7 +242,7 @@ use fmt; use iter::{FromIterator, FusedIterator, TrustedLen}; -use ops; +use ops::{self, Deref}; /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). /// @@ -999,6 +999,63 @@ impl<'a, T, E> IntoIterator for &'a mut Result { } } +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +/// Extension trait to get a reference to a Result via the Deref trait. +pub trait ResultDeref { + /// Converts from `&Result` to `Result<&T::Target, &E>`. + /// + /// Leaves the original Result in-place, creating a new one with a reference + /// to the original one, additionally coercing the `Ok` arm of the Result via + /// `Deref`. + fn deref_ok(&self) -> Result<&T::Target, &E> + where + T: Deref; + + /// Converts from `&Result` to `Result<&T, &E::Target>`. + /// + /// Leaves the original Result in-place, creating a new one with a reference + /// to the original one, additionally coercing the `Err` arm of the Result via + /// `Deref`. + fn deref_err(&self) -> Result<&T, &E::Target> + where + E: Deref; + + /// Converts from `&Result` to `Result<&T::Target, &E::Target>`. + /// + /// Leaves the original Result in-place, creating a new one with a reference + /// to the original one, additionally coercing both the `Ok` and `Err` arms + /// of the Result via `Deref`. + fn deref(&self) -> Result<&T::Target, &E::Target> + where + T: Deref, + E: Deref; +} + +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +impl ResultDeref for Result { + fn deref_ok(&self) -> Result<&T::Target, &E> + where + T: Deref, + { + self.as_ref().map(|t| t.deref()) + } + + fn deref_err(&self) -> Result<&T, &E::Target> + where + E: Deref, + { + self.as_ref().map_err(|e| e.deref()) + } + + fn deref(&self) -> Result<&T::Target, &E::Target> + where + T: Deref, + E: Deref, + { + self.as_ref().map(|t| t.deref()).map_err(|e| e.deref()) + } +} + ///////////////////////////////////////////////////////////////////////////// // The Result Iterators ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index 22109e28edd9b..77d550c532a34 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -297,3 +297,14 @@ fn test_try() { } assert_eq!(try_option_err(), Err(NoneError)); } + +#[test] +fn test_option_deref() { + // Some: &Option::Some(T) -> Option<&T::Deref::Target>::Some(&*T) + let ref_option = &Some(&42); + assert_eq!(ref_option.deref(), Some(&42)); + + // None: &Option>::None -> None + let ref_option = &None; + assert_eq!(ref_option.deref(), None); +} diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index ce41bde8342ed..dd23467322dc9 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -231,3 +231,24 @@ fn test_try() { } assert_eq!(try_result_err(), Err(1)); } + +#[test] +fn test_result_deref() { + // Ok(T).deref_ok() -> Result<&T, &E::Deref::Target>::Ok(&T) + let ref_ok: &Result<&i32, &u8> = &Ok(&42); + assert_eq!(ref_ok.deref_ok(), Ok(&42)); + assert_eq!(ref_ok.deref_ok(), Ok(&42)); + assert_eq!(ref_ok.deref(), Ok(&42)); + + // Err(E) -> Result<&T, &E::Deref::Target>::Err(&*E) + let ref_err: &Result<&i32, &u8> = &Err(&41); + assert_eq!(ref_err.deref_err(), Err(&41)); + assert_eq!(ref_err.deref_err(), Err(&41)); + assert_eq!(ref_err.deref(), Err(&41)); + + // &Ok(T).deref_err() -> Result<&T, &E::Deref::Target>::Ok(&T) + assert_eq!(ref_ok.deref_err(), Ok(&&42)); + + // &Err(E) -> Result<&T::Deref::Target, &E>::Err(&E) + assert_eq!(ref_err.deref_ok(), Err(&&41)); +}