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