From a5206f9749faf60f6b4163a526de9ad18241503e Mon Sep 17 00:00:00 2001 From: Waffle Date: Fri, 13 Mar 2020 11:51:55 +0300 Subject: [PATCH 1/3] add `Option::{zip,zip_with}` methods under "option_zip" gate This commit introduces 2 methods - `Option::zip` and `Option::zip_with` with respective signatures: - zip: `(Option, Option) -> Option<(T, U)>` - zip_with: `(Option, Option, (T, U) -> R) -> Option` 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, Option) -> Option<(A, B)>` > 2. `Vec> -> Option>` > > ? While second (2.) is clearly `vec.into_iter().collect::>()`, 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, Option) = ...; 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`. --- src/libcore/lib.rs | 1 + src/libcore/option.rs | 59 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5a731766054bd..94fc2fd357a06 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 9b32442371c37..5db92a1b35248 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -913,6 +913,65 @@ impl Option { pub fn replace(&mut self, value: T) -> Option { mem::replace(self, Some(value)) } + + /// Zips `self` with another `Option`. + /// + /// Returns `Some((_, _))` when both `self` and `other` + /// are `Some(_)`, otherwise return `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(option_zip)] + /// let x = Some(1); + /// let y = Some("hi"); + /// let z = None::; + /// + /// assert_eq!(x.zip(y), Some((1, "hi"))); + /// assert_eq!(x.zip(z), None); + /// ``` + #[inline] + #[unstable(feature = "option_zip", issue = "none")] + pub fn zip(self, other: Option) -> Option<(T, U)> { + self.zip_with(other, |a, b| (a, b)) + } + + /// Zips `self` and another `Option` with function `f`. + /// + /// Returns `Some(_)` when both `self` and `other` + /// are `Some(_)`, otherwise return `None`. + /// + /// # 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.); + /// let y = Some(42.); + /// + /// assert_eq!(x.zip_with(y, Point::new), Some(Point { x: 17., y: 42. })); + /// assert_eq!(x.zip_with(None, Point::new), None); + /// ``` + #[inline] + #[unstable(feature = "option_zip", issue = "none")] + pub fn zip_with(self, other: Option, f: F) -> Option + where + F: FnOnce(T, U) -> R, + { + Some(f(self?, other?)) + } } impl Option<&T> { From d36d3fa5a6441f13c3888b6895cc7046740b1e3d Mon Sep 17 00:00:00 2001 From: Waffle Date: Wed, 18 Mar 2020 11:02:29 +0300 Subject: [PATCH 2/3] fixes to `Option::{zip,zip_with}` - remove `#[inline]` attributes (see https://github.com/rust-lang/rust/pull/69997#discussion_r393942617) - fill tracking issue in `#[unstable]` attributes - slightly improve the docs --- src/libcore/option.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 5db92a1b35248..4bec3ec9f6b42 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -916,8 +916,8 @@ impl Option { /// Zips `self` with another `Option`. /// - /// Returns `Some((_, _))` when both `self` and `other` - /// are `Some(_)`, otherwise return `None`. + /// If `self` is `Some(s)` and other is `Some(o)`, this method returns `Some((s, o))`. + /// Otherwise, `None` is returned. /// /// # Examples /// @@ -930,16 +930,15 @@ impl Option { /// assert_eq!(x.zip(y), Some((1, "hi"))); /// assert_eq!(x.zip(z), None); /// ``` - #[inline] - #[unstable(feature = "option_zip", issue = "none")] + #[unstable(feature = "option_zip", issue = "70086")] pub fn zip(self, other: Option) -> Option<(T, U)> { self.zip_with(other, |a, b| (a, b)) } /// Zips `self` and another `Option` with function `f`. /// - /// Returns `Some(_)` when both `self` and `other` - /// are `Some(_)`, otherwise return `None`. + /// If `self` is `Some(s)` and other is `Some(o)`, this method returns `Some(f(s, o))`. + /// Otherwise, `None` is returned. /// /// # Examples /// @@ -958,14 +957,13 @@ impl Option { /// } /// } /// - /// let x = Some(17.); - /// let y = Some(42.); + /// let x = Some(17.5); + /// let y = Some(42.7); /// - /// assert_eq!(x.zip_with(y, Point::new), Some(Point { x: 17., y: 42. })); + /// 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); /// ``` - #[inline] - #[unstable(feature = "option_zip", issue = "none")] + #[unstable(feature = "option_zip", issue = "70086")] pub fn zip_with(self, other: Option, f: F) -> Option where F: FnOnce(T, U) -> R, From 121bffce8106a73b90eb4f68da42d4d7ceca5375 Mon Sep 17 00:00:00 2001 From: Waffle Date: Thu, 19 Mar 2020 22:19:37 +0300 Subject: [PATCH 3/3] make "other" in docs of `Option::{zip,zip_with}` monofont --- src/libcore/option.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 4bec3ec9f6b42..3aab8b1b3337c 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -916,7 +916,7 @@ impl Option { /// Zips `self` with another `Option`. /// - /// If `self` is `Some(s)` and other is `Some(o)`, this method returns `Some((s, o))`. + /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some((s, o))`. /// Otherwise, `None` is returned. /// /// # Examples @@ -937,7 +937,7 @@ impl Option { /// 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))`. + /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some(f(s, o))`. /// Otherwise, `None` is returned. /// /// # Examples