1use crate::functor::Functor;
2use crate::hkt::OptionF;
3use crate::hkt::ResultF;
4#[cfg(any(feature = "std", feature = "alloc"))]
5use crate::hkt::VecF;
6#[cfg(all(not(feature = "std"), feature = "alloc"))]
7use alloc::vec::Vec;
8
9pub trait Alt: Functor {
15 fn alt<A>(fa1: Self::Of<A>, fa2: Self::Of<A>) -> Self::Of<A>;
16}
17
18impl Alt for OptionF {
19 fn alt<A>(fa1: Option<A>, fa2: Option<A>) -> Option<A> {
20 fa1.or(fa2)
21 }
22}
23
24impl<E> Alt for ResultF<E> {
25 fn alt<A>(fa1: Result<A, E>, fa2: Result<A, E>) -> Result<A, E> {
26 fa1.or(fa2)
27 }
28}
29
30#[cfg(any(feature = "std", feature = "alloc"))]
31impl Alt for VecF {
32 fn alt<A>(mut fa1: Vec<A>, fa2: Vec<A>) -> Vec<A> {
33 fa1.extend(fa2);
34 fa1
35 }
36}
37
38#[cfg(any(feature = "std", feature = "alloc"))]
39impl Alt for crate::hkt::NonEmptyVecF {
40 fn alt<A>(
41 mut fa1: crate::hkt::NonEmptyVec<A>,
42 fa2: crate::hkt::NonEmptyVec<A>,
43 ) -> crate::hkt::NonEmptyVec<A> {
44 fa1.tail.push(fa2.head);
45 fa1.tail.extend(fa2.tail);
46 fa1
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn option_alt_some_some() {
56 assert_eq!(OptionF::alt(Some(1), Some(2)), Some(1));
57 }
58
59 #[test]
60 fn option_alt_none_some() {
61 assert_eq!(OptionF::alt(None, Some(2)), Some(2));
62 }
63
64 #[test]
65 fn option_alt_none_none() {
66 assert_eq!(OptionF::alt(None::<i32>, None), None);
67 }
68
69 #[test]
70 fn result_alt() {
71 assert_eq!(ResultF::<&str>::alt(Err("a"), Ok(2)), Ok(2));
72 assert_eq!(ResultF::<&str>::alt(Ok(1), Ok(2)), Ok(1));
73 }
74
75 #[test]
76 fn vec_alt() {
77 assert_eq!(VecF::alt(vec![1, 2], vec![3, 4]), vec![1, 2, 3, 4]);
78 }
79}
80
81#[cfg(test)]
82mod law_tests {
83 use super::*;
84 use crate::functor::Functor;
85 use proptest::prelude::*;
86
87 proptest! {
88 #[test]
90 fn option_associativity(
91 a in any::<Option<i32>>(),
92 b in any::<Option<i32>>(),
93 c in any::<Option<i32>>()
94 ) {
95 let left = OptionF::alt(OptionF::alt(a, b), c);
96 let right = OptionF::alt(a, OptionF::alt(b, c));
97 prop_assert_eq!(left, right);
98 }
99
100 #[test]
102 fn option_distributivity(
103 a in any::<Option<i32>>(),
104 b in any::<Option<i32>>()
105 ) {
106 let f = |x: i32| x.wrapping_add(1);
107 let left = OptionF::fmap(OptionF::alt(a, b), f);
108 let right = OptionF::alt(OptionF::fmap(a, f), OptionF::fmap(b, f));
109 prop_assert_eq!(left, right);
110 }
111
112 #[test]
113 fn vec_associativity(
114 a in prop::collection::vec(any::<i32>(), 0..5),
115 b in prop::collection::vec(any::<i32>(), 0..5),
116 c in prop::collection::vec(any::<i32>(), 0..5)
117 ) {
118 let left = VecF::alt(VecF::alt(a.clone(), b.clone()), c.clone());
119 let right = VecF::alt(a, VecF::alt(b, c));
120 prop_assert_eq!(left, right);
121 }
122 }
123}