1#![no_std]
2
3pub use enumorph_derive::Enumorph;
4
5pub 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 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 }
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}