Skip to content

Commit

Permalink
Auto merge of #50267 - humanenginuity:master, r=alexcrichton
Browse files Browse the repository at this point in the history
Implement inner deref for Option and Result

tracking issue: #50264
  • Loading branch information
bors committed Jul 31, 2018
2 parents 8961132 + 56016cb commit ed8d14d
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 3 deletions.
14 changes: 12 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 {hint, mem, ops};
use {hint, mem, ops::{self, Deref}};
use mem::PinMut;

// Note that this is not a lang item per se, but it has a hidden dependency on
Expand Down Expand Up @@ -953,6 +953,17 @@ impl<T: Default> Option<T> {
}
}

#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
impl<T: Deref> Option<T> {
/// 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`.
pub fn deref(&self) -> Option<&T::Target> {
self.as_ref().map(|t| t.deref())
}
}

impl<T, E> Option<Result<T, E>> {
/// Transposes an `Option` of a `Result` into a `Result` of an `Option`.
///
Expand Down Expand Up @@ -989,7 +1000,6 @@ fn expect_failed(msg: &str) -> ! {
panic!("{}", msg)
}


/////////////////////////////////////////////////////////////////////////////
// Trait implementations
/////////////////////////////////////////////////////////////////////////////
Expand Down
40 changes: 39 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 @@ -909,6 +909,44 @@ impl<T: Default, E> Result<T, E> {
}
}

#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
impl<T: Deref, E> Result<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`.
pub fn deref_ok(&self) -> Result<&T::Target, &E> {
self.as_ref().map(|t| t.deref())
}
}

#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
impl<T, E: Deref> Result<T, E> {
/// 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`.
pub fn deref_err(&self) -> Result<&T, &E::Target>
{
self.as_ref().map_err(|e| e.deref())
}
}

#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
impl<T: Deref, E: Deref> Result<T, E> {
/// 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`.
pub fn deref(&self) -> Result<&T::Target, &E::Target>
{
self.as_ref().map(|t| t.deref()).map_err(|e| e.deref())
}
}

impl<T, E> Result<Option<T>, E> {
/// Transposes a `Result` of an `Option` into an `Option` of a `Result`.
///
Expand Down
1 change: 1 addition & 0 deletions src/libcore/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#![feature(align_offset)]
#![feature(reverse_bits)]
#![feature(iterator_find_map)]
#![feature(inner_deref)]
#![feature(slice_internals)]
#![feature(option_replace)]

Expand Down
17 changes: 17 additions & 0 deletions src/libcore/tests/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,23 @@ 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));

let ref_option = &Some(String::from("a result"));
assert_eq!(ref_option.deref(), Some("a result"));

let ref_option = &Some(vec![1, 2, 3, 4, 5]);
assert_eq!(ref_option.deref(), Some(&[1, 2, 3, 4, 5][..]));

// None: &Option<T: Deref>>::None -> None
let ref_option: &Option<&i32> = &None;
assert_eq!(ref_option.deref(), None);
}

#[test]
fn test_replace() {
let mut x = Some(2);
Expand Down
93 changes: 93 additions & 0 deletions src/libcore/tests/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,96 @@ fn test_try() {
}
assert_eq!(try_result_err(), Err(1));
}

