h2s_core/
transformable.rs

1use crate::functor::ExactlyOne;
2use crate::Error;
3use crate::Never;
4
5/// Tries to transform from `F<T>` to `G<T>`.
6pub trait TransformableFrom<T>: Sized {
7    type Error: Error;
8    fn try_transform_from(t: T) -> Result<Self, Self::Error>;
9}
10
11impl<T> TransformableFrom<T> for T {
12    type Error = Never;
13
14    fn try_transform_from(t: T) -> Result<Self, Self::Error> {
15        Ok(t)
16    }
17}
18
19impl<T> TransformableFrom<Vec<T>> for ExactlyOne<T> {
20    type Error = VecToSingleError;
21
22    fn try_transform_from(mut t: Vec<T>) -> Result<Self, Self::Error> {
23        if t.len() > 1 {
24            Err(VecToSingleError::TooManyElements { found: t.len() })
25        } else {
26            t.pop().map(ExactlyOne).ok_or(VecToSingleError::NoElements)
27        }
28    }
29}
30
31impl<N, const A: usize> TransformableFrom<Vec<N>> for [N; A] {
32    type Error = VecToArrayError;
33
34    fn try_transform_from(t: Vec<N>) -> Result<Self, Self::Error> {
35        t.try_into()
36            .map_err(|v: Vec<_>| VecToArrayError::ElementNumberUnmatched {
37                expected: A,
38                found: v.len(),
39            })
40    }
41}
42
43impl<N> TransformableFrom<Vec<N>> for Option<N> {
44    type Error = VecToOptionError;
45
46    fn try_transform_from(mut t: Vec<N>) -> Result<Self, Self::Error> {
47        if t.len() > 1 {
48            Err(Self::Error::TooManyElements { found: t.len() })
49        } else {
50            Ok(t.pop())
51        }
52    }
53}
54
55#[derive(Debug, Clone, Eq, PartialEq)]
56pub enum VecToSingleError {
57    TooManyElements { found: usize },
58    NoElements,
59}
60
61#[derive(Debug, Clone, Eq, PartialEq)]
62pub enum VecToArrayError {
63    ElementNumberUnmatched { expected: usize, found: usize },
64}
65
66#[derive(Debug, Clone, Eq, PartialEq)]
67pub enum VecToOptionError {
68    TooManyElements { found: usize },
69}
70
71#[cfg(test)]
72mod test {
73    use crate::functor::ExactlyOne;
74    use crate::transformable::TransformableFrom;
75    use crate::transformable::{VecToArrayError, VecToOptionError, VecToSingleError};
76
77    #[test]
78    fn identity() {
79        assert_eq!(
80            ExactlyOne::try_transform_from(ExactlyOne(0)),
81            Ok(ExactlyOne(0))
82        );
83    }
84
85    #[test]
86    fn vec_to_single() {
87        assert_eq!(ExactlyOne::try_transform_from(vec![0]), Ok(ExactlyOne(0)));
88        assert_eq!(
89            ExactlyOne::<()>::try_transform_from(vec![]),
90            Err(VecToSingleError::NoElements),
91        );
92        assert_eq!(
93            ExactlyOne::try_transform_from(vec![0, 1]),
94            Err(VecToSingleError::TooManyElements { found: 2 }),
95        );
96    }
97
98    #[test]
99    fn vec_to_array() {
100        assert_eq!(
101            <[_; 2]>::try_transform_from(vec!["foo", "bar"]),
102            Ok(["foo", "bar"])
103        );
104        assert_eq!(
105            <[&str; 3]>::try_transform_from(vec!["foo", "var"]),
106            Err(VecToArrayError::ElementNumberUnmatched {
107                expected: 3,
108                found: 2
109            }),
110        );
111    }
112
113    #[test]
114    fn vec_to_option() {
115        assert_eq!(Option::<()>::try_transform_from(vec![]), Ok(None),);
116        assert_eq!(Option::try_transform_from(vec!["foo"]), Ok(Some("foo")));
117        assert_eq!(
118            Option::try_transform_from(vec!["foo", "var"]),
119            Err(VecToOptionError::TooManyElements { found: 2 })
120        );
121    }
122}