Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ where
type Item = Either<L::Item, R::Item>;

fn next(&mut self) -> Option<Self::Item> {
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<usize>) {
Expand All @@ -211,11 +211,11 @@ where
}

fn last(self) -> Option<Self::Item> {
Some(map_either!(self.inner, inner => inner.last()?))
Some(map_both!(self.inner, inner => inner.last()?))
}

fn nth(&mut self, n: usize) -> Option<Self::Item> {
Some(map_either!(self.inner, ref mut inner => inner.nth(n)?))
Some(map_both!(self.inner, ref mut inner => inner.nth(n)?))
}

fn collect<B>(self) -> B
Expand Down Expand Up @@ -275,11 +275,11 @@ where
R: DoubleEndedIterator,
{
fn next_back(&mut self) -> Option<Self::Item> {
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<Self::Item> {
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<Acc, G>(self, init: Acc, f: G) -> Acc
Expand Down
88 changes: 64 additions & 24 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ pub enum Either<L, R> {
///
/// Syntax: `either::for_both!(` *expression* `,` *pattern* `=>` *expression* `)`
///
/// Unlike [`map_both!`], this macro converges both variants to the type returned by the expression.
///
/// # Example
///
/// ```
Expand Down Expand Up @@ -87,6 +89,53 @@ 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>(T);
///
/// fn wrap(
/// owned_or_borrowed: Either<String, &'static str>,
/// ) -> Either<Wrapper<String>, Wrapper<&'static str>> {
/// either::map_both!(owned_or_borrowed, s => Wrapper(s))
/// }
/// ```
///
/// ```
/// use either::Either;
///
/// fn widen(x: Either<i32, u32>) -> Either<i64, u64> {
/// either::map_both!(x => x.into())
/// }
/// ```
#[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),
}
};
($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
/// with the opposite side. Can only be used in functions that return
/// `Either` because of the early return of `Right` that it provides.
Expand Down Expand Up @@ -130,15 +179,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;

Expand Down Expand Up @@ -240,7 +280,7 @@ impl<L, R> Either<L, R> {
/// 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<L, R>` to `Either<&mut L, &mut R>`.
Expand All @@ -262,15 +302,15 @@ impl<L, R> Either<L, R> {
/// 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<L, R>>` to `Either<Pin<&L>, Pin<&R>>`,
/// pinned projections of the inner variants.
pub fn as_pin_ref(self: Pin<&Self>) -> Either<Pin<&L>, 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<L, R>>` to `Either<Pin<&mut L>, Pin<&mut R>>`,
Expand All @@ -281,7 +321,7 @@ impl<L, R> Either<L, R> {
// 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<L, R>` to `Either<R, L>`.
Expand Down Expand Up @@ -523,7 +563,7 @@ impl<L, R> Either<L, R> {
L: IntoIterator,
R: IntoIterator<Item = L::Item>,
{
map_either!(self, inner => inner.into_iter())
map_both!(self, inner => inner.into_iter())
}

/// Borrow the inner value as an iterator.
Expand All @@ -546,7 +586,7 @@ impl<L, R> Either<L, R> {
for<'a> &'a L: IntoIterator,
for<'a> &'a R: IntoIterator<Item = <&'a L as IntoIterator>::Item>,
{
map_either!(self, inner => inner.into_iter())
map_both!(self, inner => inner.into_iter())
}

/// Mutably borrow the inner value as an iterator.
Expand Down Expand Up @@ -577,7 +617,7 @@ impl<L, R> Either<L, R> {
for<'a> &'a mut L: IntoIterator,
for<'a> &'a mut R: IntoIterator<Item = <&'a mut L as 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
Expand All @@ -599,7 +639,7 @@ impl<L, R> Either<L, R> {
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
Expand All @@ -623,7 +663,7 @@ impl<L, R> Either<L, R> {
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
Expand All @@ -649,7 +689,7 @@ impl<L, R> Either<L, R> {
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
Expand Down Expand Up @@ -1066,7 +1106,7 @@ impl<T> Either<T, T> {
where
F: FnOnce(T) -> M,
{
map_either!(self, t => f(t))
map_both!(self, t => f(t))
}
}

Expand All @@ -1078,7 +1118,7 @@ impl<L, R> 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<L, R>` by copying the contents of
Expand All @@ -1088,7 +1128,7 @@ impl<L, R> Either<&L, &R> {
L: Copy,
R: Copy,
{
map_either!(self, inner => *inner)
map_both!(self, inner => *inner)
}
}

Expand All @@ -1100,7 +1140,7 @@ impl<L, R> 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<L, R>` by copying the contents of
Expand All @@ -1110,7 +1150,7 @@ impl<L, R> Either<&mut L, &mut R> {
L: Copy,
R: Copy,
{
map_either!(self, inner => *inner)
map_both!(self, inner => *inner)
}
}

Expand Down
Loading