enumcapsulate_macros/lib.rs
1use proc_macro::TokenStream;
2use syn::parse_macro_input;
3
4use crate::utils::tokenstream;
5
6mod config;
7mod enum_deriver;
8mod type_visitor;
9mod type_visitor_mut;
10mod utils;
11
12use self::{config::*, enum_deriver::*, type_visitor::*, utils::*};
13
14/// Derive macro generating an impl of the trait `From<T>`.
15///
16/// It generates an impl for each of the enum's
17/// newtype variants, where `Inner` is the variant's field type
18/// and `Outer` is the enclosing enum's type.
19///
20/// ```ignore
21/// struct Inner;
22///
23/// enum Outer {
24/// Inner(Inner),
25/// // ...
26/// }
27///
28/// // The generated impls look something along these lines:
29///
30/// impl From<Inner> for Outer {
31/// fn from(inner: Inner) -> Self {
32/// Outer::Inner(inner)
33/// }
34/// }
35///
36/// // ...
37/// ```
38///
39#[proc_macro_derive(From, attributes(enumcapsulate))]
40pub fn derive_from(input: TokenStream) -> TokenStream {
41 let item = parse_macro_input!(input as syn::ItemEnum);
42
43 tokenstream(|| {
44 let deriver = EnumDeriver::from(item);
45 deriver.derive_from()
46 })
47}
48
49/// Derive macro generating an impl of the trait `TryFrom<T>`.
50///
51/// It generates an impl for each of the enum's newtype variants,
52/// where `Inner` is the variant's field type and `Outer`
53/// is the enclosing enum's type.
54///
55/// ```ignore
56/// struct Inner;
57///
58/// enum Outer {
59/// Inner(Inner),
60/// // ...
61/// }
62///
63/// // The generated impls look something along these lines:
64///
65/// impl TryFrom<Outer> for Inner {
66/// type Error = Outer;
67///
68/// fn try_from(outer: Outer) -> Result<Self, Self::Error> {
69/// match outer {
70/// Outer::Inner(inner) => Ok(inner),
71/// err => Err(err),
72/// }
73/// }
74/// }
75///
76/// // ...
77/// ```
78///
79/// Note: Despite the derive macro's name it's actually `TryFrom<T>`
80/// that's being derives, not `TryInto<T>`.
81/// But since the macro is derived on the enum the latter feels
82/// more appropriate as the derive's name.
83#[proc_macro_derive(TryInto, attributes(enumcapsulate))]
84pub fn derive_try_from(input: TokenStream) -> TokenStream {
85 let item = parse_macro_input!(input as syn::ItemEnum);
86
87 tokenstream(|| {
88 let deriver = EnumDeriver::from(item);
89 deriver.derive_try_into()
90 })
91}
92
93/// Derive macro generating an impl of the trait `FromVariant<T>`.
94///
95/// It generates an impl for each of the enum's
96/// newtype variants, where `Inner` is the variant's field type
97/// and `Outer` is the enclosing enum's type.
98///
99/// ```ignore
100/// # use enumcapsulate::FromVariant;
101/// #
102/// # struct Inner;
103///
104/// enum Outer {
105/// Inner(Inner),
106/// // ...
107/// }
108///
109/// // The generated impls look something along these lines:
110///
111/// impl FromVariant<Inner> for Outer {
112/// fn from_variant(inner: Inner) -> Self {
113/// Outer::Inner(inner)
114/// }
115/// }
116///
117/// // ...
118/// ```
119///
120#[proc_macro_derive(FromVariant, attributes(enumcapsulate))]
121pub fn derive_from_variant(input: TokenStream) -> TokenStream {
122 let item = parse_macro_input!(input as syn::ItemEnum);
123
124 tokenstream(|| {
125 let deriver = EnumDeriver::from(item);
126 deriver.derive_from_variant()
127 })
128}
129
130/// Derive macro generating an impl of the trait `FromVariant<T>`.
131///
132/// It generates an impl for each of the enum's
133/// newtype variants, where `Inner` is the variant's field type
134/// and `Outer` is the enclosing enum's type.
135///
136/// ```ignore
137/// # use enumcapsulate::AsVariant;
138///
139/// #[derive(Clone)]
140/// struct Inner;
141///
142/// enum Outer {
143/// Inner(Inner),
144/// // ...
145/// }
146///
147/// // The generated impls look something along these lines:
148///
149/// impl AsVariant<Inner> for Outer where Inner: Clone {
150/// fn as_variant(&self) -> Option<Inner> {
151/// match self {
152/// Outer::Inner(inner) => Some(inner.clone()),
153/// _ => None,
154/// }
155/// }
156/// }
157///
158/// // ...
159/// ```
160///
161#[proc_macro_derive(AsVariant, attributes(enumcapsulate))]
162pub fn derive_as_variant(input: TokenStream) -> TokenStream {
163 let item = parse_macro_input!(input as syn::ItemEnum);
164
165 tokenstream(|| {
166 let deriver = EnumDeriver::from(item);
167 deriver.derive_as_variant()
168 })
169}
170
171/// Derive macro generating an impl of the trait `FromVariant<T>`.
172///
173/// It generates an impl for each of the enum's
174/// newtype variants, where `Inner` is the variant's field type
175/// and `Outer` is the enclosing enum's type.
176///
177/// ```ignore
178/// # use enumcapsulate::AsVariantRef;
179///
180/// struct Inner;
181///
182/// enum Outer {
183/// Inner(Inner),
184/// // ...
185/// }
186///
187/// // The generated impls look something along these lines:
188///
189/// impl AsVariantRef<Inner> for Outer {
190/// fn as_variant_ref(&self) -> Option<&Inner> {
191/// match self {
192/// Outer::Inner(inner) => Some(inner),
193/// _ => None,
194/// }
195/// }
196/// }
197///
198/// // ...
199/// ```
200///
201#[proc_macro_derive(AsVariantRef, attributes(enumcapsulate))]
202pub fn derive_as_variant_ref(input: TokenStream) -> TokenStream {
203 let item = parse_macro_input!(input as syn::ItemEnum);
204
205 tokenstream(|| {
206 let deriver = EnumDeriver::from(item);
207 deriver.derive_as_variant_ref()
208 })
209}
210
211/// Derive macro generating an impl of the trait `From<T>`.
212///
213/// It generates an impl for each of the enum's
214/// newtype variants, where `Inner` is the variant's field type
215/// and `Outer` is the enclosing enum's type.
216///
217/// ```ignore
218/// # use enumcapsulate::AsVariantMut;
219///
220/// struct Inner;
221///
222/// enum Outer {
223/// Inner(Inner),
224/// // ...
225/// }
226///
227/// // The generated impls look something along these lines:
228///
229/// impl AsVariantMut<Inner> for Outer {
230/// fn as_variant_mut(&mut self) -> Option<&mut Inner> {
231/// match self {
232/// Outer::Inner(inner) => Some(inner),
233/// _ => None,
234/// }
235/// }
236/// }
237///
238/// // ...
239/// ```
240///
241#[proc_macro_derive(AsVariantMut, attributes(enumcapsulate))]
242pub fn derive_as_variant_mut(input: TokenStream) -> TokenStream {
243 let item = parse_macro_input!(input as syn::ItemEnum);
244
245 tokenstream(|| {
246 let deriver = EnumDeriver::from(item);
247 deriver.derive_as_variant_mut()
248 })
249}
250
251/// Derive macro generating an impl of the trait `IntoVariant<T>`.
252///
253/// It generates an impl for each of the enum's
254/// newtype variants, where `Inner` is the variant's field type
255/// and `Outer` is the enclosing enum's type.
256///
257/// ```ignore
258/// # use enumcapsulate::IntoVariant;
259///
260/// struct Inner;
261///
262/// enum Outer {
263/// Inner(Inner),
264/// // ...
265/// }
266///
267/// // The generated impls look something along these lines:
268///
269/// impl IntoVariant<Inner> for Outer {
270/// fn into_variant(self) -> Result<T, Self> {
271/// match self {
272/// Outer::Inner(inner) => Ok(inner),
273/// err => Err(err),
274/// }
275/// }
276/// }
277///
278/// // ...
279/// ```
280///
281/// Note: Despite the derive macro's name it's actually `TryFrom<T>`
282/// that's being derives, not `TryInto<T>`.
283/// But since the macro is derived on the enum the latter feels
284/// more appropriate as the derive's name.
285#[proc_macro_derive(IntoVariant, attributes(enumcapsulate))]
286pub fn derive_into_variant(input: TokenStream) -> TokenStream {
287 let item = parse_macro_input!(input as syn::ItemEnum);
288
289 tokenstream(|| {
290 let deriver = EnumDeriver::from(item);
291 deriver.derive_into_variant()
292 })
293}
294
295/// Derive macro generating an impl of the trait `VariantDowncast`.
296///
297/// ```ignore
298/// struct Inner;
299///
300/// enum Outer {
301/// Inner(Inner),
302/// // ...
303/// }
304///
305/// // The generated impl looks something along these lines:
306///
307/// impl VariantDowncast for Outer {}
308/// ```
309///
310#[proc_macro_derive(VariantDowncast, attributes(enumcapsulate))]
311pub fn derive_variant_downcast(input: TokenStream) -> TokenStream {
312 let item = parse_macro_input!(input as syn::ItemEnum);
313
314 tokenstream(|| {
315 let deriver = EnumDeriver::from(item);
316 deriver.derive_variant_downcast()
317 })
318}
319
320/// Derive macro generating an impl of the trait `VariantDiscriminant`.
321///
322/// ```ignore
323/// struct Inner;
324///
325/// enum Outer {
326/// Inner(Inner),
327/// // ...
328/// }
329///
330/// // The generated discriminant type looks something along these lines:
331///
332/// #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
333/// pub enum OuterDiscriminant {
334/// Inner,
335/// // ...
336/// }
337///
338/// // The generated impl looks something along these lines:
339///
340/// impl VariantDiscriminant for Outer {
341/// type Discriminant = OuterDiscriminant;
342///
343/// fn variant_discriminant(&self) -> Self::Discriminant {
344/// match self {
345/// Outer::Inner(_) => OuterDiscriminant::Inner,
346/// // ...
347/// }
348/// }
349/// }
350/// ```
351///
352#[proc_macro_derive(VariantDiscriminant, attributes(enumcapsulate))]
353pub fn derive_variant_discriminant(input: TokenStream) -> TokenStream {
354 let item = parse_macro_input!(input as syn::ItemEnum);
355
356 tokenstream(|| {
357 let deriver = EnumDeriver::from(item);
358 deriver.derive_variant_discriminant()
359 })
360}
361
362/// Umbrella derive macro.
363///
364/// The following use of the `Encapsulate` umbrella derive macro:
365///
366/// ```ignore
367/// use enumcapsulate::Encapsulate;
368///
369/// #[derive(Encapsulate)
370/// enum Enum {
371/// // ...
372/// }
373/// ```
374///
375/// is equivalent to the following:
376///
377/// ```ignore
378/// // ...
379///
380/// #[derive(
381/// From,
382/// TryInto,
383/// FromVariant,
384/// IntoVariant,
385/// AsVariant,
386/// AsVariantMut,
387/// AsVariantRef,
388/// VariantDowncast,
389/// )]
390/// enum Enum {
391/// // ...
392/// }
393/// ```
394///
395/// If you wish to opt out of a select few of `Encapsulate`'s trait derives,
396/// then you can do so by use of an `#[enumcapsulate(exclude(…))]` attribute
397/// on the enum itself, such as if you wanted to exclude `From` and `TryInto`:
398///
399/// ```rust
400/// #[derive(Encapsulate)]
401/// #[enumcapsulate(exclude(From, TryInto))]
402/// enum Enum {
403/// // ...
404/// }
405/// ```
406#[proc_macro_derive(Encapsulate, attributes(enumcapsulate))]
407pub fn derive_encapsulate(input: TokenStream) -> TokenStream {
408 let item = parse_macro_input!(input as syn::ItemEnum);
409
410 tokenstream(|| {
411 let deriver = EnumDeriver::from(item);
412 deriver.derive_encapsulate()
413 })
414}