Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement inner deref for Option and Result #50267

Merged
merged 11 commits into from
Jul 31, 2018
Next Next commit
added DerefOption and DerefResult + tests to std
  • Loading branch information
Xandkeeper committed Apr 27, 2018
commit 4c2e3144a98f7a636fd6a33fce122121431ad9b4
21 changes: 19 additions & 2 deletions src/libcore/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -914,7 +914,6 @@ fn expect_failed(msg: &str) -> ! {
panic!("{}", msg)
}


/////////////////////////////////////////////////////////////////////////////
// Trait implementations
/////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -979,6 +978,24 @@ impl<T> From<T> for Option<T> {
}
}

#[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<T: Deref> {
/// Converts from `&Option<T>` 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<T: Deref> OptionDeref<T> for Option<T>
{
fn deref(&self) -> Option<&T::Target> {
self.as_ref().map(|t| t.deref())
}
}

/////////////////////////////////////////////////////////////////////////////
// The Option Iterators
/////////////////////////////////////////////////////////////////////////////
Expand Down
59 changes: 58 additions & 1 deletion src/libcore/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`]).
///
Expand Down Expand Up @@ -999,6 +999,63 @@ impl<'a, T, E> IntoIterator for &'a mut Result<T, E> {
}
}

#[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<T, E> {
/// Converts from `&Result<T, E>` 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<T, E>` 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<T, E>` 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<T, E> ResultDeref<T, E> for Result<T, E> {
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
/////////////////////////////////////////////////////////////////////////////
Expand Down
11 changes: 11 additions & 0 deletions src/libcore/tests/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,14 @@ fn test_try() {
}
assert_eq!(try_option_err(), Err(NoneError));
}

#[test]
fn test_option_deref() {
// Some: &Option<T: Deref>::Some(T) -> Option<&T::Deref::Target>::Some(&*T)
let ref_option = &Some(&42);
assert_eq!(ref_option.deref(), Some(&42));

// None: &Option<T: Deref>>::None -> None
let ref_option = &None;
assert_eq!(ref_option.deref(), None);
}
21 changes: 21 additions & 0 deletions src/libcore/tests/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}