Skip to content

Commit ed8d14d

Browse files
committed
Auto merge of #50267 - humanenginuity:master, r=alexcrichton
Implement inner deref for Option and Result tracking issue: #50264
2 parents 8961132 + 56016cb commit ed8d14d

File tree

9 files changed

+226
-3
lines changed

9 files changed

+226
-3
lines changed

src/libcore/option.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@
146146
#![stable(feature = "rust1", since = "1.0.0")]
147147

148148
use iter::{FromIterator, FusedIterator, TrustedLen};
149-
use {hint, mem, ops};
149+
use {hint, mem, ops::{self, Deref}};
150150
use mem::PinMut;
151151

152152
// 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> {
953953
}
954954
}
955955

956+
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
957+
impl<T: Deref> Option<T> {
958+
/// Converts from `&Option<T>` to `Option<&T::Target>`.
959+
///
960+
/// Leaves the original Option in-place, creating a new one with a reference
961+
/// to the original one, additionally coercing the contents via `Deref`.
962+
pub fn deref(&self) -> Option<&T::Target> {
963+
self.as_ref().map(|t| t.deref())
964+
}
965+
}
966+
956967
impl<T, E> Option<Result<T, E>> {
957968
/// Transposes an `Option` of a `Result` into a `Result` of an `Option`.
958969
///
@@ -989,7 +1000,6 @@ fn expect_failed(msg: &str) -> ! {
9891000
panic!("{}", msg)
9901001
}
9911002

992-
9931003
/////////////////////////////////////////////////////////////////////////////
9941004
// Trait implementations
9951005
/////////////////////////////////////////////////////////////////////////////

src/libcore/result.rs

+39-1
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@
242242

243243
use fmt;
244244
use iter::{FromIterator, FusedIterator, TrustedLen};
245-
use ops;
245+
use ops::{self, Deref};
246246

247247
/// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]).
248248
///
@@ -909,6 +909,44 @@ impl<T: Default, E> Result<T, E> {
909909
}
910910
}
911911

