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> {}