1
Fork 0

Auto merge of #50267 - humanenginuity:master, r=alexcrichton

Implement inner deref for Option and Result

tracking issue: #50264
This commit is contained in:
bors 2018-07-31 11:20:16 +00:00
commit ed8d14db99
9 changed files with 226 additions and 3 deletions

View file

@ -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
@ -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`.
///
@ -989,7 +1000,6 @@ fn expect_failed(msg: &str) -> ! {
panic!("{}", msg)
}
/////////////////////////////////////////////////////////////////////////////
// Trait implementations
/////////////////////////////////////////////////////////////////////////////

View file

@ -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`]).
///
@ -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`.
///

View file

@ -43,6 +43,7 @@
#![feature(align_offset)]
#![feature(reverse_bits)]
#![feature(iterator_find_map)]
#![feature(inner_deref)]
#![feature(slice_internals)]
#![feature(option_replace)]

View file

@ -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);

View file

@ -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);
}

View file

@ -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}>`
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}