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