enum_ref_macro/lib.rs
1use proc_macro::TokenStream;
2use syn::{parse_macro_input, DeriveInput};
3
4#[macro_use]
5mod error;
6mod derive;
7mod utils;
8
9/// Proc. macro to derive [`EnumRef`] trait for the Rust `enum`.
10///
11/// This generates a new `enum` that mirrors all variants of the
12/// original `enum` type but wraps all variant field in a shared
13/// reference.
14/// Furthermore it implement the [`EnumRef`] trait for the original
15/// `enum` in order to make the generated `enum` accessible.
16///
17/// # Example
18///
19/// ```
20/// use enum_ref::EnumRef;
21///
22/// #[derive(EnumRef)]
23/// #[repr(u8)] // Rust requires this for `B = 42`
24/// enum Test {
25/// A,
26/// B = 42,
27/// C(i32),
28/// D(i32, i64),
29/// E { a: i32 },
30/// F { a: i32, b: i64 },
31/// }
32///
33/// // Access and name the generated `enum` as follows:
34/// type TestRef<'a> = <Test as EnumRef>::Ref<'a>;
35///
36/// // Creates reference wrappers of `enum` instances as follows:
37/// let test = Test::C(42);
38/// let test_ref: TestRef = <Test as EnumRef>::as_ref(&test);
39/// match (&test, test_ref) {
40/// (Test::C(a0), TestRef::C(a1)) => assert_eq!(a0, a1),
41/// _ => panic!("something wen't wrong ..."),
42/// }
43/// ```
44///
45/// The `#[derive(EnumRef)]` in the above example will generate roughly the following Rust code.
46///
47/// ```
48/// # #[repr(u8)] // Rust requires this for `B = 42`
49/// # enum Test {
50/// # A,
51/// # B = 42,
52/// # C(i32),
53/// # D(i32, i64),
54/// # E { a: i32 },
55/// # F { a: i32, b: i64 },
56/// # }
57/// #
58/// const _: () = {
59/// #[derive(::core::fmt::Debug)]
60/// #[repr(u8)]
61/// pub enum TestRef<'__enum_ref_lt> {
62/// A,
63/// B = 42,
64/// C(&'__enum_ref_lt i32),
65/// D(&'__enum_ref_lt i32, &'__enum_ref_lt i64),
66/// E {
67/// a: &'__enum_ref_lt i32,
68/// },
69/// F {
70/// a: &'__enum_ref_lt i32,
71/// b: &'__enum_ref_lt i64,
72/// },
73/// }
74///
75/// impl ::enum_ref::EnumRef for Test {
76/// type Ref<'__enum_ref_lt> where Self: '__enum_ref_lt =
77/// TestRef<'__enum_ref_lt> where Self: '__enum_ref_lt;
78/// fn as_ref(&self) -> <Self as ::enum_ref::EnumRef>::Ref<'_> {
79/// type __enum_ref_EnumRef_Ref<'__enum_ref_lt> =
80/// <Test as ::enum_ref::EnumRef>::Ref<'__enum_ref_lt>;
81/// match self {
82/// Self::A => __enum_ref_EnumRef_Ref::A,
83/// Self::B => __enum_ref_EnumRef_Ref::B,
84/// Self::C(_0) => __enum_ref_EnumRef_Ref::C(_0),
85/// Self::D(_0, _1) => __enum_ref_EnumRef_Ref::D(_0, _1),
86/// Self::E { a } => __enum_ref_EnumRef_Ref::E { a },
87/// Self::F { a, b } => __enum_ref_EnumRef_Ref::F { a, b },
88/// }
89/// }
90/// }
91/// };
92/// ```
93#[proc_macro_derive(EnumRef)]
94pub fn enum_ref(input: TokenStream) -> TokenStream {
95 derive::enum_ref(parse_macro_input!(input as DeriveInput)).into()
96}
97
98/// Proc. macro to derive [`EnumMut`] trait for the Rust `enum`.
99///
100/// This generates a new `enum` that mirrors all variants of the
101/// original `enum` type but wraps all variant field in an exclusive
102/// reference.
103/// Furthermore it implement the [`EnumMut`] trait for the original
104/// `enum` in order to make the generated `enum` accessible.
105///
106/// # Example
107///
108/// ```
109/// use enum_ref::EnumMut;
110///
111/// # #[derive(Clone)]
112/// #[derive(EnumMut)]
113/// #[repr(u8)] // Rust requires this for `B = 42`
114/// enum Test {
115/// A,
116/// B = 42,
117/// C(i32),
118/// D(i32, i64),
119/// E { a: i32 },
120/// F { a: i32, b: i64 },
121/// }
122///
123/// // Access and name the generated `enum` as follows:
124/// type TestMut<'a> = <Test as EnumMut>::Mut<'a>;
125///
126/// // Creates reference wrappers of `enum` instances as follows:
127/// let mut test0 = Test::C(42);
128/// let mut test1 = test0.clone();
129/// let test_ref: TestMut = <Test as EnumMut>::as_mut(&mut test0);
130/// match (&mut test1, test_ref) {
131/// (Test::C(a0), TestMut::C(a1)) => assert_eq!(a0, a1),
132/// _ => panic!("something wen't wrong ..."),
133/// }
134/// ```
135///
136/// The `#[derive(EnumMut)]` in the above example will generate roughly the following Rust code.
137///
138/// ```
139/// # #[repr(u8)] // Rust requires this for `B = 42`
140/// # enum Test {
141/// # A,
142/// # B = 42,
143/// # C(i32),
144/// # D(i32, i64),
145/// # E { a: i32 },
146/// # F { a: i32, b: i64 },
147/// # }
148/// #
149/// const _: () = {
150/// #[derive(::core::fmt::Debug)]
151/// #[repr(u8)]
152/// pub enum TestMut<'__enum_ref_lt> {
153/// A,
154/// B = 42,
155/// C(&'__enum_ref_lt mut i32),
156/// D(&'__enum_ref_lt mut i32, &'__enum_ref_lt mut i64),
157/// E {
158/// a: &'__enum_ref_lt mut i32,
159/// },
160/// F {
161/// a: &'__enum_ref_lt mut i32,
162/// b: &'__enum_ref_lt mut i64,
163/// },
164/// }
165///
166/// impl ::enum_ref::EnumMut for Test {
167/// type Mut<'__enum_ref_lt> where Self: '__enum_ref_lt =
168/// TestMut<'__enum_ref_lt> where Self: '__enum_ref_lt;
169/// fn as_mut(&mut self) -> <Self as ::enum_ref::EnumMut>::Mut<'_> {
170/// type __enum_ref_EnumMut_Mut<'__enum_ref_lt> =
171/// <Test as ::enum_ref::EnumMut>::Mut<'__enum_ref_lt>;
172/// match self {
173/// Self::A => __enum_ref_EnumMut_Mut::A,
174/// Self::B => __enum_ref_EnumMut_Mut::B,
175/// Self::C(_0) => __enum_ref_EnumMut_Mut::C(_0),
176/// Self::D(_0, _1) => __enum_ref_EnumMut_Mut::D(_0, _1),
177/// Self::E { a } => __enum_ref_EnumMut_Mut::E { a },
178/// Self::F { a, b } => __enum_ref_EnumMut_Mut::F { a, b },
179/// }
180/// }
181/// }
182/// };
183/// ```
184#[proc_macro_derive(EnumMut)]
185pub fn enum_mut(input: TokenStream) -> TokenStream {
186 derive::enum_mut(parse_macro_input!(input as DeriveInput)).into()
187}