Skip to content

Commit c9ae249

Browse files
committed
Add transpose conversions for 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.
1 parent 8e7a609 commit c9ae249

File tree

3 files changed

+115
-0
lines changed

3 files changed

+115
-0
lines changed

src/libcore/option.rs

+29
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,35 @@ impl<T: Default> Option<T> {
884884
}
885885
}
886886

887+
impl<T, E> Option<Result<T, E>> {
888+
/// Transposes an `Option` of a `Result` into a `Result` of an `Option`.
889+
///
890+
/// `None` will be mapped to `Ok(None)`.
891+
/// `Some(Ok(_))` and `Some(Err(_))` will be mapped to `Ok(Some(_))` and `Err(_)`.
892+
///
893+
/// # Examples
894+
///
895+
/// ```
896+
/// #![feature(transpose_result)]
897+
///
898+
/// #[derive(Debug, Eq, PartialEq)]
899+
/// struct SomeErr;
900+
///
901+
/// let x: Result<Option<i32>, SomeErr> = Ok(Some(5));
902+
/// let y: Option<Result<i32, SomeErr>> = Some(Ok(5));
903+
/// assert_eq!(x, y.transpose());
904+
/// ```
905+
#[inline]
906+
#[unstable(feature = "transpose_result", issue = "47338")]
907+
pub fn transpose(self) -> Result<Option<T>, E> {
908+
match self {
909+
Some(Ok(x)) => Ok(Some(x)),
910+
Some(Err(e)) => Err(e),
911+
None => Ok(None),
912+
}
913+
}
914+
}
915+
887916
// This is a separate function to reduce the code size of .expect() itself.
888917
#[inline(never)]
889918
#[cold]

src/libcore/result.rs

+29
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,35 @@ impl<T: Default, E> Result<T, E> {
909909
}
910910
}
911911

912+
impl<T, E> Result<Option<T>, E> {
913+
/// Transposes a `Result` of an `Option` into an `Option` of a `Result`.
914+
///
915+
/// `Ok(None)` will be mapped to `None`.
916+
/// `Ok(Some(_))` and `Err(_)` will be mapped to `Some(Ok(_))` and `Some(Err(_))`.
917+
///
918+
/// # Examples
919+
///
920+
/// ```
921+
/// #![feature(transpose_result)]
922+
///
923+
/// #[derive(Debug, Eq, PartialEq)]
924+
/// struct SomeErr;
925+
///
926+
/// let x: Result<Option<i32>, SomeErr> = Ok(Some(5));
927+
/// let y: Option<Result<i32, SomeErr>> = Some(Ok(5));
928+
/// assert_eq!(x.transpose(), y);
929+
/// ```
930+
#[inline]
931+
#[unstable(feature = "transpose_result", issue = "47338")]
932+
pub fn transpose(self) -> Option<Result<T, E>> {
933+
match self {
934+
Ok(Some(x)) => Some(Ok(x)),
935+
Ok(None) => None,
936+
Err(e) => Some(Err(e)),
937+
}
938+
}
939+
}
940+
912941
// This is a separate function to reduce the code size of the methods
913942
#[inline(never)]
914943
#[cold]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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(transpose_result)]
12+
13+
#[derive(Copy, Clone, Debug, PartialEq)]
14+
struct BadNumErr;
15+
16+
fn try_num(x: i32) -> Result<i32, BadNumErr> {
17+
if x <= 5 {
18+
Ok(x + 1)
19+
} else {
20+
Err(BadNumErr)
21+
}
22+
}
23+
24+
type ResOpt = Result<Option<i32>, BadNumErr>;
25+
type OptRes = Option<Result<i32, BadNumErr>>;
26+
27+
fn main() {
28+
let mut x: ResOpt = Ok(Some(5));
29+
let mut y: OptRes = Some(Ok(5));
30+
assert_eq!(x, y.transpose());
31+
assert_eq!(x.transpose(), y);
32+
33+
x = Ok(None);
34+
y = None;
35+
assert_eq!(x, y.transpose());
36+
assert_eq!(x.transpose(), y);
37+
38+
x = Err(BadNumErr);
39+
y = Some(Err(BadNumErr));
40+
assert_eq!(x, y.transpose());
41+
assert_eq!(x.transpose(), y);
42+
43+
let res: Result<Vec<i32>, BadNumErr> =
44+
(0..10)
45+
.map(|x| {
46+
let y = try_num(x)?;
47+
Ok(if y % 2 == 0 {
48+
Some(y - 1)
49+
} else {
50+
None
51+
})
52+
})
53+
.filter_map(Result::transpose)
54+
.collect();
55+
56+
assert_eq!(res, Err(BadNumErr))
57+
}

0 commit comments

Comments
 (0)