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;