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