optional_transpose/
lib.rs

1//! # optional_transpose
2//! A small crate that adds `.transpose()` to `Option<Option<T>>`
3//! It allows you to reversibly swap the inner and outer options in the pair, so that you can use `?` on the inner option
4//!
5//! Example:
6//! ```rust
7//! use optional_transpose::OptionTranspose;
8//!
9//! fn example() -> Option<i32> {
10//!     let x: Option<Option<i32>> = Some(None);
11//!     let y: Option<i32> = x.transpose()?; // Returns None, as the inner option is None
12//!     Some(1)
13//! }
14//!
15//! assert_eq!(example(), None);
16//! ```
17//!
18
19/// Transpose an `Option` of an `Option` into an `Option` of an `Option`.
20pub trait OptionTranspose<T> {
21    /// Reverses the inner and outer `Option`s.
22    /// ``````
23    fn transpose(self) -> Option<Option<T>>;
24}
25
26impl<T> OptionTranspose<T> for Option<Option<T>> {
27    fn transpose(self) -> Option<Option<T>> {
28        match self {
29            Some(Some(x)) => Some(Some(x)),
30            Some(None) => None,
31            _ => Some(None),
32        }
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39
40    #[test]
41    fn test_transpose() {
42        let x: Option<Option<i32>> = Some(Some(1));
43        assert_eq!(x.transpose(), Some(Some(1)));
44
45        let x: Option<Option<i32>> = Some(None);
46        assert_eq!(x.transpose(), None);
47
48        let x: Option<Option<i32>> = None;
49        assert_eq!(x.transpose(), Some(None));
50    }
51}