From bc4ce79764f6519ee9f1469fb3fddcc3f70b8e14 Mon Sep 17 00:00:00 2001
From: Chase Wilson <me@chasewilson.dev>
Date: Fri, 30 Jul 2021 13:11:25 -0500
Subject: [PATCH 1/4] Added the `Option::unzip()` method

---
 library/core/src/option.rs | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index d4e9c384f9302..57553865bd015 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1399,6 +1399,31 @@ impl<T> Option<T> {
     }
 }
 
+impl<T, U> Option<(T, U)> {
+    /// Unzips an option containing a tuple of two options
+    ///
+    /// If `self` is `Some((a, b))` this method returns `(Some(a), Some(b))`.
+    /// Otherwise, `(None, None)` is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let x = Some((1, "hi"));
+    /// let y = None::<(u8, u32)>;
+    ///
+    /// assert_eq!(x.unzip(), (Some(1), Some("hi")));
+    /// assert_eq!(y.unzip(), (None, None));
+    /// ```
+    #[inline]
+    #[unstable(feature = "unzip_option", issue = "none", reason = "recently added")]
+    pub const fn unzip(self) -> (Option<T>, Option<U>) {
+        match self {
+            Some((a, b)) => (Some(a), Some(b)),
+            None => (None, None),
+        }
+    }
+}
+
 impl<T: Copy> Option<&T> {
     /// Maps an `Option<&T>` to an `Option<T>` by copying the contents of the
     /// option.

From eea3520a8fc1c4a03626ee4f9d74b6d9833db54c Mon Sep 17 00:00:00 2001
From: Chase Wilson <me@chasewilson.dev>
Date: Fri, 30 Jul 2021 13:13:59 -0500
Subject: [PATCH 2/4] Added some basic tests for `Option::unzip()` and
 `Option::zip()` (I noticed that zip had no tests)

---
 library/core/tests/option.rs | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs
index 88ea15a3b33fa..cd8fdebe36a05 100644
--- a/library/core/tests/option.rs
+++ b/library/core/tests/option.rs
@@ -399,7 +399,7 @@ fn test_unwrap_drop() {
 }
 
 #[test]
-pub fn option_ext() {
+fn option_ext() {
     let thing = "{{ f }}";
     let f = thing.find("{{");
 
@@ -407,3 +407,35 @@ pub fn option_ext() {
         println!("None!");
     }
 }
+
+#[test]
+fn zip_options() {
+    let x = Some(10);
+    let y = Some("foo");
+    let z: Option<usize> = None;
+
+    assert_eq!(x.zip(y), Some((10, "foo")));
+    assert_eq!(x.zip(z), None);
+    assert_eq!(z.zip(x), None);
+}
+
+#[test]
+fn unzip_options() {
+    let x = Some((10, "foo"));
+    let y = None::<(bool, i32)>;
+
+    assert_eq!(x.unzip(), (Some(10), Some("foo")));
+    assert_eq!(y.unzip(), (None, None));
+}
+
+#[test]
+fn zip_unzip_roundtrip() {
+    let x = Some(10);
+    let y = Some("foo");
+
+    let z = x.zip(y);
+    assert_eq!(z, Some((10, "foo")));
+
+    let a = z.unzip();
+    assert_eq!(a, (x, y));
+}

From 9d8081e8b6e4082ed06bd984cd59ccf39741c9b7 Mon Sep 17 00:00:00 2001
From: Chase Wilson <me@chasewilson.dev>
Date: Sat, 31 Jul 2021 18:16:34 -0500
Subject: [PATCH 3/4] Enabled unzip_option feature for core tests & unzip docs

---
 library/core/src/option.rs | 2 ++
 library/core/tests/lib.rs  | 1 +
 2 files changed, 3 insertions(+)

diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 57553865bd015..d65915cdc71e0 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1408,6 +1408,8 @@ impl<T, U> Option<(T, U)> {
     /// # Examples
     ///
     /// ```
+    /// #![feature(unzip_option)]
+    ///
     /// let x = Some((1, "hi"));
     /// let y = None::<(u8, u32)>;
     ///
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index c7756a503c3e9..cc3527f98ec65 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -66,6 +66,7 @@
 #![feature(slice_group_by)]
 #![feature(trusted_random_access)]
 #![feature(unsize)]
+#![feature(unzip_option)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
 extern crate test;

From ab2c5902ca404cb21fc9fa8bd6f5c52f33d92949 Mon Sep 17 00:00:00 2001
From: Chase Wilson <me@chasewilson.dev>
Date: Thu, 5 Aug 2021 12:44:22 -0500
Subject: [PATCH 4/4] Added tracking issue to unstable attribute

---
 library/core/src/option.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index d65915cdc71e0..3f9f04606b36a 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1417,7 +1417,7 @@ impl<T, U> Option<(T, U)> {
     /// assert_eq!(y.unzip(), (None, None));
     /// ```
     #[inline]
-    #[unstable(feature = "unzip_option", issue = "none", reason = "recently added")]
+    #[unstable(feature = "unzip_option", issue = "87800", reason = "recently added")]
     pub const fn unzip(self) -> (Option<T>, Option<U>) {
         match self {
             Some((a, b)) => (Some(a), Some(b)),