diff options
| author | bors <bors@rust-lang.org> | 2018-07-31 11:20:16 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-07-31 11:20:16 +0000 |
| commit | ed8d14db99fc79909274454c02073bc5bd0c0df2 (patch) | |
| tree | a767dfeb41318038e44751322e15cf1c3c2e36d9 /src/libcore | |
| parent | 896113201034946c7f49c1049288665fa2a56e32 (diff) | |
| parent | 56016cb1e02ece29f25c619b297f9c9797db821c (diff) | |
| download | rust-ed8d14db99fc79909274454c02073bc5bd0c0df2.tar.gz rust-ed8d14db99fc79909274454c02073bc5bd0c0df2.zip | |
Auto merge of #50267 - humanenginuity:master, r=alexcrichton
Implement inner deref for Option and Result tracking issue: #50264
Diffstat (limited to 'src/libcore')
| -rw-r--r-- | src/libcore/option.rs | 14 | ||||
| -rw-r--r-- | src/libcore/result.rs | 40 | ||||
| -rw-r--r-- | src/libcore/tests/lib.rs | 1 | ||||
| -rw-r--r-- | src/libcore/tests/option.rs | 17 | ||||
| -rw-r--r-- | src/libcore/tests/result.rs | 93 |
5 files changed, 162 insertions, 3 deletions
diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 9f9dbd0777a..2b6c376f8a7 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 {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 ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/result.rs b/src/libcore/result.rs index e0cc669d035..fb496836c2c 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`]). /// @@ -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`. /// diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 6fcfaae4535..2323b30a010 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -43,6 +43,7 @@ #![feature(align_offset)] #![feature(reverse_bits)] #![feature(iterator_find_map)] +#![feature(inner_deref)] #![feature(slice_internals)] #![feature(option_replace)] diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index 324ebf43565..1324ba2d9a9 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -299,6 +299,23 @@ fn test_try() { } #[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); let old = x.replace(5); diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index 0616252c82c..0c00992ffd8 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -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); +} |
