From f64da476827b2ffae5af5ba482c4da3cad769f3f Mon Sep 17 00:00:00 2001 From: Dmitrii Demenev Date: Mon, 16 Sep 2024 14:59:53 -0600 Subject: [PATCH 1/5] Added either::map_both --- src/lib.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 702f54c..bf6bd4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,6 +60,8 @@ pub enum Either { /// /// Syntax: `either::for_both!(` *expression* `,` *pattern* `=>` *expression* `)` /// +/// Unlike [`map_both!`], this macro converges both variants to the type returned by the expression. +/// /// # Example /// /// ``` @@ -87,6 +89,37 @@ macro_rules! for_both { }; } +/// Evaluate the provided expression for both [`Either::Left`] and [`Either::Right`], +/// returning an [`Either`] with the results. +/// +/// This macro is useful in cases where both sides of [`Either`] can be interacted with +/// in the same way even though the don't share the same type. +/// +/// Syntax: `either::map_both!(` *expression* `,` *pattern* `=>` *expression* `)` +/// +/// Unlike [`for_both!`], this macro returns an [`Either`] with the results of the expressions. +/// +/// # Example +/// +/// ``` +/// use either::Either; +/// +/// struct Wrapper(T); +/// +/// fn wrap(owned_or_borrowed: Either) -> Either, Wrapper<&'static str>> { +/// either::map_both!(owned_or_borrowed, s => Wrapper(s)) +/// } +/// ``` +#[macro_export] +macro_rules! map_both { + ($value:expr, $pattern:pat => $result:expr) => { + match $value { + $crate::Either::Left($pattern) => $crate::Either::Left($result), + $crate::Either::Right($pattern) => $crate::Either::Right($result), + } + }; +} + /// Macro for unwrapping the left side of an [`Either`], which fails early /// with the opposite side. Can only be used in functions that return /// `Either` because of the early return of `Right` that it provides. From abd1be7fce8adf0a51ba473cf03c882b513814b3 Mon Sep 17 00:00:00 2001 From: Dmitrii Demenev Date: Tue, 17 Sep 2024 22:32:37 -0600 Subject: [PATCH 2/5] Replaced uses of internal map_either with newly added map_both --- src/iterator.rs | 10 +++++----- src/lib.rs | 21 ++++++--------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/iterator.rs b/src/iterator.rs index d54fab7..7e74686 100644 --- a/src/iterator.rs +++ b/src/iterator.rs @@ -185,7 +185,7 @@ where type Item = Either; fn next(&mut self) -> Option { - Some(map_either!(self.inner, ref mut inner => inner.next()?)) + Some(map_both!(self.inner, ref mut inner => inner.next()?)) } fn size_hint(&self) -> (usize, Option) { @@ -211,11 +211,11 @@ where } fn last(self) -> Option { - Some(map_either!(self.inner, inner => inner.last()?)) + Some(map_both!(self.inner, inner => inner.last()?)) } fn nth(&mut self, n: usize) -> Option { - Some(map_either!(self.inner, ref mut inner => inner.nth(n)?)) + Some(map_both!(self.inner, ref mut inner => inner.nth(n)?)) } fn collect(self) -> B @@ -275,11 +275,11 @@ where R: DoubleEndedIterator, { fn next_back(&mut self) -> Option { - Some(map_either!(self.inner, ref mut inner => inner.next_back()?)) + Some(map_both!(self.inner, ref mut inner => inner.next_back()?)) } fn nth_back(&mut self, n: usize) -> Option { - Some(map_either!(self.inner, ref mut inner => inner.nth_back(n)?)) + Some(map_both!(self.inner, ref mut inner => inner.nth_back(n)?)) } fn rfold(self, init: Acc, f: G) -> Acc diff --git a/src/lib.rs b/src/lib.rs index bf6bd4e..871b4e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -163,15 +163,6 @@ macro_rules! try_right { }; } -macro_rules! map_either { - ($value:expr, $pattern:pat => $result:expr) => { - match $value { - Left($pattern) => Left($result), - Right($pattern) => Right($result), - } - }; -} - mod iterator; pub use self::iterator::IterEither; @@ -556,7 +547,7 @@ impl Either { L: IntoIterator, R: IntoIterator, { - map_either!(self, inner => inner.into_iter()) + map_both!(self, inner => inner.into_iter()) } /// Borrow the inner value as an iterator. @@ -579,7 +570,7 @@ impl Either { for<'a> &'a L: IntoIterator, for<'a> &'a R: IntoIterator::Item>, { - map_either!(self, inner => inner.into_iter()) + map_both!(self, inner => inner.into_iter()) } /// Mutably borrow the inner value as an iterator. @@ -610,7 +601,7 @@ impl Either { for<'a> &'a mut L: IntoIterator, for<'a> &'a mut R: IntoIterator::Item>, { - map_either!(self, inner => inner.into_iter()) + map_both!(self, inner => inner.into_iter()) } /// Converts an `Either` of `Iterator`s to be an `Iterator` of `Either`s @@ -632,7 +623,7 @@ impl Either { L: IntoIterator, R: IntoIterator, { - IterEither::new(map_either!(self, inner => inner.into_iter())) + IterEither::new(map_both!(self, inner => inner.into_iter())) } /// Borrows an `Either` of `Iterator`s to be an `Iterator` of `Either`s @@ -656,7 +647,7 @@ impl Either { for<'a> &'a L: IntoIterator, for<'a> &'a R: IntoIterator, { - IterEither::new(map_either!(self, inner => inner.into_iter())) + IterEither::new(map_both!(self, inner => inner.into_iter())) } /// Mutably borrows an `Either` of `Iterator`s to be an `Iterator` of `Either`s @@ -682,7 +673,7 @@ impl Either { for<'a> &'a mut L: IntoIterator, for<'a> &'a mut R: IntoIterator, { - IterEither::new(map_either!(self, inner => inner.into_iter())) + IterEither::new(map_both!(self, inner => inner.into_iter())) } /// Return left value or given value From 958353c8e63311b35e1a3a86d11dba1af5f24a91 Mon Sep 17 00:00:00 2001 From: Ronno Das Date: Sat, 16 May 2026 15:13:36 +0900 Subject: [PATCH 3/5] Replaced uses of `map_either` since the old PR --- src/lib.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 871b4e6..fce31ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -264,7 +264,7 @@ impl Either { /// assert_eq!(right.as_ref(), Right(&"some value")); /// ``` pub fn as_ref(&self) -> Either<&L, &R> { - map_either!(self, inner => inner) + map_both!(self, inner => inner) } /// Convert `&mut Either` to `Either<&mut L, &mut R>`. @@ -286,7 +286,7 @@ impl Either { /// assert_eq!(right, Right(123)); /// ``` pub fn as_mut(&mut self) -> Either<&mut L, &mut R> { - map_either!(self, inner => inner) + map_both!(self, inner => inner) } /// Convert `Pin<&Either>` to `Either, Pin<&R>>`, @@ -294,7 +294,7 @@ impl Either { pub fn as_pin_ref(self: Pin<&Self>) -> Either, Pin<&R>> { // SAFETY: We can use `new_unchecked` because the `inner` parts are // guaranteed to be pinned, as they come from `self` which is pinned. - unsafe { map_either!(Pin::get_ref(self), inner => Pin::new_unchecked(inner)) } + unsafe { map_both!(Pin::get_ref(self), inner => Pin::new_unchecked(inner)) } } /// Convert `Pin<&mut Either>` to `Either, Pin<&mut R>>`, @@ -305,7 +305,7 @@ impl Either { // to be pinned, as they come from `self` which is pinned, and we never // offer an unpinned `&mut L` or `&mut R` through `Pin<&mut Self>`. We // also don't have an implementation of `Drop`, nor manual `Unpin`. - unsafe { map_either!(Pin::get_unchecked_mut(self), inner => Pin::new_unchecked(inner)) } + unsafe { map_both!(Pin::get_unchecked_mut(self), inner => Pin::new_unchecked(inner)) } } /// Convert `Either` to `Either`. @@ -1090,7 +1090,7 @@ impl Either { where F: FnOnce(T) -> M, { - map_either!(self, t => f(t)) + map_both!(self, t => f(t)) } } @@ -1102,7 +1102,7 @@ impl Either<&L, &R> { L: Clone, R: Clone, { - map_either!(self, inner => inner.clone()) + map_both!(self, inner => inner.clone()) } /// Maps an `Either<&L, &R>` to an `Either` by copying the contents of @@ -1112,7 +1112,7 @@ impl Either<&L, &R> { L: Copy, R: Copy, { - map_either!(self, inner => *inner) + map_both!(self, inner => *inner) } } @@ -1124,7 +1124,7 @@ impl Either<&mut L, &mut R> { L: Clone, R: Clone, { - map_either!(self, inner => inner.clone()) + map_both!(self, inner => inner.clone()) } /// Maps an `Either<&mut L, &mut R>` to an `Either` by copying the contents of @@ -1134,7 +1134,7 @@ impl Either<&mut L, &mut R> { L: Copy, R: Copy, { - map_either!(self, inner => *inner) + map_both!(self, inner => *inner) } } From a706625b85e45f34914b3a1ef62d808446863f6b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 20 May 2026 11:40:33 -0700 Subject: [PATCH 4/5] Format the `map_both!` example --- src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fce31ad..7cc54e4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,8 +106,10 @@ macro_rules! for_both { /// /// struct Wrapper(T); /// -/// fn wrap(owned_or_borrowed: Either) -> Either, Wrapper<&'static str>> { -/// either::map_both!(owned_or_borrowed, s => Wrapper(s)) +/// fn wrap( +/// owned_or_borrowed: Either, +/// ) -> Either, Wrapper<&'static str>> { +/// either::map_both!(owned_or_borrowed, s => Wrapper(s)) /// } /// ``` #[macro_export] From aa7f1d46f1d40b96f326ea642f1eb14bc99b9400 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 20 May 2026 11:52:01 -0700 Subject: [PATCH 5/5] Add a single-ident version of `map_both!` --- src/lib.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 7cc54e4..73bd5bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -112,6 +112,14 @@ macro_rules! for_both { /// either::map_both!(owned_or_borrowed, s => Wrapper(s)) /// } /// ``` +/// +/// ``` +/// use either::Either; +/// +/// fn widen(x: Either) -> Either { +/// either::map_both!(x => x.into()) +/// } +/// ``` #[macro_export] macro_rules! map_both { ($value:expr, $pattern:pat => $result:expr) => { @@ -120,6 +128,12 @@ macro_rules! map_both { $crate::Either::Right($pattern) => $crate::Either::Right($result), } }; + ($name:ident => $result:expr) => { + match $name { + $crate::Either::Left($name) => $crate::Either::Left($result), + $crate::Either::Right($name) => $crate::Either::Right($result), + } + }; } /// Macro for unwrapping the left side of an [`Either`], which fails early