1use crate::hkt::HKT;
2
3pub trait NaturalTransformation<F: HKT, G: HKT> {
8 fn transform<A>(fa: F::Of<A>) -> G::Of<A>;
9}
10
11#[cfg(any(feature = "std", feature = "alloc"))]
13pub struct OptionToVec;
14
15#[cfg(any(feature = "std", feature = "alloc"))]
16impl NaturalTransformation<crate::hkt::OptionF, crate::hkt::VecF> for OptionToVec {
17 fn transform<A>(fa: Option<A>) -> Vec<A> {
18 match fa {
19 Some(a) => vec![a],
20 None => vec![],
21 }
22 }
23}
24
25#[cfg(any(feature = "std", feature = "alloc"))]
27pub struct VecHeadToOption;
28
29#[cfg(any(feature = "std", feature = "alloc"))]
30impl NaturalTransformation<crate::hkt::VecF, crate::hkt::OptionF> for VecHeadToOption {
31 fn transform<A>(fa: Vec<A>) -> Option<A> {
32 fa.into_iter().next()
33 }
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39
40 #[test]
41 fn option_to_vec_some() {
42 assert_eq!(OptionToVec::transform(Some(42)), vec![42]);
43 }
44
45 #[test]
46 fn option_to_vec_none() {
47 assert_eq!(OptionToVec::transform(None::<i32>), Vec::<i32>::new());
48 }
49
50 #[test]
51 fn vec_head_to_option_non_empty() {
52 assert_eq!(VecHeadToOption::transform(vec![1, 2, 3]), Some(1));
53 }
54
55 #[test]
56 fn vec_head_to_option_empty() {
57 assert_eq!(VecHeadToOption::transform(Vec::<i32>::new()), None);
58 }
59}
60
61#[cfg(test)]
62mod law_tests {
63 use super::*;
64 use crate::functor::Functor;
65 use crate::hkt::{OptionF, VecF};
66 use proptest::prelude::*;
67
68 proptest! {
69 #[test]
71 fn option_to_vec_naturality(x in any::<Option<i32>>()) {
72 let f = |a: i32| a.wrapping_add(1);
73 let left = VecF::fmap(OptionToVec::transform(x), f);
74 let right = OptionToVec::transform(OptionF::fmap(x, f));
75 prop_assert_eq!(left, right);
76 }
77
78 #[test]
79 fn vec_head_to_option_naturality(x in prop::collection::vec(any::<i32>(), 0..10)) {
80 let f = |a: i32| a.wrapping_add(1);
81 let left = OptionF::fmap(VecHeadToOption::transform(x.clone()), f);
82 let right = VecHeadToOption::transform(VecF::fmap(x, f));
83 prop_assert_eq!(left, right);
84 }
85 }
86}