1use super::functions::*;
5
6#[allow(dead_code)]
12pub struct EitherTMonad<M, E, A> {
13 pub inner: Vec<OxiEither<A, E>>,
16 _phantom: std::marker::PhantomData<M>,
18}
19#[allow(dead_code)]
20impl<M, E: Clone, A: Clone> EitherTMonad<M, E, A> {
21 pub fn new(value: OxiEither<A, E>) -> Self {
23 Self {
24 inner: vec![value],
25 _phantom: std::marker::PhantomData,
26 }
27 }
28 pub fn pure(a: A) -> Self {
30 Self::new(OxiEither::Left(a))
31 }
32 pub fn throw(e: E) -> Self {
34 Self::new(OxiEither::Right(e))
35 }
36 pub fn run(self) -> Option<OxiEither<A, E>> {
38 self.inner.into_iter().next()
39 }
40 pub fn bind<B: Clone, F>(self, f: F) -> EitherTMonad<M, E, B>
42 where
43 F: FnOnce(A) -> EitherTMonad<M, E, B>,
44 {
45 match self.run() {
46 Some(OxiEither::Left(a)) => f(a),
47 Some(OxiEither::Right(e)) => EitherTMonad::<M, E, B>::throw(e),
48 None => EitherTMonad {
49 inner: vec![],
50 _phantom: std::marker::PhantomData,
51 },
52 }
53 }
54 pub fn map<B: Clone, F: FnOnce(A) -> B>(self, f: F) -> EitherTMonad<M, E, B> {
56 match self.run() {
57 Some(OxiEither::Left(a)) => EitherTMonad::<M, E, B>::new(OxiEither::Left(f(a))),
58 Some(OxiEither::Right(e)) => EitherTMonad::<M, E, B>::new(OxiEither::Right(e)),
59 None => EitherTMonad {
60 inner: vec![],
61 _phantom: std::marker::PhantomData,
62 },
63 }
64 }
65}
66#[allow(dead_code)]
68pub struct EitherKleisli<E, A, B> {
69 pub run: Box<dyn Fn(A) -> OxiEither<B, E>>,
71}
72#[allow(dead_code)]
73impl<E: 'static, A: 'static, B: 'static> EitherKleisli<E, A, B> {
74 pub fn new<F: Fn(A) -> OxiEither<B, E> + 'static>(f: F) -> Self {
76 Self { run: Box::new(f) }
77 }
78 pub fn apply(&self, a: A) -> OxiEither<B, E> {
80 (self.run)(a)
81 }
82 pub fn compose<C: 'static>(self, g: EitherKleisli<E, B, C>) -> EitherKleisli<E, A, C>
84 where
85 E: Clone + 'static,
86 {
87 EitherKleisli::new(move |a: A| match (self.run)(a) {
88 OxiEither::Left(b) => (g.run)(b),
89 OxiEither::Right(e) => OxiEither::Right(e),
90 })
91 }
92 pub fn lift_fn<F: Fn(A) -> B + 'static>(f: F) -> Self {
94 Self::new(move |a| OxiEither::Left(f(a)))
95 }
96}
97#[allow(dead_code)]
103pub struct SelectCombinator<E, A, B> {
104 pub lhs: OxiEither<A, E>,
106 pub rhs: OxiEither<Box<dyn Fn(A) -> B>, E>,
108}
109#[allow(dead_code)]
110impl<E: Clone, A, B> SelectCombinator<E, A, B> {
111 pub fn new(lhs: OxiEither<A, E>, rhs: OxiEither<Box<dyn Fn(A) -> B>, E>) -> Self {
113 Self { lhs, rhs }
114 }
115 pub fn select(self) -> OxiEither<B, E> {
117 match self.lhs {
118 OxiEither::Left(a) => match self.rhs {
119 OxiEither::Left(f) => OxiEither::Left(f(a)),
120 OxiEither::Right(e) => OxiEither::Right(e),
121 },
122 OxiEither::Right(e) => OxiEither::Right(e),
123 }
124 }
125 pub fn select_right_law(e: E) -> OxiEither<B, E> {
127 OxiEither::Right(e)
128 }
129}
130pub struct EitherLeftIter<A: Clone, B> {
132 pub(super) inner: Option<OxiEither<A, B>>,
133}
134impl<A: Clone, B> EitherLeftIter<A, B> {
135 pub fn new(e: OxiEither<A, B>) -> Self {
137 Self { inner: Some(e) }
138 }
139}
140#[derive(Clone, Debug, PartialEq, Eq)]
143pub enum OxiEither<A, B> {
144 Left(A),
146 Right(B),
148}
149impl<A, B> OxiEither<A, B> {
150 pub fn is_left(&self) -> bool {
152 matches!(self, OxiEither::Left(_))
153 }
154 pub fn is_right(&self) -> bool {
156 matches!(self, OxiEither::Right(_))
157 }
158 pub fn map_left<C, F: FnOnce(A) -> C>(self, f: F) -> OxiEither<C, B> {
160 match self {
161 OxiEither::Left(a) => OxiEither::Left(f(a)),
162 OxiEither::Right(b) => OxiEither::Right(b),
163 }
164 }
165 pub fn map_right<C, F: FnOnce(B) -> C>(self, f: F) -> OxiEither<A, C> {
167 match self {
168 OxiEither::Left(a) => OxiEither::Left(a),
169 OxiEither::Right(b) => OxiEither::Right(f(b)),
170 }
171 }
172 pub fn fold<C, FL: FnOnce(A) -> C, FR: FnOnce(B) -> C>(self, fl: FL, fr: FR) -> C {
174 match self {
175 OxiEither::Left(a) => fl(a),
176 OxiEither::Right(b) => fr(b),
177 }
178 }
179 pub fn swap(self) -> OxiEither<B, A> {
181 match self {
182 OxiEither::Left(a) => OxiEither::Right(a),
183 OxiEither::Right(b) => OxiEither::Left(b),
184 }
185 }
186 pub fn left_or(self, default: A) -> A {
188 match self {
189 OxiEither::Left(a) => a,
190 OxiEither::Right(_) => default,
191 }
192 }
193 pub fn right_or(self, default: B) -> B {
195 match self {
196 OxiEither::Left(_) => default,
197 OxiEither::Right(b) => b,
198 }
199 }
200 pub fn left(self) -> Option<A> {
202 match self {
203 OxiEither::Left(a) => Some(a),
204 OxiEither::Right(_) => None,
205 }
206 }
207 pub fn right(self) -> Option<B> {
209 match self {
210 OxiEither::Left(_) => None,
211 OxiEither::Right(b) => Some(b),
212 }
213 }
214 pub fn as_left(&self) -> Option<&A> {
216 match self {
217 OxiEither::Left(a) => Some(a),
218 OxiEither::Right(_) => None,
219 }
220 }
221 pub fn as_right(&self) -> Option<&B> {
223 match self {
224 OxiEither::Left(_) => None,
225 OxiEither::Right(b) => Some(b),
226 }
227 }
228}
229impl<T> OxiEither<T, T> {
230 pub fn merge<F: FnOnce(T) -> T>(self, f: F) -> T {
232 match self {
233 OxiEither::Left(a) | OxiEither::Right(a) => f(a),
234 }
235 }
236 pub fn into_inner(self) -> T {
238 match self {
239 OxiEither::Left(a) | OxiEither::Right(a) => a,
240 }
241 }
242}
243pub struct EitherRightIter<A, B> {
245 pub(super) inner: Option<OxiEither<A, B>>,
246}
247impl<A, B: Clone> EitherRightIter<A, B> {
248 pub fn new(e: OxiEither<A, B>) -> Self {
250 Self { inner: Some(e) }
251 }
252}
253#[allow(dead_code)]
255pub struct EitherPartition<L, R> {
256 pub lefts: Vec<L>,
258 pub rights: Vec<R>,
260}
261#[allow(dead_code)]
262impl<L, R> EitherPartition<L, R> {
263 pub fn from_iter<I: IntoIterator<Item = OxiEither<L, R>>>(iter: I) -> Self {
265 let mut lefts = Vec::new();
266 let mut rights = Vec::new();
267 for item in iter {
268 match item {
269 OxiEither::Left(l) => lefts.push(l),
270 OxiEither::Right(r) => rights.push(r),
271 }
272 }
273 Self { lefts, rights }
274 }
275 pub fn total(&self) -> usize {
277 self.lefts.len() + self.rights.len()
278 }
279 pub fn no_lefts(&self) -> bool {
281 self.lefts.is_empty()
282 }
283 pub fn no_rights(&self) -> bool {
285 self.rights.is_empty()
286 }
287 pub fn left_ratio(&self) -> f64 {
289 let total = self.total();
290 if total == 0 {
291 0.0
292 } else {
293 self.lefts.len() as f64 / total as f64
294 }
295 }
296}
297pub struct RightIter<A, B, I: Iterator<Item = OxiEither<A, B>>> {
299 pub(super) inner: I,
300}
301pub struct LeftIter<A, B, I: Iterator<Item = OxiEither<A, B>>> {
303 pub(super) inner: I,
304}
305#[derive(Clone, Debug, PartialEq, Eq)]
307pub enum TripleSum<A, B, C> {
308 First(A),
310 Second(B),
312 Third(C),
314}
315impl<A, B, C> TripleSum<A, B, C> {
316 pub fn to_nested(self) -> OxiEither<A, OxiEither<B, C>> {
318 match self {
319 TripleSum::First(a) => OxiEither::Left(a),
320 TripleSum::Second(b) => OxiEither::Right(OxiEither::Left(b)),
321 TripleSum::Third(c) => OxiEither::Right(OxiEither::Right(c)),
322 }
323 }
324 pub fn is_first(&self) -> bool {
326 matches!(self, TripleSum::First(_))
327 }
328 pub fn is_second(&self) -> bool {
330 matches!(self, TripleSum::Second(_))
331 }
332 pub fn is_third(&self) -> bool {
334 matches!(self, TripleSum::Third(_))
335 }
336}
337#[allow(dead_code)]
339pub struct EitherTraversal<A, B> {
340 pub successes: Vec<B>,
342 pub error: Option<A>,
344}
345#[allow(dead_code)]
346impl<A, B> EitherTraversal<A, B> {
347 pub fn new() -> Self {
349 Self {
350 successes: Vec::new(),
351 error: None,
352 }
353 }
354 pub fn step(&mut self, value: OxiEither<B, A>) {
357 if self.error.is_some() {
358 return;
359 }
360 match value {
361 OxiEither::Left(b) => self.successes.push(b),
362 OxiEither::Right(a) => self.error = Some(a),
363 }
364 }
365 pub fn finish(self) -> OxiEither<Vec<B>, A> {
368 match self.error {
369 None => OxiEither::Left(self.successes),
370 Some(e) => OxiEither::Right(e),
371 }
372 }
373 pub fn has_error(&self) -> bool {
375 self.error.is_some()
376 }
377 pub fn success_count(&self) -> usize {
379 self.successes.len()
380 }
381}
382#[derive(Clone, Debug)]
384pub struct EitherIter<A, B> {
385 inner: OxiEither<A, B>,
386 done: bool,
387}
388impl<A: Clone, B: Clone> EitherIter<A, B> {
389 pub fn new(e: OxiEither<A, B>) -> Self {
391 Self {
392 inner: e,
393 done: false,
394 }
395 }
396}