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 #[error("value for enum `{0}` is out of range: {1}")]
34 u32(&'static str, u32),
35 #[error("value for enum `{0}` is out of range: {1}")]
36 u16(&'static str, u16),
37 #[error("value for enum `{0}` is out of range: {1}")]
38 u8(&'static str, u8),
39 #[error("value for enum `{0}` is out of range: {1}")]
40 usize(&'static str, usize),
41}
42
43///
44/// Associates u32 values to each enum value and declares
45/// a `TryFrom<u32>` implementation for this enum allowing
46/// a `try_from(u32)` to enum conversion.
47///
48/// Example:
49/// ```rust
50/// use workflow_core::enums::u32_try_from;
51///
52/// u32_try_from!{
53/// #[derive(Debug, Clone, PartialEq)]
54/// enum MyEnum {
55/// A, // 0u32
56/// B, // 1u32
57/// C, // 2u32
58/// }
59/// }
60///
61/// let v1 = MyEnum::B;
62/// let n = v1.clone() as u32;
63/// let v2 = MyEnum::try_from(n).unwrap();
64/// assert_eq!(v1, v2);
65/// ```
66///
67#[macro_export]
68macro_rules! u32_try_from {
69 ($(#[$meta:meta])* $vis:vis enum $name:ident {
70 $($(#[$vmeta:meta])* $vname:ident $(= $val:expr)?,)*
71 }) => {
72 $(#[$meta])*
73 $vis enum $name {
74 $($(#[$vmeta])* $vname $(= $val)?,)*
75 }
76
77 impl std::convert::TryFrom<u32> for $name {
78 type Error = workflow_core::enums::TryFromError;
79
80 fn try_from(v: u32) -> std::result::Result<Self, workflow_core::enums::TryFromError> {
81 match v {
82 $(x if x == $name::$vname as u32 => Ok($name::$vname),)*
83 _ => {
84 Err(workflow_core::enums::TryFromError::u32(stringify!($name),v))
85 },
86 }
87 }
88 }
89 }
90}
91
92pub use u32_try_from;
93
94///
95/// Associates u16 values to each enum value and declares
96/// a `TryFrom<u16>` implementation for this enum allowing
97/// a `try_from(u16)` to enum conversion.
98///
99/// Example:
100/// ```rust
101/// use workflow_core::enums::u16_try_from;
102///
103/// u16_try_from!{
104/// #[derive(Debug, Clone, PartialEq)]
105/// enum MyEnum {
106/// A, // 0u16
107/// B, // 1u16
108/// C, // 2u16
109/// }
110/// }
111///
112/// let v1 = MyEnum::B;
113/// let n: u16 = v1.clone() as u16;
114/// let v2 = MyEnum::try_from(n).unwrap();
115/// assert_eq!(v1, v2);
116/// ```
117///
118
119#[macro_export]
120macro_rules! u16_try_from {
121 ($(#[$meta:meta])* $vis:vis enum $name:ident {
122 $($(#[$vmeta:meta])* $vname:ident $(= $val:expr)?,)*
123 }) => {
124 $(#[$meta])*
125 $vis enum $name {
126 $($(#[$vmeta])* $vname $(= $val)?,)*
127 }
128
129 impl std::convert::TryFrom<u16> for $name {
130 type Error = workflow_core::enums::TryFromError;
131
132 fn try_from(v: u16) -> std::result::Result<Self, workflow_core::enums::TryFromError> {
133 match v {
134 $(x if x == $name::$vname as u16 => Ok($name::$vname),)*
135 _ => {
136 Err(workflow_core::enums::TryFromError::u16(stringify!($name),v))
137 },
138 }
139 }
140 }
141
142 impl std::convert::From<$name> for u16 {
143 fn from(v: $name) -> u16 {
144 v as u16
145 }
146 }
147 }
148}
149
150pub use u16_try_from;
151
152///
153/// Associates u8 values to each enum value and declares
154/// a `TryFrom<u8>` implementation for this enum allowing
155/// a `try_from(u8)` to enum conversion.
156///
157/// Example:
158/// ```rust
159/// use workflow_core::enums::u8_try_from;
160///
161/// u8_try_from!{
162/// #[derive(Debug, Clone, PartialEq)]
163/// enum MyEnum {
164/// A, // 0u8
165/// B, // 1u8
166/// C, // 2u8
167/// }
168/// }
169///
170/// let v1 = MyEnum::B;
171/// let n: u8 = v1.clone() as u8;
172/// let v2 = MyEnum::try_from(n).unwrap();
173/// assert_eq!(v1, v2);
174/// ```
175///
176
177#[macro_export]
178macro_rules! u8_try_from {
179 ($(#[$meta:meta])* $vis:vis enum $name:ident {
180 $($(#[$vmeta:meta])* $vname:ident $(= $val:expr)?,)*
181 }) => {
182 $(#[$meta])*
183 $vis enum $name {
184 $($(#[$vmeta])* $vname $(= $val)?,)*
185 }
186
187 impl std::convert::TryFrom<u8> for $name {
188 type Error = workflow_core::enums::TryFromError;
189
190 fn try_from(v: u8) -> std::result::Result<Self, workflow_core::enums::TryFromError> {
191 match v {
192 $(x if x == $name::$vname as u8 => Ok($name::$vname),)*
193 _ => {
194 Err(workflow_core::enums::TryFromError::u8(stringify!($name),v))
195 },
196 }
197 }
198 }
199 }
200}
201
202pub use u8_try_from;
203
204///
205/// Associates usize values to each enum value and declares
206/// a `TryFrom<usize>` implementation for this enum allowing
207/// a `try_from(usize)` to enum conversion.
208///
209/// Example:
210/// ```rust
211/// use workflow_core::enums::usize_try_from;
212///
213/// usize_try_from!{
214/// #[derive(Debug, Clone, PartialEq)]
215/// enum MyEnum {
216/// A, // 0usize
217/// B, // 1usize
218/// C, // 2usize
219/// }
220/// }
221///
222/// let v1 = MyEnum::B;
223/// let n: usize = v1.clone() as usize;
224/// let v2 = MyEnum::try_from(n).unwrap();
225/// assert_eq!(v1, v2);
226/// ```
227///
228#[macro_export]
229macro_rules! usize_try_from {
230 ($(#[$meta:meta])* $vis:vis enum $name:ident {
231 $($(#[$vmeta:meta])* $vname:ident $(= $val:expr)?,)*
232 }) => {
233 $(#[$meta])*
234 $vis enum $name {
235 $($(#[$vmeta])* $vname $(= $val)?,)*
236 }
237
238 impl std::convert::TryFrom<usize> for $name {
239 type Error = workflow_core::enums::TryFromError;
240
241 fn try_from(v: usize) -> std::result::Result<Self, workflow_core::enums::TryFromError> {
242 match v {
243 $(x if x == $name::$vname as usize => Ok($name::$vname),)*
244 _ => {
245 Err(workflow_core::enums::TryFromError::usize(stringify!($name),v))
246 },
247 }
248 }
249 }
250 }
251}
252
253pub use usize_try_from;