nutype_enum/
lib.rs

1//! The crate provides a macro to create a new enum type with a single field.
2//!
3//! ## Why do we need this?
4//!
5//! This is useful when you have a value and you want to have enum like behavior and have a catch all case for all other values.
6//!
7//! ## Examples
8//!
9//! ```rust
10//! use nutype_enum::nutype_enum;
11//!
12//! nutype_enum! {
13//!     pub enum AacPacketType(u8) {
14//!         SeqHdr = 0x0,
15//!         Raw = 0x1,
16//!     }
17//! }
18//! ```
19//!
20//! ## License
21//!
22//! This project is licensed under the [MIT](./LICENSE.MIT) or [Apache-2.0](./LICENSE.Apache-2.0) license.
23//! You can choose between one of them if you use this work.
24//!
25//! `SPDX-License-Identifier: MIT OR Apache-2.0`
26#![deny(missing_docs)]
27#![deny(unsafe_code)]
28#![deny(unreachable_pub)]
29
30/// Helper macro to create a new enum type with a single field.
31///
32/// The enum type is derived with the `Clone`, `Copy`, `PartialEq`, `Eq`,
33/// `PartialOrd`, `Ord`, and `Hash` traits. The nutype also impls `From` and
34/// `Into` for the underlying type. As well as a custom `Debug` impl for human
35/// readable output.
36///
37/// # Examples
38///
39/// ```rust
40/// # use nutype_enum::nutype_enum;
41/// nutype_enum! {
42///     pub enum AacPacketType(u8) {
43///         SeqHdr = 0x0,
44///         Raw = 0x1,
45///     }
46/// }
47/// ```
48#[macro_export]
49macro_rules! nutype_enum {
50    (
51        $(#[$attr:meta])*
52        $vis:vis enum $name:ident($type:ty) {
53            $(
54                $(#[$variant_attr:meta])*
55                $variant:ident = $value:expr
56            ),*$(,)?
57        }
58    ) => {
59        #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
60        $(#[$attr])*
61        #[repr(transparent)]
62        $vis struct $name(pub $type);
63
64        impl ::std::fmt::Debug for $name {
65            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66                match self {
67                    $(
68                        &$name::$variant => write!(f, "{}::{}", stringify!($name), stringify!($variant)),
69                    )*
70                    _ => write!(f, "{}({:?})", stringify!($name), self.0),
71                }
72            }
73        }
74
75        impl $name {
76            $(
77                $(#[$variant_attr])*
78                #[allow(non_upper_case_globals)]
79                pub const $variant: Self = Self($value);
80            )*
81        }
82
83        impl From<$type> for $name {
84            fn from(value: $type) -> Self {
85                Self(value)
86            }
87        }
88
89        impl From<$name> for $type {
90            fn from(value: $name) -> Self {
91                value.0
92            }
93        }
94    };
95}
96
97/// Helper macro to create a bitwise enum.
98///
99/// The enum type is derived with the `BitAnd`, `BitOr`, `BitXor`, `BitAndAssign`,
100/// `BitOrAssign`, and `BitXorAssign` traits.
101///
102/// # Examples
103///
104/// ```rust
105/// # use nutype_enum::{nutype_enum, bitwise_enum};
106/// nutype_enum! {
107///     pub enum IoFlags(u8) {
108///         Seek = 0x1,
109///         Write = 0x2,
110///         Read = 0x4,
111///     }
112/// }
113///
114/// bitwise_enum!(IoFlags);
115/// ```
116#[macro_export]
117macro_rules! bitwise_enum {
118    ($name:ident) => {
119        impl ::std::ops::BitAnd for $name {
120            type Output = Self;
121
122            fn bitand(self, rhs: Self) -> Self::Output {
123                Self(self.0 & rhs.0)
124            }
125        }
126
127        impl ::std::ops::BitOr for $name {
128            type Output = Self;
129
130            fn bitor(self, rhs: Self) -> Self::Output {
131                Self(self.0 | rhs.0)
132            }
133        }
134
135        impl ::std::ops::BitXor for $name {
136            type Output = Self;
137
138            fn bitxor(self, rhs: Self) -> Self::Output {
139                Self(self.0 ^ rhs.0)
140            }
141        }
142
143        impl ::std::ops::Not for $name {
144            type Output = Self;
145
146            fn not(self) -> Self::Output {
147                Self(!self.0)
148            }
149        }
150
151        impl ::std::ops::BitAndAssign for $name {
152            fn bitand_assign(&mut self, rhs: Self) {
153                self.0 &= rhs.0;
154            }
155        }
156
157        impl ::std::ops::BitOrAssign for $name {
158            fn bitor_assign(&mut self, rhs: Self) {
159                self.0 |= rhs.0;
160            }
161        }
162
163        impl ::std::ops::BitXorAssign for $name {
164            fn bitxor_assign(&mut self, rhs: Self) {
165                self.0 ^= rhs.0;
166            }
167        }
168    };
169}