1#![forbid(unsafe_code)]
2#[cfg(feature = "serde")]
24pub use serde;
25
26#[cfg(feature = "strum")]
27pub use strum;
28
29#[cfg(feature = "phf")]
30pub use phf;
31
32#[cfg(feature = "phf")]
33#[macro_export]
34macro_rules! str_enum_try_from_str {
35 (#[phf] $(#[error_type($error_ty:ident)])? $(#[derive($($derive_trait:ident),* $(,)?)])? $(#[repr($repr:ty)])? $vis:vis enum $ty:ident { $($variant:ident $(= $variant_repr:literal)? => $val:literal $(($($other_valid:literal),* $(,)?))?),* $(,)? }) => {
36 impl $ty {
37 #[doc = "Compile time generated map from all valid string variants to their Variant"]
38 const PHF_MAP: $crate::phf::Map<&'static str, $ty> = $crate::phf::phf_map! {
39 $($val $($(| $other_valid )*)? => $ty::$variant,)*
40 };
41
42 #[doc = "Try to generate `Self` from an &str, using `Self::PHF_MAP`"]
43 pub fn try_from_str(s: &str) -> Option<Self> {
44 Self::PHF_MAP.get(s).copied()
45 }
46 }
47 };
48 ($(#[error_type($error_ty:ident)])? $(#[derive($($derive_trait:ident),* $(,)?)])? $(#[repr($repr:ty)])? $vis:vis enum $ty:ident { $($variant:ident $(= $variant_repr:literal)? => $val:literal $(($($other_valid:literal),* $(,)?))?),* $(,)? }) => {
49 impl $ty {
50 #[doc = "Try to generate `Self` from an &str by matching on all valid values.\nNote: If you have many variants you may want to enable the `phf` feature and add the `#[phf]` attribute."]
51 pub fn try_from_str(s: &str) -> Option<Self> {
52 match s {
53 $($val $($(|$other_valid)*)? => Some(Self::$variant),)*
54 _ => None,
55 }
56 }
57 }
58 }
59}
60
61#[cfg(not(feature = "phf"))]
62#[macro_export]
63macro_rules! str_enum_try_from_str {
64 (#[phf] $(#[error_type($error_ty:ident)])? $(#[derive($($derive_trait:ident),* $(,)?)])? $(#[repr($repr:ty)])? $vis:vis enum $ty:ident { $($variant:ident $(= $variant_repr:literal)? => $val:literal $(($($other_valid:literal),* $(,)?))?),* $(,)? }) => {
65 impl $ty {
66 #[doc = "Try to generate `Self` from an &str by matching on all valid values.\nNote: If you have many variants you may want to enable the `phf` feature and add the `#[phf]` attribute."]
67 pub fn try_from_str(s: &str) -> Option<Self> {
68 match s {
69 $($val $($(|$other_valid)*)? => Some(Self::$variant),)*
70 _ => None,
71 }
72 }
73 }
74 };
75 ($(#[error_type($error_ty:ident)])? $(#[derive($($derive_trait:ident),* $(,)?)])? $(#[repr($repr:ty)])? $vis:vis enum $ty:ident { $($variant:ident $(= $variant_repr:literal)? => $val:literal $(($($other_valid:literal),* $(,)?))?),* $(,)? }) => {
76 impl $ty {
77 #[doc = "Try to generate `Self` from an &str by matching on all valid values.\nNote: If you have many variants you may want to enable the `phf` feature and add the `#[phf]` attribute."]
78 pub fn try_from_str(s: &str) -> Option<Self> {
79 match s {
80 $($val $($(|$other_valid)*)? => Some(Self::$variant),)*
81 _ => None,
82 }
83 }
84 }
85 }
86}
87
88#[macro_export]
89macro_rules! str_enum_base {
90 ($(#[error_type($error_ty:ident)])? $(#[derive($($derive_trait:ident),* $(,)?)])? $(#[repr($repr:ty)])? $vis:vis enum $ty:ident { $($variant:ident $(= $variant_repr:literal)? => $val:literal $(($($other_valid:literal),* $(,)?))?),* $(,)? }) => {
91 $(
92 #[derive($($derive_trait,)*)]
93 )?
94 $(
95 #[repr($repr)]
96 )?
97 $vis enum $ty {
98 $(
99 $variant $(= $variant_repr)?,
100 )*
101 }
102
103 impl $ty {
104 #[doc = "Collection of all variants in `Self`"]
105 pub const ALL_VARIANTS: &[Self] = &[$(Self::$variant,)*];
106 #[doc = "Number of variants in `Self`"]
107 pub const NUM_VARIANTS: usize = Self::ALL_VARIANTS.len();
108
109 pub const fn as_str(&self) -> &'static str {
110 match self {
111 $(Self::$variant => $val,)*
112 }
113 }
114
115 #[doc = "All values of `Self`, does not include alternate spellings used for `Self::try_from_str`"]
116 pub const ALL_VALUES: &[&str] = &[$(Self::$variant.as_str(),)*];
117
118 #[doc = "Total length of `Self::ALL_VALUES + 1 byte separator. You do not need this."]
119 const ALL_VALUES_STR_LEN: usize = {
120 let mut len = 0usize;
121 let mut idx = 0usize;
122 while idx < Self::ALL_VALUES.len() {
123 let value = Self::ALL_VALUES[idx];
124 len += value.len() + 1;
125 idx += 1
126 }
127 len - 1
128 };
129
130 #[doc = "Fixed size byte array of `Self::ALL_VALUES` joined by a comma separator. You do not need this."]
131 const ALL_VALUE_BYTES: [u8; Self::ALL_VALUES_STR_LEN] = {
132 let mut buf = [0u8; Self::ALL_VALUES_STR_LEN];
133 let mut idx = 0;
134 let mut buf_idx = 0;
135 while idx < Self::ALL_VALUES.len() {
136 let value = Self::ALL_VALUES[idx];
137 let mut value_idx = 0;
138 while value_idx < value.len() {
139 buf[buf_idx] = value.as_bytes()[value_idx];
140 value_idx += 1;
141 buf_idx += 1
142 }
143
144 if idx != Self::ALL_VALUES.len() - 1 {
145 buf[buf_idx] = b',';
146 buf_idx += 1;
147 }
148 idx += 1
149 }
150 buf
151 };
152
153 #[doc = "&'static str of `Self::ALL_VALUE_BYTES`"]
155 const ALL_VALUE_STR: &str = {
156 match str::from_utf8(&Self::ALL_VALUE_BYTES) {
157 Ok(o) => o,
158 Err(_) => panic!(),
159 }
160 };
161 }
162
163 impl $ty {
164 #[doc = "len() of this variant's str equivalent"]
165 pub const fn len(&self) -> usize {
166 self.as_str().len()
167 }
168
169 #[doc = "equivalent to str::is_empty"]
170 pub const fn is_empty(&self) -> bool {
171 self.as_str().is_empty()
172 }
173 }
174
175 $(
176 impl $ty {
177 #[doc = "Convert this enum into its repr"]
178 fn into_repr(self) -> $repr {
179 self as $repr
180 }
181 }
182
183 impl From<$ty> for $repr {
184 fn from(v: $ty) -> $repr {
185 v as $repr
186 }
187 }
188 )?
189
190 impl std::fmt::Display for $ty {
191 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192 <str as std::fmt::Display>::fmt(self.as_str(), fmt)
193 }
194 }
195
196 impl std::borrow::Borrow<str> for $ty {
197 fn borrow(&self) -> &str {
198 self.as_str()
199 }
200 }
201
202 impl std::hash::Hash for $ty {
203 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
204 <str as std::hash::Hash>::hash(self.as_str(), state)
205 }
206 }
207
208 impl<'a> std::ops::Add<$ty> for std::borrow::Cow<'a, str> {
209 type Output = std::borrow::Cow<'a, str>;
210
211 fn add(self, rhs: $ty) -> std::borrow::Cow<'a, str> {
212 self.add(rhs.as_str())
213 }
214 }
215
216 impl std::ops::Add<$ty> for String {
217 type Output = String;
218
219 fn add(self, rhs: $ty) -> String {
220 self.add(rhs.as_str())
221 }
222 }
223
224 impl<'a> std::ops::AddAssign<$ty> for std::borrow::Cow<'a, str> {
225 fn add_assign(&mut self, rhs: $ty) {
226 self.add_assign(rhs.as_str())
227 }
228 }
229
230 impl std::ops::AddAssign<$ty> for String {
231 fn add_assign(&mut self, rhs: $ty) {
232 self.add_assign(rhs.as_str())
233 }
234 }
235
236 $crate::str_enum_base!(AsRef $ty, [str, std::ffi::OsStr, std::path::Path, [u8]]);
237
238 impl Extend<$ty> for String {
239 fn extend<I>(&mut self, iter: I) where I: IntoIterator<Item = $ty> {
240 iter.into_iter().for_each(move |s| self.push_str(s.as_str()))
241 }
242 }
243
244 $crate::str_enum_base!(From $ty, [std::sync::Arc<str>, Box<str>, std::rc::Rc<str>, String, Vec<u8>]);
245 $crate::str_enum_base!(From 'a $ty, [Box<dyn std::error::Error + 'a>, Box<dyn std::error::Error + Send + Sync + 'a>, std::borrow::Cow<'a, str>]);
246 $crate::str_enum_base!(FromIterator $ty, [Box<str>, String]);
247 $crate::str_enum_base!(FromIterator 'a $ty, [std::borrow::Cow<'a, str>]);
248
249 impl<I: std::slice::SliceIndex<str>> std::ops::Index<I> for $ty {
250 type Output = <I as std::slice::SliceIndex<str>>::Output;
251
252 fn index(&self, index: I) -> &<I as std::slice::SliceIndex<str>>::Output {
253 self.as_str().index(index)
254 }
255 }
256
257 $crate::str_enum_base!(PartialEq $ty, [std::ffi::OsStr, std::ffi::OsString, String, std::path::Path, std::path::PathBuf]);
258 $crate::str_enum_base!(PartialEq 'a $ty, [std::borrow::Cow<'a, str>]);
259
260 impl PartialEq<&str> for $ty {
261 fn eq(&self, rhs: &&str) -> bool {
262 self.as_str().eq(*rhs)
263 }
264 }
265
266 impl PartialEq<$ty> for &str {
267 fn eq(&self, rhs: &$ty) -> bool {
268 self.eq(&rhs.as_str())
269 }
270 }
271
272 impl PartialEq<str> for $ty {
273 fn eq(&self, rhs: &str) -> bool {
274 self.as_str().eq(rhs)
275 }
276 }
277
278 impl PartialEq<$ty> for str {
279 fn eq(&self, rhs: &$ty) -> bool {
280 self.eq(rhs.as_str())
281 }
282 }
283
284 $crate::str_enum_base!(PartialOrd $ty, [std::ffi::OsStr, std::ffi::OsString]);
285
286 impl PartialOrd<$ty> for str {
287 fn partial_cmp(&self, rhs: &$ty) -> Option<std::cmp::Ordering> {
288 self.partial_cmp(rhs.as_str())
289 }
290 }
291
292 impl PartialOrd<str> for $ty {
293 fn partial_cmp(&self, rhs: &str) -> Option<std::cmp::Ordering> {
294 self.as_str().partial_cmp(rhs)
295 }
296 }
297
298 impl PartialOrd<$ty> for &str {
299 fn partial_cmp(&self, rhs: &$ty) -> Option<std::cmp::Ordering> {
300 self.partial_cmp(&rhs.as_str())
301 }
302 }
303
304 impl PartialOrd<&str> for $ty {
305 fn partial_cmp(&self, rhs: &&str) -> Option<std::cmp::Ordering> {
306 self.as_str().partial_cmp(*rhs)
307 }
308 }
309
310 impl std::net::ToSocketAddrs for $ty {
311 type Iter = std::vec::IntoIter<std::net::SocketAddr>;
312
313 fn to_socket_addrs(&self) -> std::io::Result<std::vec::IntoIter<std::net::SocketAddr>> {
314 <str as std::net::ToSocketAddrs>::to_socket_addrs(self.as_str())
315 }
316 }
317
318 };
319 (AsRef $self:ident, [$($other:ty),*]) => {
320 $(
321 impl AsRef<$other> for $self {
322 fn as_ref(&self) -> &$other {
323 <str as AsRef<$other>>::as_ref(self.as_str())
324 }
325 }
326 )*
327 };
328 (From $self:ident, [$($other:ty),*]) => {
329 $(
330 impl From<$self> for $other {
331 fn from(val: $self) -> $other {
332 From::from(val.as_str())
333 }
334 }
335 )*
336 };
337 (From 'a $self:ident, [$($other:ty),*]) => {
338 $(
339 impl<'a> From<$self> for $other {
340 fn from(val: $self) -> $other {
341 From::from(val.as_str())
342 }
343 }
344 )*
345 };
346 (FromIterator $self:ident, [$($other:ty),*]) => {
347 $(
348 impl std::iter::FromIterator<$self> for $other {
349 fn from_iter<T>(iter: T) -> $other
350 where
351 T: IntoIterator<Item = $self>
352 {
353 <$other as std::iter::FromIterator<&'static str>>::from_iter(iter.into_iter().map(|s| s.as_str()))
354 }
355 }
356 )*
357 };
358 (FromIterator 'a $self:ident, [$($other:ty),*]) => {
359 $(
360 impl<'a> std::iter::FromIterator<$self> for $other {
361 fn from_iter<T>(iter: T) -> $other
362 where
363 T: IntoIterator<Item = $self>
364 {
365 <$other as std::iter::FromIterator<&'static str>>::from_iter(iter.into_iter().map(|s| s.as_str()))
366 }
367 }
368 )*
369 };
370 (PartialEq $self:ident, [$($other:ty),*]) => {
371 $(
372 impl PartialEq<$self> for $other {
373 fn eq(&self, rhs: &$self) -> bool {
374 self.eq(rhs.as_str())
375 }
376 }
377
378 impl PartialEq<$other> for $self {
379 fn eq(&self, rhs: &$other) -> bool {
380 self.as_str().eq(rhs)
381 }
382 }
383 )*
384 };
385 (PartialEq 'a $self:ident, [$($other:ty),*]) => {
386 $(
387 impl<'a> PartialEq<$self> for $other {
388 fn eq(&self, rhs: &$self) -> bool {
389 self.eq(rhs.as_str())
390 }
391 }
392
393 impl<'a> PartialEq<$other> for $self {
394 fn eq(&self, rhs: &$other) -> bool {
395 self.as_str().eq(rhs)
396 }
397 }
398 )*
399 };
400 (PartialOrd $self:ident, [$($other:ty),*]) => {
401 $(
402 impl PartialOrd<$self> for $other {
403 fn partial_cmp(&self, rhs: &$self) -> Option<std::cmp::Ordering> {
404 self.partial_cmp(rhs.as_str())
405 }
406 }
407 )*
408 };
409 (PartialOrd 'a $self:ident, [$($other:ty),*]) => {
410 $(
411 impl<'a> PartialOrd<$self> for $other {
412 fn partial_cmp(&self, rhs: &$self) -> Option<std::cmp::Ordering> {
413 self.partial_cmp(rhs.as_str())
414 }
415 }
416 )*
417 };
418 (FromStr $(#[error_type($error_ty:ident)])? $(#[derive($($derive_trait:ident),* $(,)?)])? $(#[repr($repr:ty)])? $vis:vis enum $ty:ident { $($variant:ident $(= $variant_repr:literal)? => $val:literal $(($($other_valid:literal),* $(,)?))?),* $(,)? }) => {
419 $(
420 #[derive(Debug, Clone, Copy, Default)]
421 $vis struct $error_ty;
422
423 impl $error_ty {
424 #[doc = "Length of Self's error string. You do not need this."]
425 const EXPECTED_STR_LEN: usize = "expected one of [".len() + "]".len() + $ty::ALL_VALUES_STR_LEN;
426 #[doc = "Bytes of Self's error string. You do not need this."]
427 const EXPECTED_STR_BYTES: [u8; Self::EXPECTED_STR_LEN] = {
428 let mut buf = [0u8; Self::EXPECTED_STR_LEN];
429 let mut idx = 0;
430
431 let first_part = b"expected one of [";
432
433 while idx < first_part.len() {
434 buf[idx] = first_part[idx];
435 idx += 1
436 }
437
438 while idx < first_part.len() + $ty::ALL_VALUES_STR_LEN {
439 buf[idx] = $ty::ALL_VALUE_BYTES[idx - first_part.len()];
440 idx +=1
441 }
442 buf[Self::EXPECTED_STR_LEN - 1] = b']';
443
444 buf
445 };
446 #[doc = "&'static str of `Self::EXPECTED_STR_BYTES`. You do not need this."]
447 const EXPECTED_STR: &str = {
448 match str::from_utf8(&Self::EXPECTED_STR_BYTES) {
449 Ok(o) => o,
450 Err(_) => panic!(),
451 }
452 };
453 }
454
455 impl std::fmt::Display for $error_ty {
456 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
457 <str as std::fmt::Display>::fmt(Self::EXPECTED_STR, fmt)
458 }
459 }
460
461 impl std::error::Error for $error_ty {}
462
463 impl std::str::FromStr for $ty {
464 type Err = $error_ty;
465
466 fn from_str(s: &str) -> Result<$ty, Self::Err> {
467 match Self::try_from_str(s) {
468 Some(variant) => Ok(variant),
469 None => Err($error_ty)
470 }
471 }
472 }
473
474 impl TryFrom<&str> for $ty {
475 type Error = $error_ty;
476
477 fn try_from(s: &str) -> Result<$ty, Self::Error> {
478 match Self::try_from_str(s) {
479 Some(variant) => Ok(variant),
480 None => Err($error_ty)
481 }
482 }
483 }
484
485 impl TryFrom<String> for $ty {
486 type Error = $error_ty;
487
488 fn try_from(s: String) -> Result<$ty, Self::Error> {
489 match Self::try_from_str(&s) {
490 Some(variant) => Ok(variant),
491 None => Err($error_ty)
492 }
493 }
494 }
495
496 impl<'a> TryFrom<&'a std::ffi::OsStr> for $ty {
497 type Error = $crate::Utf8EnumError<$error_ty>;
498
499 fn try_from(value: &'a std::ffi::OsStr) -> Result<$ty, Self::Error> {
500 <&'a str as TryFrom<&'a std::ffi::OsStr>>::try_from(value)
501 .map_err($crate::Utf8EnumError::Utf8)
502 .and_then(|s| $ty::try_from(s).map_err($crate::Utf8EnumError::InvalidVariant))
503 }
504 }
505 )?
506 }
507}
508
509#[cfg(feature = "strum")]
510#[macro_export]
511macro_rules! str_enum_strum {
512 ($(#[error_type($error_ty:ident)])? $(#[derive($($derive_trait:ident),* $(,)?)])? $(#[repr($repr:ty)])? $vis:vis enum $ty:ident { $($variant:ident $(= $variant_repr:literal)? => $val:literal $(($($other_valid:literal),* $(,)?))?),* $(,)? }) => {
513 impl $crate::strum::EnumCount for $ty {
514 const COUNT: usize = $ty::ALL_VARIANTS.len();
515 }
516
517 $(
518 impl $crate::strum::IntoDiscriminant for $ty {
519 type Discriminant = $repr;
520
521 fn discriminant(&self) -> Self::Discriminant {
522 self.into_repr()
523 }
524 }
525 )?
526
527 impl $crate::strum::IntoEnumIterator for $ty {
528 type Iterator = std::array::IntoIter<$ty, {$ty::NUM_VARIANTS}>;
529
530 fn iter() -> Self::Iterator {
531 [$(Self::$variant,)*].into_iter()
532 }
533 }
534
535 impl $crate::strum::VariantArray for $ty {
536 const VARIANTS: &'static [Self] = Self::ALL_VARIANTS;
537 }
538
539 impl $crate::strum::VariantIterator for $ty {
540 type Iterator = std::array::IntoIter<$ty, {$ty::NUM_VARIANTS}>;
541
542 fn iter() -> Self::Iterator {
543 [$(Self::$variant,)*].into_iter()
544 }
545 }
546
547 impl $crate::strum::VariantNames for $ty {
548 const VARIANTS: &'static [&'static str] = &[$(stringify!($variant),)*];
549 }
550
551 impl $crate::strum::VariantMetadata for $ty {
552 const VARIANT_COUNT: usize = Self::ALL_VARIANTS.len();
553 const VARIANT_NAMES: &'static [&'static str] = &[$(stringify!($variant),)*];
554
555 fn variant_name(&self) -> &'static str {
556 match self {
557 $(Self::$variant => stringify!($variant),)*
558 }
559 }
560 }
561 };
562}
563
564#[macro_export]
565#[cfg(not(feature = "strum"))]
566macro_rules! str_enum_strum {
567 ($(#[error_type($error_ty:ident)])? $(#[derive($($derive_trait:ident),* $(,)?)])? $(#[repr($repr:ty)])? $vis:vis enum $ty:ident { $($variant:ident $(= $variant_repr:literal)? => $val:literal $(($($other_valid:literal),* $(,)?))?),* $(,)? }) => {};
568}
569
570#[macro_export]
571#[cfg(feature = "serde")]
572macro_rules! str_enum_serde {
573 ($(#[error_type($error_ty:ident)])? $(#[derive($($derive_trait:ident),* $(,)?)])? $(#[repr($repr:ty)])? $vis:vis enum $ty:ident { $($variant:ident $(= $variant_repr:literal)? => $val:literal $(($($other_valid:literal),* $(,)?))?),* $(,)? }) => {
574 impl $ty {
575 #[doc = "Length of Self's serde deserialize error. You do not need this."]
576 const SERDE_EXPECTED_STR_LEN: usize = "one of [".len() + "]".len() + Self::ALL_VALUES_STR_LEN;
577 #[doc = "Bytes of Self's serde deserialize error. You do not need this."]
578 const SERDE_EXPECTED_STR_BYTES: [u8; Self::SERDE_EXPECTED_STR_LEN] = {
579 let mut buf = [0u8; Self::SERDE_EXPECTED_STR_LEN];
580 let mut idx = 0;
581
582 let first_part = b"one of [";
583
584 while idx < first_part.len() {
585 buf[idx] = first_part[idx];
586 idx += 1
587 }
588
589 while idx < first_part.len() + Self::ALL_VALUES_STR_LEN {
590 buf[idx] = Self::ALL_VALUE_BYTES[idx - first_part.len()];
591 idx +=1
592 }
593 buf[Self::SERDE_EXPECTED_STR_LEN - 1] = b']';
594
595 buf
596 };
597
598 #[doc = "&'static str of `Self::SERDE_EXPECTED_STR_BYTES`. You do not need this."]
599 const SERDE_EXPECTED_STR: &str = {
600 match str::from_utf8(&Self::SERDE_EXPECTED_STR_BYTES) {
601 Ok(o) => o,
602 Err(_) => panic!(),
603 }
604 };
605 }
606
607
608 $(
609 impl $crate::serde::de::Expected for $error_ty {
610 fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
611 <str as std::fmt::Display>::fmt($ty::SERDE_EXPECTED_STR, formatter)
612 }
613 }
614 )?
615
616 impl $crate::serde::Serialize for $ty {
617 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
618 where
619 S: $crate::serde::Serializer,
620 {
621 self.as_str().serialize(serializer)
622 }
623 }
624
625 impl<'de> $crate::serde::Deserialize<'de> for $ty {
626 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
627 where
628 D: $crate::serde::Deserializer<'de>,
629 {
630 let val = <std::borrow::Cow<'_, str> as $crate::serde::Deserialize>::deserialize(deserializer)?;
631 $ty::try_from_str(&val).ok_or_else(|| $crate::serde::de::Error::invalid_value($crate::serde::de::Unexpected::Str(&val), &$ty::SERDE_EXPECTED_STR))
632 }
633 }
634 };
635}
636
637#[macro_export]
638#[cfg(not(feature = "serde"))]
639macro_rules! str_enum_serde {
640 ($(#[error_type($error_ty:ident)])? $(#[derive($($derive_trait:ident),* $(,)?)])? $(#[repr($repr:ty)])? $vis:vis enum $ty:ident { $($variant:ident $(= $variant_repr:literal)? => $val:literal $(($($other_valid:literal),* $(,)?))?),* $(,)? }) => {};
641}
642
643#[macro_export]
644macro_rules! str_enum {
645 ($(#[error_type($error_ty:ident)])? $(#[derive($($derive_trait:ident),* $(,)?)])? $(#[repr($repr:ty)])? $vis:vis enum $ty:ident { $($variant:ident $(= $variant_repr:literal)? => $val:literal $(($($other_valid:literal),* $(,)?))?),* $(,)? }) => {
646 $crate::str_enum_base!(
647 $(#[error_type($error_ty)])?
648 $(#[derive($($derive_trait,)*)])?
649 $(#[repr($repr)])?
650 $vis enum $ty {
651 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
652 }
653 );
654
655 $crate::str_enum_strum!(
656 $(#[error_type($error_ty)])?
657 $(#[derive($($derive_trait,)*)])?
658 $(#[repr($repr)])?
659 $vis enum $ty {
660 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
661 }
662 );
663
664 $crate::str_enum_serde!(
665 $(#[error_type($error_ty)])?
666 $(#[derive($($derive_trait,)*)])?
667 $(#[repr($repr)])?
668 $vis enum $ty {
669 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
670 }
671 );
672
673 $crate::str_enum_try_from_str!{
674 $(#[error_type($error_ty)])?
675 $(#[derive($($derive_trait,)*)])?
676 $(#[repr($repr)])?
677 $vis enum $ty {
678 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
679 }
680 }
681
682 $crate::str_enum_base!(FromStr
683 $(#[error_type($error_ty)])?
684 $(#[derive($($derive_trait,)*)])?
685 $(#[repr($repr)])?
686 $vis enum $ty {
687 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
688 }
689 );
690 };
691 (#[phf] $(#[error_type($error_ty:ident)])? $(#[derive($($derive_trait:ident),* $(,)?)])? $(#[repr($repr:ty)])? $vis:vis enum $ty:ident { $($variant:ident $(= $variant_repr:literal)? => $val:literal $(($($other_valid:literal),* $(,)?))?),* $(,)? }) => {
692 $crate::str_enum_base!(
693 $(#[error_type($error_ty)])?
694 $(#[derive($($derive_trait,)*)])?
695 $(#[repr($repr)])?
696 $vis enum $ty {
697 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
698 }
699 );
700
701 $crate::str_enum_strum!(
702 $(#[error_type($error_ty)])?
703 $(#[derive($($derive_trait,)*)])?
704 $(#[repr($repr)])?
705 $vis enum $ty {
706 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
707 }
708 );
709
710 $crate::str_enum_serde!(
711 $(#[error_type($error_ty)])?
712 $(#[derive($($derive_trait,)*)])?
713 $(#[repr($repr)])?
714 $vis enum $ty {
715 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
716 }
717 );
718
719 $crate::str_enum_try_from_str!{
720 #[phf]
721 $(#[error_type($error_ty)])?
722 $(#[derive($($derive_trait,)*)])?
723 $(#[repr($repr)])?
724 $vis enum $ty {
725 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
726 }
727 }
728
729 $crate::str_enum_base!(FromStr
730 $(#[error_type($error_ty)])?
731 $(#[derive($($derive_trait,)*)])?
732 $(#[repr($repr)])?
733 $vis enum $ty {
734 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
735 }
736 );
737 };
738}
739
740#[derive(Debug, Clone, Copy, PartialEq, Eq)]
741pub enum Utf8EnumError<E> {
742 Utf8(std::str::Utf8Error),
743 InvalidVariant(E),
744}
745
746impl<E> std::fmt::Display for Utf8EnumError<E>
747where
748 E: std::fmt::Display,
749{
750 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
751 match self {
752 Utf8EnumError::Utf8(utf8_error) => utf8_error.fmt(f),
753 Utf8EnumError::InvalidVariant(variant_error) => variant_error.fmt(f),
754 }
755 }
756}
757
758impl<E> std::error::Error for Utf8EnumError<E> where E: std::error::Error {}