enumorph/
lib.rs

1#![no_std]
2
3pub use enumorph_derive::Enumorph;
4
5/// Convenience trait around the conversions provided by [`Enumorph`], but with
6/// the generics on the functions instead of the trait.
7///
8/// ```rust
9/// use enumorph::{Enumorph, EnumorphAs};
10///
11/// #[derive(Enumorph)]
12/// enum Enum1 {
13///     A(A),
14///     B(B),
15/// }
16///
17/// #[derive(Enumorph)]
18/// enum Enum2 {
19///     A(A),
20///     C(C),
21/// }
22///
23/// struct A;
24/// struct B;
25/// struct C;
26///
27/// let enum_1 = A.widen::<Enum1>();
28/// let enum_2 = A.widen::<Enum2>();
29/// ```
30pub trait EnumorphAs: Sized {
31    fn widen<T>(self) -> T
32    where
33        Self: Into<T>,
34    {
35        self.into()
36    }
37
38    fn narrow<T>(self) -> Result<T, Self>
39    where
40        Self: TryInto<T, Error = Self>,
41    {
42        self.try_into()
43    }
44}
45
46impl<T> EnumorphAs for T {}
47
48pub trait Enumorph<T>: TryFrom<T, Error = T> + Into<T> {}
49impl<T, U> Enumorph<U> for T where T: TryFrom<U, Error = U> + Into<U> {}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn enumorph_as() {
57        #[derive(Debug, PartialEq, Enumorph)]
58        enum Enum<T, U> {
59            A(A<T>),
60            B(B<U>),
61        }
62
63        #[derive(Debug, PartialEq)]
64        struct A<T>(T);
65
66        #[derive(Debug, PartialEq)]
67        struct B<U>(U);
68
69        assert_eq!(A("a").widen::<Enum<&str, u8>>(), Enum::A(A("a")));
70        assert_eq!(Enum::<&str, u8>::A(A("a")).narrow::<A<_>>(), Ok(A("a")));
71
72        assert_eq!(B(1).widen::<Enum<&str, u8>>(), Enum::B(B(1)));
73        assert_eq!(Enum::<&str, u8>::B(B(1)).narrow::<B<_>>(), Ok(B(1)));
74    }
75
76    #[test]
77    fn try_from_into() {
78        #[derive(Debug, PartialEq, Enumorph)]
79        enum A {
80            B(B),
81            C(C),
82            D(D),
83        }
84
85        #[derive(Debug, PartialEq)]
86        struct B;
87        #[derive(Debug, PartialEq)]
88        struct C;
89
90        #[derive(Debug, PartialEq, Enumorph)]
91        enum D {
92            E(E),
93        }
94
95        #[derive(Debug, PartialEq)]
96        struct E;
97
98        assert!(matches!(A::B(B).try_into(), Ok(B)));
99        assert!(matches!(A::C(C).try_into(), Ok(C)));
100        assert!(matches!(A::D(D::E(E)).try_into(), Ok(D::E(E))));
101        // currently doesn't work
102        // assert_eq!(A::D(D::E(E)).try_into(), Ok(E));
103
104        assert!(matches!(B.into(), A::B(B)));
105        assert!(matches!(C.into(), A::C(C)));
106        assert!(matches!(D::E(E).into(), A::D(D::E(E))));
107        // currently doesn't work
108        // assert!(matches!(E.into(), A::D(D::E(E))));
109    }
110
111    #[test]
112    fn ui() {
113        let t = trybuild::TestCases::new();
114        t.pass("tests/ui/pass/*.rs");
115        t.compile_fail("tests/ui/compile_fail/*.rs");
116    }
117}