Skip to content

Commit 9fd2a75

Browse files
authored
feat: either_or combinator (#3417)
1 parent 429d1b1 commit 9fd2a75

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

either_of/src/lib.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,86 @@ where
3232
}
3333
}
3434

35+
pub trait EitherOr {
36+
type Left;
37+
type Right;
38+
fn either_or<FA, A, FB, B>(self, a: FA, b: FB) -> Either<A, B>
39+
where
40+
FA: FnOnce(Self::Left) -> A,
41+
FB: FnOnce(Self::Right) -> B;
42+
}
43+
44+
impl EitherOr for bool {
45+
type Left = ();
46+
type Right = ();
47+
48+
fn either_or<FA, A, FB, B>(self, a: FA, b: FB) -> Either<A, B>
49+
where
50+
FA: FnOnce(Self::Left) -> A,
51+
FB: FnOnce(Self::Right) -> B,
52+
{
53+
if self {
54+
Either::Left(a(()))
55+
} else {
56+
Either::Right(b(()))
57+
}
58+
}
59+
}
60+
61+
impl<T> EitherOr for Option<T> {
62+
type Left = T;
63+
type Right = ();
64+
65+
fn either_or<FA, A, FB, B>(self, a: FA, b: FB) -> Either<A, B>
66+
where
67+
FA: FnOnce(Self::Left) -> A,
68+
FB: FnOnce(Self::Right) -> B,
69+
{
70+
match self {
71+
Some(t) => Either::Left(a(t)),
72+
None => Either::Right(b(())),
73+
}
74+
}
75+
}
76+
77+
impl<T, E> EitherOr for Result<T, E> {
78+
type Left = T;
79+
type Right = E;
80+
81+
fn either_or<FA, A, FB, B>(self, a: FA, b: FB) -> Either<A, B>
82+
where
83+
FA: FnOnce(Self::Left) -> A,
84+
FB: FnOnce(Self::Right) -> B,
85+
{
86+
match self {
87+
Ok(t) => Either::Left(a(t)),
88+
Err(err) => Either::Right(b(err)),
89+
}
90+
}
91+
}
92+
93+
#[test]
94+
fn test_either_or() {
95+
let right = false.either_or(|_| 'a', |_| 12);
96+
assert!(matches!(right, Either::Right(12)));
97+
98+
let left = true.either_or(|_| 'a', |_| 12);
99+
assert!(matches!(left, Either::Left('a')));
100+
101+
let left = Some(12).either_or(|a| a, |_| 'a');
102+
assert!(matches!(left, Either::Left(12)));
103+
let right = None.either_or(|a: i32| a, |_| 'a');
104+
assert!(matches!(right, Either::Right('a')));
105+
106+
let result: Result<_, ()> = Ok(1.2f32);
107+
let left = result.either_or(|a| a * 2f32, |b| b);
108+
assert!(matches!(left, Either::Left(2.4f32)));
109+
110+
let result: Result<i32, _> = Err("12");
111+
let right = result.either_or(|a| a, |b| b.chars().next());
112+
assert!(matches!(right, Either::Right(Some('1'))));
113+
}
114+
35115
pin_project! {
36116
#[project = EitherFutureProj]
37117
pub enum EitherFuture<A, B> {

0 commit comments

Comments
 (0)