Skip to content

Commit 8bc377e

Browse files
Merge #629
629: Improvements to `EitherOrBoth` r=jswrenn a=JoJoJet * Added more methods for accessing the left and right variants. * Added methods for inserting left and right values (using unsafe code). * Improved some grammar. Co-authored-by: JoJoJet <[email protected]>
2 parents cc5ae85 + 4b15974 commit 8bc377e

File tree

1 file changed

+240
-8
lines changed

1 file changed

+240
-8
lines changed

src/either_or_both.rs

+240-8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use core::ops::{Deref, DerefMut};
2+
13
use crate::EitherOrBoth::*;
24

35
use either::Either;
@@ -14,7 +16,7 @@ pub enum EitherOrBoth<A, B> {
1416
}
1517

1618
impl<A, B> EitherOrBoth<A, B> {
17-
/// If `Left`, or `Both`, return true, otherwise, return false.
19+
/// If `Left`, or `Both`, return true. Otherwise, return false.
1820
pub fn has_left(&self) -> bool {
1921
self.as_ref().left().is_some()
2022
}
@@ -24,7 +26,7 @@ impl<A, B> EitherOrBoth<A, B> {
2426
self.as_ref().right().is_some()
2527
}
2628

27-
/// If Left, return true otherwise, return false.
29+
/// If `Left`, return true. Otherwise, return false.
2830
/// Exclusive version of [`has_left`](EitherOrBoth::has_left).
2931
pub fn is_left(&self) -> bool {
3032
match *self {
@@ -33,7 +35,7 @@ impl<A, B> EitherOrBoth<A, B> {
3335
}
3436
}
3537

36-
/// If Right, return true otherwise, return false.
38+
/// If `Right`, return true. Otherwise, return false.
3739
/// Exclusive version of [`has_right`](EitherOrBoth::has_right).
3840
pub fn is_right(&self) -> bool {
3941
match *self {
@@ -42,36 +44,107 @@ impl<A, B> EitherOrBoth<A, B> {
4244
}
4345
}
4446

45-
/// If Right, return true otherwise, return false.
46-
/// Equivalent to `self.as_ref().both().is_some()`.
47+
/// If `Both`, return true. Otherwise, return false.
4748
pub fn is_both(&self) -> bool {
4849
self.as_ref().both().is_some()
4950
}
5051

51-
/// If `Left`, or `Both`, return `Some` with the left value, otherwise, return `None`.
52+
/// If `Left`, or `Both`, return `Some` with the left value. Otherwise, return `None`.
5253
pub fn left(self) -> Option<A> {
5354
match self {
5455
Left(left) | Both(left, _) => Some(left),
5556
_ => None,
5657
}
5758
}
5859

59-
/// If `Right`, or `Both`, return `Some` with the right value, otherwise, return `None`.
60+
/// If `Right`, or `Both`, return `Some` with the right value. Otherwise, return `None`.
6061
pub fn right(self) -> Option<B> {
6162
match self {
6263
Right(right) | Both(_, right) => Some(right),
6364
_ => None,
6465
}
6566
}
6667

67-
/// If Both, return `Some` tuple containing left and right.
68+
/// If `Left`, return `Some` with the left value. If `Right` or `Both`, return `None`.
69+
///
70+
/// # Examples
71+
///
72+
/// ```
73+
/// // On the `Left` variant.
74+
/// # use itertools::{EitherOrBoth, EitherOrBoth::{Left, Right, Both}};
75+
/// let x: EitherOrBoth<_, ()> = Left("bonjour");
76+
/// assert_eq!(x.just_left(), Some("bonjour"));
77+
///
78+
/// // On the `Right` variant.
79+
/// let x: EitherOrBoth<(), _> = Right("hola");
80+
/// assert_eq!(x.just_left(), None);
81+
///
82+
/// // On the `Both` variant.
83+
/// let x = Both("bonjour", "hola");
84+
/// assert_eq!(x.just_left(), None);
85+
/// ```
86+
pub fn just_left(self) -> Option<A> {
87+
match self {
88+
Left(left) => Some(left),
89+
_ => None,
90+
}
91+
}
92+
93+
/// If `Right`, return `Some` with the right value. If `Left` or `Both`, return `None`.
94+
///
95+
/// # Examples
96+
///
97+
/// ```
98+
/// // On the `Left` variant.
99+
/// # use itertools::{EitherOrBoth::{Left, Right, Both}, EitherOrBoth};
100+
/// let x: EitherOrBoth<_, ()> = Left("auf wiedersehen");
101+
/// assert_eq!(x.just_left(), Some("auf wiedersehen"));
102+
///
103+
/// // On the `Right` variant.
104+
/// let x: EitherOrBoth<(), _> = Right("adios");
105+
/// assert_eq!(x.just_left(), None);
106+
///
107+
/// // On the `Both` variant.
108+
/// let x = Both("auf wiedersehen", "adios");
109+
/// assert_eq!(x.just_left(), None);
110+
/// ```
111+
pub fn just_right(self) -> Option<B> {
112+
match self {
113+
Right(right) => Some(right),
114+
_ => None,
115+
}
116+
}
117+
118+
/// If `Both`, return `Some` containing the left and right values. Otherwise, return `None`.
68119
pub fn both(self) -> Option<(A, B)> {
69120
match self {
70121
Both(a, b) => Some((a, b)),
71122
_ => None,
72123
}
73124
}
74125

126+
/// If `Left` or `Both`, return the left value. Otherwise, convert the right value and return it.
127+
pub fn into_left(self) -> A
128+
where
129+
B: Into<A>,
130+
{
131+
match self {
132+
Left(a) | Both(a, _) => a,
133+
Right(b) => b.into(),
134+
}
135+
}
136+
137+
/// If `Right` or `Both`, return the right value. Otherwise, convert the left value and return it.
138+
pub fn into_right(self) -> B
139+
where
140+
A: Into<B>,
141+
{
142+
match self {
143+
Right(b) | Both(_, b) => b,
144+
Left(a) => a.into(),
145+
}
146+
}
147+
75148
/// Converts from `&EitherOrBoth<A, B>` to `EitherOrBoth<&A, &B>`.
76149
pub fn as_ref(&self) -> EitherOrBoth<&A, &B> {
77150
match *self {
@@ -90,6 +163,32 @@ impl<A, B> EitherOrBoth<A, B> {
90163
}
91164
}
92165

166+
/// Converts from `&EitherOrBoth<A, B>` to `EitherOrBoth<&_, &_>` using the [`Deref`] trait.
167+
pub fn as_deref(&self) -> EitherOrBoth<&A::Target, &B::Target>
168+
where
169+
A: Deref,
170+
B: Deref,
171+
{
172+
match *self {
173+
Left(ref left) => Left(left),
174+
Right(ref right) => Right(right),
175+
Both(ref left, ref right) => Both(left, right),
176+
}
177+
}
178+
179+
/// Converts from `&mut EitherOrBoth<A, B>` to `EitherOrBoth<&mut _, &mut _>` using the [`DerefMut`] trait.
180+
pub fn as_deref_mut(&mut self) -> EitherOrBoth<&mut A::Target, &mut B::Target>
181+
where
182+
A: DerefMut,
183+
B: DerefMut,
184+
{
185+
match *self {
186+
Left(ref mut left) => Left(left),
187+
Right(ref mut right) => Right(right),
188+
Both(ref mut left, ref mut right) => Both(left, right),
189+
}
190+
}
191+
93192
/// Convert `EitherOrBoth<A, B>` to `EitherOrBoth<B, A>`.
94193
pub fn flip(self) -> EitherOrBoth<B, A> {
95194
match self {
@@ -227,6 +326,139 @@ impl<A, B> EitherOrBoth<A, B> {
227326
Both(inner_l, inner_r) => (inner_l, inner_r),
228327
}
229328
}
329+
330+
/// Returns a mutable reference to the left value. If the left value is not present,
331+
/// it is replaced with `val`.
332+
pub fn left_or_insert(&mut self, val: A) -> &mut A {
333+
self.left_or_insert_with(|| val)
334+
}
335+
336+
/// Returns a mutable reference to the right value. If the right value is not present,
337+
/// it is replaced with `val`.
338+
pub fn right_or_insert(&mut self, val: B) -> &mut B {
339+
self.right_or_insert_with(|| val)
340+
}
341+
342+
/// If the left value is not present, replace it the value computed by the closure `f`.
343+
/// Returns a mutable reference to the now-present left value.
344+
pub fn left_or_insert_with<F>(&mut self, f: F) -> &mut A
345+
where
346+
F: FnOnce() -> A,
347+
{
348+
match self {
349+
Left(left) | Both(left, _) => left,
350+
Right(_) => self.insert_left(f()),
351+
}
352+
}
353+
354+
/// If the right value is not present, replace it the value computed by the closure `f`.
355+
/// Returns a mutable reference to the now-present right value.
356+
pub fn right_or_insert_with<F>(&mut self, f: F) -> &mut B
357+
where
358+
F: FnOnce() -> B,
359+
{
360+
match self {
361+
Right(right) | Both(_, right) => right,
362+
Left(_) => self.insert_right(f()),
363+
}
364+
}
365+
366+
/// Sets the `left` value of this instance, and returns a mutable reference to it.
367+
/// Does not affect the `right` value.
368+
///
369+
/// # Examples
370+
/// ```
371+
/// # use itertools::{EitherOrBoth, EitherOrBoth::{Left, Right, Both}};
372+
///
373+
/// // Overwriting a pre-existing value.
374+
/// let mut either: EitherOrBoth<_, ()> = Left(0_u32);
375+
/// assert_eq!(*either.insert_left(69), 69);
376+
///
377+
/// // Inserting a second value.
378+
/// let mut either = Right("no");
379+
/// assert_eq!(*either.insert_left("yes"), "yes");
380+
/// assert_eq!(either, Both("yes", "no"));
381+
/// ```
382+
pub fn insert_left(&mut self, val: A) -> &mut A {
383+
match self {
384+
Left(left) | Both(left, _) => {
385+
*left = val;
386+
left
387+
}
388+
Right(right) => {
389+
// This is like a map in place operation. We move out of the reference,
390+
// change the value, and then move back into the reference.
391+
unsafe {
392+
// SAFETY: We know this pointer is valid for reading since we got it from a reference.
393+
let right = std::ptr::read(right as *mut _);
394+
// SAFETY: Again, we know the pointer is valid since we got it from a reference.
395+
std::ptr::write(self as *mut _, Both(val, right));
396+
}
397+
398+
if let Both(left, _) = self {
399+
left
400+
} else {
401+
// SAFETY: The above pattern will always match, since we just
402+
// set `self` equal to `Both`.
403+
unsafe { std::hint::unreachable_unchecked() }
404+
}
405+
}
406+
}
407+
}
408+
409+
/// Sets the `right` value of this instance, and returns a mutable reference to it.
410+
/// Does not affect the `left` value.
411+
///
412+
/// # Examples
413+
/// ```
414+
/// # use itertools::{EitherOrBoth, EitherOrBoth::{Left, Both}};
415+
/// // Overwriting a pre-existing value.
416+
/// let mut either: EitherOrBoth<_, ()> = Left(0_u32);
417+
/// assert_eq!(*either.insert_left(69), 69);
418+
///
419+
/// // Inserting a second value.
420+
/// let mut either = Left("what's");
421+
/// assert_eq!(*either.insert_right(9 + 10), 21 - 2);
422+
/// assert_eq!(either, Both("what's", 9+10));
423+
/// ```
424+
pub fn insert_right(&mut self, val: B) -> &mut B {
425+
match self {
426+
Right(right) | Both(_, right) => {
427+
*right = val;
428+
right
429+
}
430+
Left(left) => {
431+
// This is like a map in place operation. We move out of the reference,
432+
// change the value, and then move back into the reference.
433+
unsafe {
434+
// SAFETY: We know this pointer is valid for reading since we got it from a reference.
435+
let left = std::ptr::read(left as *mut _);
436+
// SAFETY: Again, we know the pointer is valid since we got it from a reference.
437+
std::ptr::write(self as *mut _, Both(left, val));
438+
}
439+
if let Both(_, right) = self {
440+
right
441+
} else {
442+
// SAFETY: The above pattern will always match, since we just
443+
// set `self` equal to `Both`.
444+
unsafe { std::hint::unreachable_unchecked() }
445+
}
446+
}
447+
}
448+
}
449+
450+
/// Set `self` to `Both(..)`, containing the specified left and right values,
451+
/// and returns a mutable reference to those values.
452+
pub fn insert_both(&mut self, left: A, right: B) -> (&mut A, &mut B) {
453+
*self = Both(left, right);
454+
if let Both(left, right) = self {
455+
(left, right)
456+
} else {
457+
// SAFETY: The above pattern will always match, since we just
458+
// set `self` equal to `Both`.
459+
unsafe { std::hint::unreachable_unchecked() }
460+
}
461+
}
230462
}
231463

232464
impl<T> EitherOrBoth<T, T> {

0 commit comments

Comments
 (0)