about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-03-21 05:33:16 +0100
committerGitHub <noreply@github.com>2020-03-21 05:33:16 +0100
commit801a25abc1899df538939a8c2a3907bbea62cf1c (patch)
tree35bd7295c566320cbc5b316805357ca4679f6cca
parentef7c8a158f5bb36e3f5b96eacc196061e8ab9d10 (diff)
parent121bffce8106a73b90eb4f68da42d4d7ceca5375 (diff)
downloadrust-801a25abc1899df538939a8c2a3907bbea62cf1c.tar.gz
rust-801a25abc1899df538939a8c2a3907bbea62cf1c.zip
Rollup merge of #69997 - WaffleLapkin:option_zip, r=LukasKalbertodt
add `Option::{zip,zip_with}` methods under "option_zip" gate

This PR introduces 2 methods - `Option::zip` and `Option::zip_with` with
respective signatures:
- zip: `(Option<T>, Option<U>) -> Option<(T, U)>`
- zip_with: `(Option<T>, Option<U>, (T, U) -> R) -> Option<R>`
Both are under the feature gate "option_zip".

I'm not sure about the name "zip", maybe we can find a better name for this.
(I would prefer `union` for example, but this is a keyword :( )

--------------------------------------------------------------------------------

Recently in a russian rust begginers telegram chat a newbie asked (translated):
> Are there any methods for these conversions:
>
> 1. `(Option<A>, Option<B>) -> Option<(A, B)>`
> 2. `Vec<Option<T>> -> Option<Vec<T>>`
>
> ?

While second (2.) is clearly `vec.into_iter().collect::<Option<Vec<_>>()`, the
first one isn't that clear.

I couldn't find anything similar in the `core` and I've come to this solution:
```rust
let tuple: (Option<A>, Option<B>) = ...;
let res: Option<(A, B)> = tuple.0.and_then(|a| tuple.1.map(|b| (a, b)));
```

However this solution isn't "nice" (same for just `match`/`if let`), so I thought
that this functionality should be in `core`.
-rw-r--r--src/libcore/lib.rs1
-rw-r--r--src/libcore/option.rs57
2 files changed, 58 insertions, 0 deletions
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 5a731766054..94fc2fd357a 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -140,6 +140,7 @@
 #![feature(associated_type_bounds)]
 #![feature(const_type_id)]
 #![feature(const_caller_location)]
+#![feature(option_zip)]
 #![feature(no_niche)] // rust-lang/rust#68303
 
 #[prelude_import]
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index 9b32442371c..3aab8b1b333 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -913,6 +913,63 @@ impl<T> Option<T> {
     pub fn replace(&mut self, value: T) -> Option<T> {
         mem::replace(self, Some(value))
     }
+
+    /// Zips `self` with another `Option`.
+    ///
+    /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some((s, o))`.
+    /// Otherwise, `None` is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(option_zip)]
+    /// let x = Some(1);
+    /// let y = Some("hi");
+    /// let z = None::<u8>;
+    ///
+    /// assert_eq!(x.zip(y), Some((1, "hi")));
+    /// assert_eq!(x.zip(z), None);
+    /// ```
+    #[unstable(feature = "option_zip", issue = "70086")]
+    pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)> {
+        self.zip_with(other, |a, b| (a, b))
+    }
+
+    /// Zips `self` and another `Option` with function `f`.
+    ///
+    /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some(f(s, o))`.
+    /// Otherwise, `None` is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(option_zip)]
+    ///
+    /// #[derive(Debug, PartialEq)]
+    /// struct Point {
+    ///     x: f64,
+    ///     y: f64,
+    /// }
+    ///
+    /// impl Point {
+    ///     fn new(x: f64, y: f64) -> Self {
+    ///         Self { x, y }
+    ///     }
+    /// }
+    ///
+    /// let x = Some(17.5);
+    /// let y = Some(42.7);
+    ///
+    /// assert_eq!(x.zip_with(y, Point::new), Some(Point { x: 17.5, y: 42.7 }));
+    /// assert_eq!(x.zip_with(None, Point::new), None);
+    /// ```
+    #[unstable(feature = "option_zip", issue = "70086")]
+    pub fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
+    where
+        F: FnOnce(T, U) -> R,
+    {
+        Some(f(self?, other?))
+    }
 }
 
 impl<T: Copy> Option<&T> {