#[test]
fn test_result_deref() {
// &Result<T: Deref, E>::Ok(T).deref_ok() ->
// Result<&T::Deref::Target, &E>::Ok(&*T)
let ref_ok = &Result::Ok::<&i32, u8>(&42);
let expected_result = Result::Ok::<&i32, &u8>(&42);
assert_eq!(ref_ok.deref_ok(), expected_result);

let ref_ok = &Result::Ok::<String, u32>(String::from("a result"));
let expected_result = Result::Ok::<&str, &u32>("a result");
assert_eq!(ref_ok.deref_ok(), expected_result);

let ref_ok = &Result::Ok::<Vec<i32>, u32>(vec![1, 2, 3, 4, 5]);
let expected_result = Result::Ok::<&[i32], &u32>(&[1, 2, 3, 4, 5][..]);
assert_eq!(ref_ok.deref_ok(), expected_result);

// &Result<T: Deref, E: Deref>::Ok(T).deref() ->
// Result<&T::Deref::Target, &E::Deref::Target>::Ok(&*T)
let ref_ok = &Result::Ok::<&i32, &u8>(&42);
let expected_result = Result::Ok::<&i32, &u8>(&42);
assert_eq!(ref_ok.deref(), expected_result);

let ref_ok = &Result::Ok::<String, &u32>(String::from("a result"));
let expected_result = Result::Ok::<&str, &u32>("a result");
assert_eq!(ref_ok.deref(), expected_result);

let ref_ok = &Result::Ok::<Vec<i32>, &u32>(vec![1, 2, 3, 4, 5]);
let expected_result = Result::Ok::<&[i32], &u32>(&[1, 2, 3, 4, 5][..]);
assert_eq!(ref_ok.deref(), expected_result);

// &Result<T, E: Deref>::Err(T).deref_err() ->
// Result<&T, &E::Deref::Target>::Err(&*E)
let ref_err = &Result::Err::<u8, &i32>(&41);
let expected_result = Result::Err::<&u8, &i32>(&41);
assert_eq!(ref_err.deref_err(), expected_result);

let ref_err = &Result::Err::<u32, String>(String::from("an error"));
let expected_result = Result::Err::<&u32, &str>("an error");
assert_eq!(ref_err.deref_err(), expected_result);

let ref_err = &Result::Err::<u32, Vec<i32>>(vec![5, 4, 3, 2, 1]);
let expected_result = Result::Err::<&u32, &[i32]>(&[5, 4, 3, 2, 1][..]);
assert_eq!(ref_err.deref_err(), expected_result);

// &Result<T: Deref, E: Deref>::Err(T).deref_err() ->
// Result<&T, &E::Deref::Target>::Err(&*E)
let ref_err = &Result::Err::<&u8, &i32>(&41);
let expected_result = Result::Err::<&u8, &i32>(&41);
assert_eq!(ref_err.deref(), expected_result);

let ref_err = &Result::Err::<&u32, String>(String::from("an error"));
let expected_result = Result::Err::<&u32, &str>("an error");
assert_eq!(ref_err.deref(), expected_result);

let ref_err = &Result::Err::<&u32, Vec<i32>>(vec![5, 4, 3, 2, 1]);
let expected_result = Result::Err::<&u32, &[i32]>(&[5, 4, 3, 2, 1][..]);
assert_eq!(ref_err.deref(), expected_result);

// The following cases test calling deref_* with the wrong variant (i.e.
// `deref_ok()` with a `Result::Err()`, or `deref_err()` with a `Result::Ok()`.
// While unusual, these cases are supported to ensure that an `inner_deref`
// call can still be made even when one of the Result types does not implement
// `Deref` (for example, std::io::Error).

// &Result<T, E: Deref>::Ok(T).deref_err() ->
// Result<&T, &E::Deref::Target>::Ok(&T)
let ref_ok = &Result::Ok::<i32, &u8>(42);
let expected_result = Result::Ok::<&i32, &u8>(&42);
assert_eq!(ref_ok.deref_err(), expected_result);

let ref_ok = &Result::Ok::<&str, &u32>("a result");
let expected_result = Result::Ok::<&&str, &u32>(&"a result");
assert_eq!(ref_ok.deref_err(), expected_result);

let ref_ok = &Result::Ok::<[i32; 5], &u32>([1, 2, 3, 4, 5]);
let expected_result = Result::Ok::<&[i32; 5], &u32>(&[1, 2, 3, 4, 5]);
assert_eq!(ref_ok.deref_err(), expected_result);

// &Result<T: Deref, E>::Err(E).deref_ok() ->
// Result<&T::Deref::Target, &E>::Err(&E)
let ref_err = &Result::Err::<&u8, i32>(41);
let expected_result = Result::Err::<&u8, &i32>(&41);
assert_eq!(ref_err.deref_ok(), expected_result);

let ref_err = &Result::Err::<&u32, &str>("an error");
let expected_result = Result::Err::<&u32, &&str>(&"an error");
assert_eq!(ref_err.deref_ok(), expected_result);

let ref_err = &Result::Err::<&u32, [i32; 5]>([5, 4, 3, 2, 1]);
let expected_result = Result::Err::<&u32, &[i32; 5]>(&[5, 4, 3, 2, 1]);
assert_eq!(ref_err.deref_ok(), expected_result);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(inner_deref)]

fn main() {
let _result = &Some(42).deref();
//~^ ERROR no method named `deref` found for type `std::option::Option<{integer}>`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(inner_deref)]

fn main() {
let _result = &Ok(42).deref();
//~^ ERROR no method named `deref` found
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(inner_deref)]

fn main() {
let _result = &Err(41).deref_err();
//~^ ERROR no method named `deref_err` found
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(inner_deref)]

fn main() {
let _result = &Ok(42).deref_ok();
//~^ ERROR no method named `deref_ok` found
}

0 comments on commit ed8d14d

Please sign in to comment.