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