912+
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
913+
impl<T: Deref, E> Result<T, E> {
914+
/// Converts from `&Result<T, E>` to `Result<&T::Target, &E>`.
915+
///
916+
/// Leaves the original Result in-place, creating a new one with a reference
917+
/// to the original one, additionally coercing the `Ok` arm of the Result via
918+
/// `Deref`.
919+
pub fn deref_ok(&self) -> Result<&T::Target, &E> {
920+
self.as_ref().map(|t| t.deref())
921+
}
922+
}
923+
924+
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
925+
impl<T, E: Deref> Result<T, E> {
926+
/// Converts from `&Result<T, E>` to `Result<&T, &E::Target>`.
927+
///
928+
/// Leaves the original Result in-place, creating a new one with a reference
929+
/// to the original one, additionally coercing the `Err` arm of the Result via
930+
/// `Deref`.
931+
pub fn deref_err(&self) -> Result<&T, &E::Target>
932+
{
933+
self.as_ref().map_err(|e| e.deref())
934+
}
935+
}
936+
937+
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
938+
impl<T: Deref, E: Deref> Result<T, E> {
939+
/// Converts from `&Result<T, E>` to `Result<&T::Target, &E::Target>`.
940+
///
941+
/// Leaves the original Result in-place, creating a new one with a reference
942+
/// to the original one, additionally coercing both the `Ok` and `Err` arms
943+
/// of the Result via `Deref`.
944+
pub fn deref(&self) -> Result<&T::Target, &E::Target>
945+
{
946+
self.as_ref().map(|t| t.deref()).map_err(|e| e.deref())
947+
}
948+
}
949+
912950
impl<T, E> Result<Option<T>, E> {
913951
/// Transposes a `Result` of an `Option` into an `Option` of a `Result`.
914952
///

src/libcore/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#![feature(align_offset)]
4444
#![feature(reverse_bits)]
4545
#![feature(iterator_find_map)]
46+
#![feature(inner_deref)]
4647
#![feature(slice_internals)]
4748
#![feature(option_replace)]
4849

src/libcore/tests/option.rs

+17
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,23 @@ fn test_try() {
298298
assert_eq!(try_option_err(), Err(NoneError));
299299
}
300300

301+
#[test]
302+
fn test_option_deref() {
303+
// Some: &Option<T: Deref>::Some(T) -> Option<&T::Deref::Target>::Some(&*T)
304+
let ref_option = &Some(&42);
305+
assert_eq!(ref_option.deref(), Some(&42));
306+
307+
let ref_option = &Some(String::from("a result"));
308+
assert_eq!(ref_option.deref(), Some("a result"));
309+
310+
let ref_option = &Some(vec![1, 2, 3, 4, 5]);
311+
assert_eq!(ref_option.deref(), Some(&[1, 2, 3, 4, 5][..]));
312+
313+
// None: &Option<T: Deref>>::None -> None
314+
let ref_option: &Option<&i32> = &None;
315+
assert_eq!(ref_option.deref(), None);
316+
}
317+
301318
#[test]
302319
fn test_replace() {
303320
let mut x = Some(2);

src/libcore/tests/result.rs

+93
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,96 @@ fn test_try() {
233233
}
234234
assert_eq!(try_result_err(), Err(1));
235235
}
236+
237+
#[test]
238+
fn test_result_deref() {
239+
// &Result<T: Deref, E>::Ok(T).deref_ok() ->
240+
// Result<&T::Deref::Target, &E>::Ok(&*T)
241+
let ref_ok = &Result::Ok::<&i32, u8>(&42);
242+
let expected_result = Result::Ok::<&i32, &u8>(&42);
243+
assert_eq!(ref_ok.deref_ok(), expected_result);
244+
245+
let ref_ok = &Result::Ok::<String, u32>(String::from("a result"));
246+
let expected_result = Result::Ok::<&str, &u32>("a result");
247+
assert_eq!(ref_ok.deref_ok(), expected_result);
248+
249+
let ref_ok = &Result::Ok::<Vec<i32>, u32>(vec![1, 2, 3, 4, 5]);
250+
let expected_result = Result::Ok::<&[i32], &u32>(&[1, 2, 3, 4, 5][..]);
251+
assert_eq!(ref_ok.deref_ok(), expected_result);
252+
253+
// &Result<T: Deref, E: Deref>::Ok(T).deref() ->
254+
// Result<&T::Deref::Target, &E::Deref::Target>::Ok(&*T)
255+
let ref_ok = &Result::Ok::<&i32, &u8>(&42);
256+
let expected_result = Result::Ok::<&i32, &u8>(&42);
257+
assert_eq!(ref_ok.deref(), expected_result);
258+
259+
let ref_ok = &Result::Ok::<String, &u32>(String::from("a result"));
260+
let expected_result = Result::Ok::<&str, &u32>("a result");
261+
assert_eq!(ref_ok.deref(), expected_result);
262+
263+
let ref_ok = &Result::Ok::<Vec<i32>, &u32>(vec![1, 2, 3, 4, 5]);
264+
let expected_result = Result::Ok::<&[i32], &u32>(&[1, 2, 3, 4, 5][..]);
265+
assert_eq!(ref_ok.deref(), expected_result);
266+
267+
// &Result<T, E: Deref>::Err(T).deref_err() ->
268+
// Result<&T, &E::Deref::Target>::Err(&*E)
269+
let ref_err = &Result::Err::<u8, &i32>(&41);
270+
let expected_result = Result::Err::<&u8, &i32>(&41);
271+
assert_eq!(ref_err.deref_err(), expected_result);
272+
273+
let ref_err = &Result::Err::<u32, String>(String::from("an error"));
274+
let expected_result = Result::Err::<&u32, &str>("an error");
275+
assert_eq!(ref_err.deref_err(), expected_result);
276+
277+
let ref_err = &Result::Err::<u32, Vec<i32>>(vec![5, 4, 3, 2, 1]);
278+
let expected_result = Result::Err::<&u32, &[i32]>(&[5, 4, 3, 2, 1][..]);
279+
assert_eq!(ref_err.deref_err(), expected_result);
280+
281+
// &Result<T: Deref, E: Deref>::Err(T).deref_err() ->
282+
// Result<&T, &E::Deref::Target>::Err(&*E)
283+
let ref_err = &Result::Err::<&u8, &i32>(&41);
284+
let expected_result = Result::Err::<&u8, &i32>(&41);
285+
assert_eq!(ref_err.deref(), expected_result);
286+
287+
let ref_err = &Result::Err::<&u32, String>(String::from("an error"));
288+
let expected_result = Result::Err::<&u32, &str>("an error");
289+
assert_eq!(ref_err.deref(), expected_result);
290+
291+
let ref_err = &Result::Err::<&u32, Vec<i32>>(vec![5, 4, 3, 2, 1]);
292+
let expected_result = Result::Err::<&u32, &[i32]>(&[5, 4, 3, 2, 1][..]);
293+
assert_eq!(ref_err.deref(), expected_result);
294+
295+
// The following cases test calling deref_* with the wrong variant (i.e.
296+
// `deref_ok()` with a `Result::Err()`, or `deref_err()` with a `Result::Ok()`.
297+
// While unusual, these cases are supported to ensure that an `inner_deref`
298+
// call can still be made even when one of the Result types does not implement
299+
// `Deref` (for example, std::io::Error).
300+
301+
// &Result<T, E: Deref>::Ok(T).deref_err() ->
302+
// Result<&T, &E::Deref::Target>::Ok(&T)
303+
let ref_ok = &Result::Ok::<i32, &u8>(42);
304+
let expected_result = Result::Ok::<&i32, &u8>(&42);
305+
assert_eq!(ref_ok.deref_err(), expected_result);
306+
307+
let ref_ok = &Result::Ok::<&str, &u32>("a result");
308+
let expected_result = Result::Ok::<&&str, &u32>(&"a result");
309+
assert_eq!(ref_ok.deref_err(), expected_result);
310+
311+
let ref_ok = &Result::Ok::<[i32; 5], &u32>([1, 2, 3, 4, 5]);
312+
let expected_result = Result::Ok::<&[i32; 5], &u32>(&[1, 2, 3, 4, 5]);
313+
assert_eq!(ref_ok.deref_err(), expected_result);
314+
315+
// &Result<T: Deref, E>::Err(E).deref_ok() ->
316+
// Result<&T::Deref::Target, &E>::Err(&E)
317+
let ref_err = &Result::Err::<&u8, i32>(41);
318+
let expected_result = Result::Err::<&u8, &i32>(&41);
319+
assert_eq!(ref_err.deref_ok(), expected_result);
320+
321+
let ref_err = &Result::Err::<&u32, &str>("an error");
322+
let expected_result = Result::Err::<&u32, &&str>(&"an error");
323+
assert_eq!(ref_err.deref_ok(), expected_result);
324+
325+
let ref_err = &Result::Err::<&u32, [i32; 5]>([5, 4, 3, 2, 1]);
326+
let expected_result = Result::Err::<&u32, &[i32; 5]>(&[5, 4, 3, 2, 1]);
327+
assert_eq!(ref_err.deref_ok(), expected_result);
328+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(inner_deref)]
12+
13+
fn main() {
14+
let _result = &Some(42).deref();
15+
//~^ ERROR no method named `deref` found for type `std::option::Option<{integer}>`
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(inner_deref)]
12+
13+
fn main() {
14+
let _result = &Ok(42).deref();
15+
//~^ ERROR no method named `deref` found
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(inner_deref)]
12+
13+
fn main() {
14+
let _result = &Err(41).deref_err();
15+
//~^ ERROR no method named `deref_err` found
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(inner_deref)]
12+
13+
fn main() {
14+
let _result = &Ok(42).deref_ok();
15+
//~^ ERROR no method named `deref_ok` found
16+
}

0 commit comments

Comments
 (0)