diff options
| author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2018-01-20 22:32:42 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-01-20 22:32:42 +0100 |
| commit | 0e270fc842bab8529b22ed483494d63ac4d6370f (patch) | |
| tree | a2a70d10faa15c72e4dc47c2121381aa3709feca | |
| parent | fe811eb32883573416b3eaace532c2bcb5c10685 (diff) | |
| parent | c9ae249265c5da207ba0d8a2f8be95e58817e1dc (diff) | |
| download | rust-0e270fc842bab8529b22ed483494d63ac4d6370f.tar.gz rust-0e270fc842bab8529b22ed483494d63ac4d6370f.zip | |
Rollup merge of #47193 - cramertj:result-opts, r=TimNN
Add transpose conversions for nested Option and Result These impls are useful when working with combinator methods that expect an option or a result, but you have a `Result<Option<T>, E>` instead of an `Option<Result<T, E>>` or vice versa.
| -rw-r--r-- | src/libcore/option.rs | 29 | ||||
| -rw-r--r-- | src/libcore/result.rs | 29 | ||||
| -rw-r--r-- | src/test/run-pass/result-opt-conversions.rs | 57 |
3 files changed, 115 insertions, 0 deletions
diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 15181dab853..b8fe28d0f0d 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -881,6 +881,35 @@ impl<T: Default> Option<T> { } } +impl<T, E> Option<Result<T, E>> { + /// Transposes an `Option` of a `Result` into a `Result` of an `Option`. + /// + /// `None` will be mapped to `Ok(None)`. + /// `Some(Ok(_))` and `Some(Err(_))` will be mapped to `Ok(Some(_))` and `Err(_)`. + /// + /// # Examples + /// + /// ``` + /// #![feature(transpose_result)] + /// + /// #[derive(Debug, Eq, PartialEq)] + /// struct SomeErr; + /// + /// let x: Result<Option<i32>, SomeErr> = Ok(Some(5)); + /// let y: Option<Result<i32, SomeErr>> = Some(Ok(5)); + /// assert_eq!(x, y.transpose()); + /// ``` + #[inline] + #[unstable(feature = "transpose_result", issue = "47338")] + pub fn transpose(self) -> Result<Option<T>, E> { + match self { + Some(Ok(x)) => Ok(Some(x)), + Some(Err(e)) => Err(e), + None => Ok(None), + } + } +} + // This is a separate function to reduce the code size of .expect() itself. #[inline(never)] #[cold] diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 2ace3d2aee8..3801db94e15 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -909,6 +909,35 @@ impl<T: Default, E> Result<T, E> { } } +impl<T, E> Result<Option<T>, E> { + /// Transposes a `Result` of an `Option` into an `Option` of a `Result`. + /// + /// `Ok(None)` will be mapped to `None`. + /// `Ok(Some(_))` and `Err(_)` will be mapped to `Some(Ok(_))` and `Some(Err(_))`. + /// + /// # Examples + /// + /// ``` + /// #![feature(transpose_result)] + /// + /// #[derive(Debug, Eq, PartialEq)] + /// struct SomeErr; + /// + /// let x: Result<Option<i32>, SomeErr> = Ok(Some(5)); + /// let y: Option<Result<i32, SomeErr>> = Some(Ok(5)); + /// assert_eq!(x.transpose(), y); + /// ``` + #[inline] + #[unstable(feature = "transpose_result", issue = "47338")] + pub fn transpose(self) -> Option<Result<T, E>> { + match self { + Ok(Some(x)) => Some(Ok(x)), + Ok(None) => None, + Err(e) => Some(Err(e)), + } + } +} + // This is a separate function to reduce the code size of the methods #[inline(never)] #[cold] diff --git a/src/test/run-pass/result-opt-conversions.rs b/src/test/run-pass/result-opt-conversions.rs new file mode 100644 index 00000000000..0f6da002dda --- /dev/null +++ b/src/test/run-pass/result-opt-conversions.rs @@ -0,0 +1,57 @@ +// 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(transpose_result)] + +#[derive(Copy, Clone, Debug, PartialEq)] +struct BadNumErr; + +fn try_num(x: i32) -> Result<i32, BadNumErr> { + if x <= 5 { + Ok(x + 1) + } else { + Err(BadNumErr) + } +} + +type ResOpt = Result<Option<i32>, BadNumErr>; +type OptRes = Option<Result<i32, BadNumErr>>; + +fn main() { + let mut x: ResOpt = Ok(Some(5)); + let mut y: OptRes = Some(Ok(5)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Ok(None); + y = None; + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Err(BadNumErr); + y = Some(Err(BadNumErr)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + let res: Result<Vec<i32>, BadNumErr> = + (0..10) + .map(|x| { + let y = try_num(x)?; + Ok(if y % 2 == 0 { + Some(y - 1) + } else { + None + }) + }) + .filter_map(Result::transpose) + .collect(); + + assert_eq!(res, Err(BadNumErr)) +} |
