newtype_enum/
lib.rs

1#![no_std]
2#![warn(missing_docs, clippy::all, clippy::pedantic, clippy::nursery)]
3#![allow(clippy::missing_safety_doc)]
4
5//! Traits and macro to use newtype enums and convert between enums and their variants.
6//!
7//! A newtype enum is an enum where every variant wraps another type and the wrapped type can uniquely identify the variant.
8//!
9//! You can use the [`newtype_enum`](attr.newtype_enum.html) attribute macro to define a newtype enum. When the macro is applied to an enum `E` it will implement the [`Enum`](trait.Enum.html) trait for `E` and the [`Variant<E>`](trait.Variant.html) trait for all variant types.
10//!
11//! See the [**examples in the `Enum` trait**](trait.Enum.html) for usage of the available methods.
12//!
13//! The macro will also convert all unit and struct variants to generated structs and replace the enum variant with a newtype variant that contains the generated struct. See below for the rules and options that are available.
14//!
15//! # Variant transformation
16//! The variants of the enum will be converted in the following way:
17//!
18//! ## Unit variants
19//! ```
20//! # use newtype_enum::newtype_enum;
21//! #[newtype_enum]
22//! enum Test {
23//!     Example,
24//! }
25//! ```
26//! ```
27//! enum Test {
28//!     Example(Test_variants::Example),
29//! }
30//!
31//! mod Test_variants {
32//!     pub(super) struct Example;
33//! }
34//! ```
35//!
36//! ## Newtype variants
37//! ```
38//! # use newtype_enum::newtype_enum;
39//! #[newtype_enum]
40//! enum Test {
41//!     Example(usize),
42//! }
43//! ```
44//! ```
45//! enum Test {
46//!     Example(usize),
47//! }
48//! ```
49//! ## Struct variants
50//! ```
51//! # use newtype_enum::newtype_enum;
52//! #[newtype_enum]
53//! enum Test {
54//!     Example { test: usize },
55//! }
56//! ```
57//! ```
58//! enum Test {
59//!     Example(Test_variants::Example),
60//! }
61//!
62//! mod Test_variants {
63//!     pub(super) struct Example {
64//!         pub(super) test: usize,
65//!     }
66//! }
67//! ```
68//!
69//! # Attribute arguments
70//! You can pass the following arguments to the `newtype_enum` macro:
71//!
72//! ## Variants module name
73//! ```
74//! # use newtype_enum::newtype_enum;
75//! #[newtype_enum(variants = "test")]
76//! enum Test {
77//!     Example,
78//! }
79//! ```
80//! ```
81//! enum Test {
82//!     Example(test::Example),
83//! }
84//!
85//! mod test {
86//!     // <-- the name of the generated module
87//!     pub(super) struct Example;
88//! }
89//! ```
90//! ## Variants module visibility
91//! ```
92//! # use newtype_enum::newtype_enum;
93//! #[newtype_enum(variants = "pub(crate) test")]
94//! enum Test {
95//!     Example,
96//! }
97//! ```
98//! ```
99//! enum Test {
100//!     Example(test::Example),
101//! }
102//!
103//! pub(crate) mod test {
104//!     // <-- the visibility of the generated module
105//!     pub(super) struct Example;
106//! }
107//! ```
108//!
109//! # Visibilities and attributes (e.g. `#[derive]` attributes)
110//! The visibility of the generated variant structs behaves as if they where part of a normal enum: All variants and their fields have the same visibiltiy scope as the enum itself.
111//!
112//! Attributes will be passed to the following locations:
113//!
114//! Location | Destination
115//! -|-
116//! enum | Enum and generated variant structs
117//! enum variant | Generated variant struct
118//! variant field | Generated struct field
119//!
120//! ```
121//! # mod test {
122//! # use newtype_enum::newtype_enum;
123//! #[newtype_enum]
124//! #[derive(Debug)]
125//! pub(crate) enum Test {
126//!     #[derive(Clone)]
127//!     Example {
128//!         test: usize,
129//!         pub(super) test_super: usize,
130//!         pub(self) test_self: usize,
131//!     },
132//! }
133//! # }
134//! ```
135//! ```
136//! # mod test {
137//! #[derive(Debug)]
138//! pub(crate) enum Test {
139//!     Example(Test_variants::Example),
140//! }
141//!
142//! pub(crate) mod Test_variants {
143//!     #[derive(Debug, Clone)]
144//!     pub(crate) struct Example {
145//!         pub(crate) test: usize,
146//!         pub(in super::super) test_super: usize,
147//!         pub(super) test_self: usize,
148//!     }
149//! }
150//! # }
151//! ```
152
153pub mod unstable;
154
155/// Define a newtype enum.
156///
157/// See [crate-level documentation](index.html) for more information.
158pub use newtype_enum_macro::newtype_enum;
159
160/// Mark a type as an `enum`.
161///
162/// Use the [`newtype_enum`](attr.newtype_enum.html) macro to implement this trait for your enum types.
163///
164/// ```
165/// # use newtype_enum::newtype_enum;
166/// #[newtype_enum(variants = "pub example")]
167/// #[derive(Debug)]
168/// # #[derive(PartialEq, Eq)]
169/// pub enum Test {
170///     Ping,
171///     Number(usize),
172///     Str(&'static str),
173///     #[derive(Clone)]
174///     Hello {
175///         name: &'static str,
176///     },
177/// }
178///
179/// use newtype_enum::Enum;
180///
181/// let test = Test::from_variant(example::Hello { name: "Tester" });
182/// println!("{:?}", test);
183///
184/// let variant: example::Hello = test.into_variant().unwrap();
185/// let cloned = variant.clone();
186/// assert_eq!(variant, cloned);
187/// ```
188pub trait Enum: Sized {
189    /// Construct an enum from one of its newtype variants.
190    ///
191    /// ```
192    /// # #[newtype_enum::newtype_enum]
193    /// # #[derive(Debug, PartialEq, Eq)]
194    /// # pub enum Test {
195    /// #     Number(usize),
196    /// #     Str(&'static str),
197    /// # }
198    /// # fn main() {
199    /// # use newtype_enum::Enum;
200    /// let test = Test::from_variant(123);
201    /// assert_eq!(test, Test::Number(123));
202    /// # }
203    /// ```
204    fn from_variant(v: impl Variant<Self>) -> Self {
205        v.into_enum()
206    }
207
208    /// Set the enum to one of its newtype variants.
209    ///
210    /// This returns the old value of the enum.
211    ///
212    /// ```
213    /// # #[newtype_enum::newtype_enum]
214    /// # #[derive(Debug, PartialEq, Eq)]
215    /// # pub enum Test {
216    /// #     Number(usize),
217    /// #     Str(&'static str),
218    /// # }
219    /// # fn main() {
220    /// # use newtype_enum::Enum;
221    /// let mut test = Test::from_variant(123);
222    ///
223    /// let old = test.set_variant("Hello World");
224    /// assert_eq!(old, Test::Number(123));
225    /// assert_eq!(test, Test::Str("Hello World"));
226    /// # }
227    /// ```
228    fn set_variant(&mut self, v: impl Variant<Self>) -> Self {
229        ::core::mem::replace(self, v.into_enum())
230    }
231
232    /// Convert the enum into one of its newtype variants.
233    ///
234    /// ```
235    /// # #[newtype_enum::newtype_enum]
236    /// # #[derive(Debug, PartialEq, Eq)]
237    /// # pub enum Test {
238    /// #     Number(usize),
239    /// #     Str(&'static str),
240    /// # }
241    /// # fn main() {
242    /// # use newtype_enum::Enum;
243    /// let create_test = || Test::from_variant(123);
244    ///
245    /// assert_eq!(create_test().into_variant(), Some(123));
246    ///
247    /// let variant: Option<&str> = create_test().into_variant();
248    /// assert_eq!(variant, None);
249    ///
250    /// assert_eq!(create_test().into_variant::<&str>(), None);
251    /// # }
252    /// ```
253    fn into_variant<V: Variant<Self>>(self) -> Option<V> {
254        V::from_enum(self)
255    }
256
257    /// Get a reference to one of its newtype variants.
258    ///
259    /// ```
260    /// # #[newtype_enum::newtype_enum]
261    /// # #[derive(Debug, PartialEq, Eq)]
262    /// # pub enum Test {
263    /// #     Number(usize),
264    /// #     Str(&'static str),
265    /// # }
266    /// # fn main() {
267    /// # use newtype_enum::Enum;
268    /// let test = Test::from_variant(123);
269    /// assert_eq!(test.variant(), Some(&123));
270    ///
271    /// let variant: Option<&&str> = test.variant();
272    /// assert_eq!(variant, None);
273    ///
274    /// assert_eq!(test.variant::<&str>(), None);
275    /// # }
276    /// ```
277    fn variant<V: Variant<Self>>(&self) -> Option<&V> {
278        V::ref_enum(self)
279    }
280
281    /// Get a mutable reference to one of its newtype variants.
282    ///
283    /// ```
284    /// # #[newtype_enum::newtype_enum]
285    /// # #[derive(Debug, PartialEq, Eq)]
286    /// # pub enum Test {
287    /// #     Number(usize),
288    /// #     Str(&'static str),
289    /// # }
290    /// # fn main() {
291    /// # use newtype_enum::Enum;
292    /// let mut test = Test::from_variant(123);
293    /// assert_eq!(test.variant_mut(), Some(&mut 123));
294    /// assert_eq!(test.variant_mut(), None::<&mut &str>);
295    ///
296    /// if let Some(mut variant) = test.variant_mut() {
297    ///     *variant = 42;
298    /// }
299    /// assert_eq!(test.into_variant(), Some(42));
300    /// # }
301    /// ```
302    fn variant_mut<V: Variant<Self>>(&mut self) -> Option<&mut V> {
303        V::mut_enum(self)
304    }
305
306    /// Check if the enum currently holds the newtype variant `V`.
307    ///
308    /// If this method returns `true`, it is safe to call one of the `variant_unchecked` methods.
309    ///
310    /// ```
311    /// # #[newtype_enum::newtype_enum]
312    /// # #[derive(Debug, PartialEq, Eq)]
313    /// # pub enum Test {
314    /// #     Number(usize),
315    /// #     Str(&'static str),
316    /// # }
317    /// # fn main() {
318    /// # use newtype_enum::Enum;
319    /// let mut test = Test::from_variant(123);
320    /// assert_eq!(test.is_variant::<usize>(), true);
321    /// assert_eq!(test.is_variant::<&str>(), false);
322    /// # }
323    /// ```
324    fn is_variant<V: Variant<Self>>(&self) -> bool {
325        V::is_enum_variant(self)
326    }
327
328    /// Convert the enum into one of its newtype variants and unwrap the value.
329    ///
330    /// This method is equivalent to `self.into_variant().unwrap()` but written without an intermediate `Option<V>` value.
331    /// Therefore the compiler can sometimes optimize the code better.
332    ///
333    /// ```
334    /// # #[newtype_enum::newtype_enum]
335    /// # #[derive(Debug, PartialEq, Eq)]
336    /// # pub enum Test {
337    /// #     Number(usize),
338    /// #     Str(&'static str),
339    /// # }
340    /// # fn main() {
341    /// # use newtype_enum::Enum;
342    /// let mut test = Test::from_variant(123);
343    /// let variant: usize = test.into_variant_unwrap();
344    /// assert_eq!(variant, 123);
345    /// # }
346    /// ```
347    ///
348    /// ```should_panic
349    /// # #[newtype_enum::newtype_enum]
350    /// # #[derive(Debug, PartialEq, Eq)]
351    /// # pub enum Test {
352    /// #     Number(usize),
353    /// #     Str(&'static str),
354    /// # }
355    /// # fn main() {
356    /// # use newtype_enum::Enum;
357    /// let mut test = Test::from_variant("Hello World");
358    /// let variant: usize = test.into_variant_unwrap(); // fails
359    /// # }
360    /// ```
361    fn into_variant_unwrap<V: Variant<Self>>(self) -> V {
362        V::from_enum_unwrap(self)
363    }
364
365    /// Convert the enum into one of its newtype variants **without checking if the variant matches**.
366    ///
367    /// ```
368    /// # #[newtype_enum::newtype_enum]
369    /// # #[derive(Debug, PartialEq, Eq)]
370    /// # pub enum Test {
371    /// #     Number(usize),
372    /// #     Str(&'static str),
373    /// # }
374    /// # fn main() {
375    /// # use newtype_enum::Enum;
376    /// let test = Test::from_variant(123);
377    ///
378    /// if test.is_variant::<usize>() {
379    ///     // ...
380    ///
381    ///     // SAFETY: We already checked if the enum has the correct variant
382    ///     // and we did not change it in between.
383    ///     let number: usize = unsafe { test.into_variant_unchecked() };
384    ///     assert_eq!(number, 123);
385    /// } else {
386    ///     panic!("expected a usize variant");
387    /// }
388    /// # }
389    /// ```
390    unsafe fn into_variant_unchecked<V: Variant<Self>>(self) -> V {
391        V::from_enum_unchecked(self)
392    }
393
394    /// Get a reference to one of its newtype variants **without checking if the variant matches**.
395    ///
396    /// ```
397    /// # #[newtype_enum::newtype_enum]
398    /// # #[derive(Debug, PartialEq, Eq)]
399    /// # pub enum Test {
400    /// #     Number(usize),
401    /// #     Str(&'static str),
402    /// # }
403    /// # fn main() {
404    /// # use newtype_enum::Enum;
405    /// let test = Test::from_variant(123);
406    ///
407    /// if test.is_variant::<usize>() {
408    ///     // ...
409    ///
410    ///     // SAFETY: We already checked if the enum has the correct variant
411    ///     // and we did not change it in between.
412    ///     let number: &usize = unsafe { test.variant_unchecked() };
413    ///     assert_eq!(number, &123);
414    /// } else {
415    ///     panic!("expected a usize variant");
416    /// }
417    /// # }
418    /// ```
419    unsafe fn variant_unchecked<V: Variant<Self>>(&self) -> &V {
420        V::ref_enum_unchecked(self)
421    }
422
423    /// Get a mutable reference to one of its newtype variants **without checking if the variant matches**.
424    ///
425    /// ```
426    /// # #[newtype_enum::newtype_enum]
427    /// # #[derive(Debug, PartialEq, Eq)]
428    /// # pub enum Test {
429    /// #     Number(usize),
430    /// #     Str(&'static str),
431    /// # }
432    /// # fn main() {
433    /// # use newtype_enum::Enum;
434    /// let mut test = Test::from_variant(123);
435    ///
436    /// if test.is_variant::<usize>() {
437    ///     // ...
438    ///
439    ///     // SAFETY: We already checked if the enum has the correct variant
440    ///     // and we did not change it in between.
441    ///     let number: &mut usize = unsafe { test.variant_unchecked_mut() };
442    ///     *number = 42;
443    /// } else {
444    ///     panic!("expected a usize variant");
445    /// }
446    ///
447    /// assert_eq!(test.into_variant(), Some(42));
448    /// # }
449    /// ```
450    unsafe fn variant_unchecked_mut<V: Variant<Self>>(&mut self) -> &mut V {
451        V::mut_enum_unchecked(self)
452    }
453}
454
455/// Mark a type as a newtype variant of an [`Enum`](trait.Enum.html) `E`.
456///
457/// Use the [`newtype_enum`](attr.newtype_enum.html) macro to implement this trait for your enum variants.
458pub trait Variant<E: Enum>: unstable::VariantCore<E> {}