workflow_core/enums.rs
1//!
2//! Rust enum conversion utilities
3//!
4
5pub use workflow_core_macros::Describe;
6
7/// Enum trait used by the [`Describe`] derive macro
8pub trait Describe: Sized + 'static {
9 /// return a caption for the enum declared by the `#[caption=""]` attribute
10 fn caption() -> &'static str;
11 /// return all permutations of the enum as an iterator
12 fn iter() -> impl Iterator<Item = &'static Self>;
13 /// converts enum into an iterator
14 fn into_iter() -> impl Iterator<Item = Self>;
15 /// return `rust doc` text describing the enum value
16 fn rustdoc(&self) -> &'static str;
17 /// return `#[describe=""]` text describing the enum value
18 fn describe(&self) -> &'static str;
19 /// return enum value as a string without namespace (i.e. `Value`)
20 fn as_str(&self) -> &'static str;
21 /// return enum value as a string with namespace (i.e. `Enum::Value`)
22 fn as_str_ns(&self) -> &'static str;
23 /// get enum value from the value string without namespace (i.e. `Value`)
24 fn from_str(str: &str) -> Option<Self>;
25 /// get enum value from the value string with namespace (i.e. `Enum::Value`)
26 fn from_str_ns(str: &str) -> Option<Self>;
27}
28
29/// Error produced by the enum `try_from` macros
30#[derive(Clone, Debug, thiserror::Error)]
31#[allow(non_camel_case_types)]
32pub enum TryFromError {
33 /// A `u32` value (second field) is out of range for the named enum (first field).
34 #[error("value for enum `{0}` is out of range: {1}")]
35 u32(&'static str, u32),
36 /// A `u16` value (second field) is out of range for the named enum (first field).
37 #[error("value for enum `{0}` is out of range: {1}")]
38 u16(&'static str, u16),
39 /// A `u8` value (second field) is out of range for the named enum (first field).
40 #[error("value for enum `{0}` is out of range: {1}")]
41 u8(&'static str, u8),
42 /// A `usize` value (second field) is out of range for the named enum (first field).
43 #[error("value for enum `{0}` is out of range: {1}")]
44 usize(&'static str, usize),
45}
46
47///
48/// Associates u32 values to each enum value and declares
49/// a `TryFrom<u32>` implementation for this enum allowing
50/// a `try_from(u32)` to enum conversion.
51///
52/// Example:
53/// ```rust
54/// use workflow_core::enums::u32_try_from;
55///
56/// u32_try_from!{
57/// #[derive(Debug, Clone, PartialEq)]
58/// enum MyEnum {
59/// A, // 0u32
60/// B, // 1u32
61/// C, // 2u32
62/// }
63/// }
64///
65/// let v1 = MyEnum::B;
66/// let n = v1.clone() as u32;
67/// let v2 = MyEnum::try_from(n).unwrap();
68/// assert_eq!(v1, v2);
69/// ```
70///
71#[macro_export]
72macro_rules! u32_try_from {
73 ($(#[$meta:meta])* $vis:vis enum $name:ident {
74 $($(#[$vmeta:meta])* $vname:ident $(= $val:expr_2021)?,)*
75 }) => {
76 $(#[$meta])*
77 $vis enum $name {
78 $($(#[$vmeta])* $vname $(= $val)?,)*
79 }
80
81 impl std::convert::TryFrom<u32> for $name {
82 type Error = workflow_core::enums::TryFromError;
83
84 fn try_from(v: u32) -> std::result::Result<Self, workflow_core::enums::TryFromError> {
85 match v {
86 $(x if x == $name::$vname as u32 => Ok($name::$vname),)*
87 _ => {
88 Err(workflow_core::enums::TryFromError::u32(stringify!($name),v))
89 },
90 }
91 }
92 }
93 }
94}
95
96pub use u32_try_from;
97
98///
99/// Associates u16 values to each enum value and declares
100/// a `TryFrom<u16>` implementation for this enum allowing
101/// a `try_from(u16)` to enum conversion.
102///
103/// Example:
104/// ```rust
105/// use workflow_core::enums::u16_try_from;
106///
107/// u16_try_from!{
108/// #[derive(Debug, Clone, PartialEq)]
109/// enum MyEnum {
110/// A, // 0u16
111/// B, // 1u16
112/// C, // 2u16
113/// }
114/// }
115///
116/// let v1 = MyEnum::B;
117/// let n: u16 = v1.clone() as u16;
118/// let v2 = MyEnum::try_from(n).unwrap();
119/// assert_eq!(v1, v2);
120/// ```
121///
122#[macro_export]
123macro_rules! u16_try_from {
124 ($(#[$meta:meta])* $vis:vis enum $name:ident {
125 $($(#[$vmeta:meta])* $vname:ident $(= $val:expr_2021)?,)*
126 }) => {
127 $(#[$meta])*
128 $vis enum $name {
129 $($(#[$vmeta])* $vname $(= $val)?,)*
130 }
131
132 impl std::convert::TryFrom<u16> for $name {
133 type Error = workflow_core::enums::TryFromError;
134
135 fn try_from(v: u16) -> std::result::Result<Self, workflow_core::enums::TryFromError> {
136 match v {
137 $(x if x == $name::$vname as u16 => Ok($name::$vname),)*
138 _ => {
139 Err(workflow_core::enums::TryFromError::u16(stringify!($name),v))
140 },
141 }
142 }
143 }
144
145 impl std::convert::From<$name> for u16 {
146 fn from(v: $name) -> u16 {
147 v as u16
148 }
149 }
150 }
151}
152
153pub use u16_try_from;
154
155///
156/// Associates u8 values to each enum value and declares
157/// a `TryFrom<u8>` implementation for this enum allowing
158/// a `try_from(u8)` to enum conversion.
159///
160/// Example:
161/// ```rust
162/// use workflow_core::enums::u8_try_from;
163///
164/// u8_try_from!{
165/// #[derive(Debug, Clone, PartialEq)]
166/// enum MyEnum {
167/// A, // 0u8
168/// B, // 1u8
169/// C, // 2u8
170/// }
171/// }
172///
173/// let v1 = MyEnum::B;
174/// let n: u8 = v1.clone() as u8;
175/// let v2 = MyEnum::try_from(n).unwrap();
176/// assert_eq!(v1, v2);
177/// ```
178///
179#[macro_export]
180macro_rules! u8_try_from {
181 ($(#[$meta:meta])* $vis:vis enum $name:ident {
182 $($(#[$vmeta:meta])* $vname:ident $(= $val:expr_2021)?,)*
183 }) => {
184 $(#[$meta])*
185 $vis enum $name {
186 $($(#[$vmeta])* $vname $(= $val)?,)*
187 }
188
189 impl std::convert::TryFrom<u8> for $name {
190 type Error = workflow_core::enums::TryFromError;
191
192 fn try_from(v: u8) -> std::result::Result<Self, workflow_core::enums::TryFromError> {
193 match v {
194 $(x if x == $name::$vname as u8 => Ok($name::$vname),)*
195 _ => {
196 Err(workflow_core::enums::TryFromError::u8(stringify!($name),v))
197 },
198 }
199 }
200 }
201 }
202}
203
204pub use u8_try_from;
205
206///
207/// Associates usize values to each enum value and declares
208/// a `TryFrom<usize>` implementation for this enum allowing
209/// a `try_from(usize)` to enum conversion.
210///
211/// Example:
212/// ```rust
213/// use workflow_core::enums::usize_try_from;
214///
215/// usize_try_from!{
216/// #[derive(Debug, Clone, PartialEq)]
217/// enum MyEnum {
218/// A, // 0usize
219/// B, // 1usize
220/// C, // 2usize
221/// }
222/// }
223///
224/// let v1 = MyEnum::B;
225/// let n: usize = v1.clone() as usize;
226/// let v2 = MyEnum::try_from(n).unwrap();
227/// assert_eq!(v1, v2);
228/// ```
229///
230#[macro_export]
231macro_rules! usize_try_from {
232 ($(#[$meta:meta])* $vis:vis enum $name:ident {
233 $($(#[$vmeta:meta])* $vname:ident $(= $val:expr_2021)?,)*
234 }) => {
235 $(#[$meta])*
236 $vis enum $name {
237 $($(#[$vmeta])* $vname $(= $val)?,)*
238 }
239
240 impl std::convert::TryFrom<usize> for $name {
241 type Error = workflow_core::enums::TryFromError;
242
243 fn try_from(v: usize) -> std::result::Result<Self, workflow_core::enums::TryFromError> {
244 match v {
245 $(x if x == $name::$vname as usize => Ok($name::$vname),)*
246 _ => {
247 Err(workflow_core::enums::TryFromError::usize(stringify!($name),v))
248 },
249 }
250 }
251 }
252 }
253}
254
255pub use usize_try_from;