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
170 $(
171 impl $ty {
172 #[doc = "Convert this enum into its repr"]
173 fn into_repr(self) -> $repr {
174 self as $repr
175 }
176 }
177
178 impl From<$ty> for $repr {
179 fn from(v: $ty) -> $repr {
180 v as $repr
181 }
182 }
183 )?
184
185 impl std::fmt::Display for $ty {
186 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187 <str as std::fmt::Display>::fmt(self.as_str(), fmt)
188 }
189 }
190
191 impl std::borrow::Borrow<str> for $ty {
192 fn borrow(&self) -> &str {
193 self.as_str()
194 }
195 }
196
197 impl std::hash::Hash for $ty {
198 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
199 <str as std::hash::Hash>::hash(self.as_str(), state)
200 }
201 }
202
203 impl<'a> std::ops::Add<$ty> for std::borrow::Cow<'a, str> {
204 type Output = std::borrow::Cow<'a, str>;
205
206 fn add(self, rhs: $ty) -> std::borrow::Cow<'a, str> {
207 self.add(rhs.as_str())
208 }
209 }
210
211 impl std::ops::Add<$ty> for String {
212 type Output = String;
213
214 fn add(self, rhs: $ty) -> String {
215 self.add(rhs.as_str())
216 }
217 }
218
219 impl<'a> std::ops::AddAssign<$ty> for std::borrow::Cow<'a, str> {
220 fn add_assign(&mut self, rhs: $ty) {
221 self.add_assign(rhs.as_str())
222 }
223 }
224
225 impl std::ops::AddAssign<$ty> for String {
226 fn add_assign(&mut self, rhs: $ty) {
227 self.add_assign(rhs.as_str())
228 }
229 }
230
231 $crate::str_enum_base!(AsRef $ty, [str, std::ffi::OsStr, std::path::Path, [u8]]);
232
233 impl Extend<$ty> for String {
234 fn extend<I>(&mut self, iter: I) where I: IntoIterator<Item = $ty> {
235 iter.into_iter().for_each(move |s| self.push_str(s.as_str()))
236 }
237 }
238
239 $crate::str_enum_base!(From $ty, [std::sync::Arc<str>, Box<str>, std::rc::Rc<str>, String, Vec<u8>]);
240 $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>]);
241 $crate::str_enum_base!(FromIterator $ty, [Box<str>, String]);
242 $crate::str_enum_base!(FromIterator 'a $ty, [std::borrow::Cow<'a, str>]);
243
244 impl<I: std::slice::SliceIndex<str>> std::ops::Index<I> for $ty {
245 type Output = <I as std::slice::SliceIndex<str>>::Output;
246
247 fn index(&self, index: I) -> &<I as std::slice::SliceIndex<str>>::Output {
248 self.as_str().index(index)
249 }
250 }
251
252 $crate::str_enum_base!(PartialEq $ty, [std::ffi::OsStr, std::ffi::OsString, String, std::path::Path, std::path::PathBuf]);
253 $crate::str_enum_base!(PartialEq 'a $ty, [std::borrow::Cow<'a, str>]);
254
255 impl PartialEq<&str> for $ty {
256 fn eq(&self, rhs: &&str) -> bool {
257 self.as_str().eq(*rhs)
258 }
259 }
260
261 impl PartialEq<$ty> for &str {
262 fn eq(&self, rhs: &$ty) -> bool {
263 self.eq(&rhs.as_str())
264 }
265 }
266
267 impl PartialEq<str> for $ty {
268 fn eq(&self, rhs: &str) -> bool {
269 self.as_str().eq(rhs)
270 }
271 }
272
273 impl PartialEq<$ty> for str {
274 fn eq(&self, rhs: &$ty) -> bool {
275 self.eq(rhs.as_str())
276 }
277 }
278
279 $crate::str_enum_base!(PartialOrd $ty, [std::ffi::OsStr, std::ffi::OsString]);
280
281 impl PartialOrd<$ty> for str {
282 fn partial_cmp(&self, rhs: &$ty) -> Option<std::cmp::Ordering> {
283 self.partial_cmp(rhs.as_str())
284 }
285 }
286
287 impl PartialOrd<str> for $ty {
288 fn partial_cmp(&self, rhs: &str) -> Option<std::cmp::Ordering> {
289 self.as_str().partial_cmp(rhs)
290 }
291 }
292
293 impl PartialOrd<$ty> for &str {
294 fn partial_cmp(&self, rhs: &$ty) -> Option<std::cmp::Ordering> {
295 self.partial_cmp(&rhs.as_str())
296 }
297 }
298
299 impl PartialOrd<&str> for $ty {
300 fn partial_cmp(&self, rhs: &&str) -> Option<std::cmp::Ordering> {
301 self.as_str().partial_cmp(*rhs)
302 }
303 }
304
305 impl std::net::ToSocketAddrs for $ty {
306 type Iter = std::vec::IntoIter<std::net::SocketAddr>;
307
308 fn to_socket_addrs(&self) -> std::io::Result<std::vec::IntoIter<std::net::SocketAddr>> {
309 <str as std::net::ToSocketAddrs>::to_socket_addrs(self.as_str())
310 }
311 }
312
313 };
314 (AsRef $self:ident, [$($other:ty),*]) => {
315 $(
316 impl AsRef<$other> for $self {
317 fn as_ref(&self) -> &$other {
318 <str as AsRef<$other>>::as_ref(self.as_str())
319 }
320 }
321 )*
322 };
323 (From $self:ident, [$($other:ty),*]) => {
324 $(
325 impl From<$self> for $other {
326 fn from(val: $self) -> $other {
327 From::from(val.as_str())
328 }
329 }
330 )*
331 };
332 (From 'a $self:ident, [$($other:ty),*]) => {
333 $(
334 impl<'a> From<$self> for $other {
335 fn from(val: $self) -> $other {
336 From::from(val.as_str())
337 }
338 }
339 )*
340 };
341 (FromIterator $self:ident, [$($other:ty),*]) => {
342 $(
343 impl std::iter::FromIterator<$self> for $other {
344 fn from_iter<T>(iter: T) -> $other
345 where
346 T: IntoIterator<Item = $self>
347 {
348 <$other as std::iter::FromIterator<&'static str>>::from_iter(iter.into_iter().map(|s| s.as_str()))
349 }
350 }
351 )*
352 };
353 (FromIterator 'a $self:ident, [$($other:ty),*]) => {
354 $(
355 impl<'a> std::iter::FromIterator<$self> for $other {
356 fn from_iter<T>(iter: T) -> $other
357 where
358 T: IntoIterator<Item = $self>
359 {
360 <$other as std::iter::FromIterator<&'static str>>::from_iter(iter.into_iter().map(|s| s.as_str()))
361 }
362 }
363 )*
364 };
365 (PartialEq $self:ident, [$($other:ty),*]) => {
366 $(
367 impl PartialEq<$self> for $other {
368 fn eq(&self, rhs: &$self) -> bool {
369 self.eq(rhs.as_str())
370 }
371 }
372
373 impl PartialEq<$other> for $self {
374 fn eq(&self, rhs: &$other) -> bool {
375 self.as_str().eq(rhs)
376 }
377 }
378 )*
379 };
380 (PartialEq 'a $self:ident, [$($other:ty),*]) => {
381 $(
382 impl<'a> PartialEq<$self> for $other {
383 fn eq(&self, rhs: &$self) -> bool {
384 self.eq(rhs.as_str())
385 }
386 }
387
388 impl<'a> PartialEq<$other> for $self {
389 fn eq(&self, rhs: &$other) -> bool {
390 self.as_str().eq(rhs)
391 }
392 }
393 )*
394 };
395 (PartialOrd $self:ident, [$($other:ty),*]) => {
396 $(
397 impl PartialOrd<$self> for $other {
398 fn partial_cmp(&self, rhs: &$self) -> Option<std::cmp::Ordering> {
399 self.partial_cmp(rhs.as_str())
400 }
401 }
402 )*
403 };
404 (PartialOrd 'a $self:ident, [$($other:ty),*]) => {
405 $(
406 impl<'a> PartialOrd<$self> for $other {
407 fn partial_cmp(&self, rhs: &$self) -> Option<std::cmp::Ordering> {
408 self.partial_cmp(rhs.as_str())
409 }
410 }
411 )*
412 };
413 (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),* $(,)?))?),* $(,)? }) => {
414 $(
415 #[derive(Debug, Clone, Copy, Default)]
416 $vis struct $error_ty;
417
418 impl $error_ty {
419 #[doc = "Length of Self's error string. You do not need this."]
420 const EXPECTED_STR_LEN: usize = "expected one of [".len() + "]".len() + $ty::ALL_VALUES_STR_LEN;
421 #[doc = "Bytes of Self's error string. You do not need this."]
422 const EXPECTED_STR_BYTES: [u8; Self::EXPECTED_STR_LEN] = {
423 let mut buf = [0u8; Self::EXPECTED_STR_LEN];
424 let mut idx = 0;
425
426 let first_part = b"expected one of [";
427
428 while idx < first_part.len() {
429 buf[idx] = first_part[idx];
430 idx += 1
431 }
432
433 while idx < first_part.len() + $ty::ALL_VALUES_STR_LEN {
434 buf[idx] = $ty::ALL_VALUE_BYTES[idx - first_part.len()];
435 idx +=1
436 }
437 buf[Self::EXPECTED_STR_LEN - 1] = b']';
438
439 buf
440 };
441 #[doc = "&'static str of `Self::EXPECTED_STR_BYTES`. You do not need this."]
442 const EXPECTED_STR: &str = {
443 match str::from_utf8(&Self::EXPECTED_STR_BYTES) {
444 Ok(o) => o,
445 Err(_) => panic!(),
446 }
447 };
448 }
449
450 impl std::fmt::Display for $error_ty {
451 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
452 <str as std::fmt::Display>::fmt(Self::EXPECTED_STR, fmt)
453 }
454 }
455
456 impl std::error::Error for $error_ty {}
457
458 impl std::str::FromStr for $ty {
459 type Err = $error_ty;
460
461 fn from_str(s: &str) -> Result<$ty, Self::Err> {
462 match Self::try_from_str(s) {
463 Some(variant) => Ok(variant),
464 None => Err($error_ty)
465 }
466 }
467 }
468
469 impl TryFrom<&str> for $ty {
470 type Error = $error_ty;
471
472 fn try_from(s: &str) -> Result<$ty, Self::Error> {
473 match Self::try_from_str(s) {
474 Some(variant) => Ok(variant),
475 None => Err($error_ty)
476 }
477 }
478 }
479
480 impl TryFrom<String> for $ty {
481 type Error = $error_ty;
482
483 fn try_from(s: String) -> Result<$ty, Self::Error> {
484 match Self::try_from_str(&s) {
485 Some(variant) => Ok(variant),
486 None => Err($error_ty)
487 }
488 }
489 }
490
491 impl<'a> TryFrom<&'a std::ffi::OsStr> for $ty {
492 type Error = $crate::Utf8EnumError<$error_ty>;
493
494 fn try_from(value: &'a std::ffi::OsStr) -> Result<$ty, Self::Error> {
495 <&'a str as TryFrom<&'a std::ffi::OsStr>>::try_from(value)
496 .map_err($crate::Utf8EnumError::Utf8)
497 .and_then(|s| $ty::try_from(s).map_err($crate::Utf8EnumError::InvalidVariant))
498 }
499 }
500 )?
501 }
502}
503
504#[cfg(feature = "strum")]
505#[macro_export]
506macro_rules! str_enum_strum {
507 ($(#[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),* $(,)?))?),* $(,)? }) => {
508 impl $crate::strum::EnumCount for $ty {
509 const COUNT: usize = $ty::ALL_VARIANTS.len();
510 }
511
512 $(
513 impl $crate::strum::IntoDiscriminant for $ty {
514 type Discriminant = $repr;
515
516 fn discriminant(&self) -> Self::Discriminant {
517 self.into_repr()
518 }
519 }
520 )?
521
522 impl $crate::strum::IntoEnumIterator for $ty {
523 type Iterator = std::array::IntoIter<$ty, {$ty::NUM_VARIANTS}>;
524
525 fn iter() -> Self::Iterator {
526 [$(Self::$variant,)*].into_iter()
527 }
528 }
529
530 impl $crate::strum::VariantArray for $ty {
531 const VARIANTS: &'static [Self] = Self::ALL_VARIANTS;
532 }
533
534 impl $crate::strum::VariantIterator for $ty {
535 type Iterator = std::array::IntoIter<$ty, {$ty::NUM_VARIANTS}>;
536
537 fn iter() -> Self::Iterator {
538 [$(Self::$variant,)*].into_iter()
539 }
540 }
541
542 impl $crate::strum::VariantNames for $ty {
543 const VARIANTS: &'static [&'static str] = &[$(stringify!($variant),)*];
544 }
545
546 impl $crate::strum::VariantMetadata for $ty {
547 const VARIANT_COUNT: usize = Self::ALL_VARIANTS.len();
548 const VARIANT_NAMES: &'static [&'static str] = &[$(stringify!($variant),)*];
549
550 fn variant_name(&self) -> &'static str {
551 match self {
552 $(Self::$variant => stringify!($variant),)*
553 }
554 }
555 }
556 };
557}
558
559#[macro_export]
560#[cfg(not(feature = "strum"))]
561macro_rules! str_enum_strum {
562 ($(#[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),* $(,)?))?),* $(,)? }) => {};
563}
564
565#[macro_export]
566#[cfg(feature = "serde")]
567macro_rules! str_enum_serde {
568 ($(#[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),* $(,)?))?),* $(,)? }) => {
569 impl $ty {
570 #[doc = "Length of Self's serde deserialize error. You do not need this."]
571 const SERDE_EXPECTED_STR_LEN: usize = "one of [".len() + "]".len() + Self::ALL_VALUES_STR_LEN;
572 #[doc = "Bytes of Self's serde deserialize error. You do not need this."]
573 const SERDE_EXPECTED_STR_BYTES: [u8; Self::SERDE_EXPECTED_STR_LEN] = {
574 let mut buf = [0u8; Self::SERDE_EXPECTED_STR_LEN];
575 let mut idx = 0;
576
577 let first_part = b"one of [";
578
579 while idx < first_part.len() {
580 buf[idx] = first_part[idx];
581 idx += 1
582 }
583
584 while idx < first_part.len() + Self::ALL_VALUES_STR_LEN {
585 buf[idx] = Self::ALL_VALUE_BYTES[idx - first_part.len()];
586 idx +=1
587 }
588 buf[Self::SERDE_EXPECTED_STR_LEN - 1] = b']';
589
590 buf
591 };
592
593 #[doc = "&'static str of `Self::SERDE_EXPECTED_STR_BYTES`. You do not need this."]
594 const SERDE_EXPECTED_STR: &str = {
595 match str::from_utf8(&Self::SERDE_EXPECTED_STR_BYTES) {
596 Ok(o) => o,
597 Err(_) => panic!(),
598 }
599 };
600 }
601
602
603 $(
604 impl $crate::serde::de::Expected for $error_ty {
605 fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
606 <str as std::fmt::Display>::fmt($ty::SERDE_EXPECTED_STR, formatter)
607 }
608 }
609 )?
610
611 impl $crate::serde::Serialize for $ty {
612 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
613 where
614 S: $crate::serde::Serializer,
615 {
616 self.as_str().serialize(serializer)
617 }
618 }
619
620 impl<'de> $crate::serde::Deserialize<'de> for $ty {
621 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
622 where
623 D: $crate::serde::Deserializer<'de>,
624 {
625 let val = <std::borrow::Cow<'_, str> as $crate::serde::Deserialize>::deserialize(deserializer)?;
626 $ty::try_from_str(&val).ok_or_else(|| $crate::serde::de::Error::invalid_value($crate::serde::de::Unexpected::Str(&val), &$ty::SERDE_EXPECTED_STR))
627 }
628 }
629 };
630}
631
632#[macro_export]
633#[cfg(not(feature = "serde"))]
634macro_rules! str_enum_serde {
635 ($(#[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),* $(,)?))?),* $(,)? }) => {};
636}
637
638#[macro_export]
639macro_rules! str_enum {
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 $crate::str_enum_base!(
642 $(#[error_type($error_ty)])?
643 $(#[derive($($derive_trait,)*)])?
644 $(#[repr($repr)])?
645 $vis enum $ty {
646 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
647 }
648 );
649
650 $crate::str_enum_strum!(
651 $(#[error_type($error_ty)])?
652 $(#[derive($($derive_trait,)*)])?
653 $(#[repr($repr)])?
654 $vis enum $ty {
655 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
656 }
657 );
658
659 $crate::str_enum_serde!(
660 $(#[error_type($error_ty)])?
661 $(#[derive($($derive_trait,)*)])?
662 $(#[repr($repr)])?
663 $vis enum $ty {
664 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
665 }
666 );
667
668 $crate::str_enum_try_from_str!{
669 $(#[error_type($error_ty)])?
670 $(#[derive($($derive_trait,)*)])?
671 $(#[repr($repr)])?
672 $vis enum $ty {
673 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
674 }
675 }
676
677 $crate::str_enum_base!(FromStr
678 $(#[error_type($error_ty)])?
679 $(#[derive($($derive_trait,)*)])?
680 $(#[repr($repr)])?
681 $vis enum $ty {
682 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
683 }
684 );
685 };
686 (#[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),* $(,)?))?),* $(,)? }) => {
687 $crate::str_enum_base!(
688 $(#[error_type($error_ty)])?
689 $(#[derive($($derive_trait,)*)])?
690 $(#[repr($repr)])?
691 $vis enum $ty {
692 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
693 }
694 );
695
696 $crate::str_enum_strum!(
697 $(#[error_type($error_ty)])?
698 $(#[derive($($derive_trait,)*)])?
699 $(#[repr($repr)])?
700 $vis enum $ty {
701 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
702 }
703 );
704
705 $crate::str_enum_serde!(
706 $(#[error_type($error_ty)])?
707 $(#[derive($($derive_trait,)*)])?
708 $(#[repr($repr)])?
709 $vis enum $ty {
710 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
711 }
712 );
713
714 $crate::str_enum_try_from_str!{
715 #[phf]
716 $(#[error_type($error_ty)])?
717 $(#[derive($($derive_trait,)*)])?
718 $(#[repr($repr)])?
719 $vis enum $ty {
720 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
721 }
722 }
723
724 $crate::str_enum_base!(FromStr
725 $(#[error_type($error_ty)])?
726 $(#[derive($($derive_trait,)*)])?
727 $(#[repr($repr)])?
728 $vis enum $ty {
729 $($variant $(= $variant_repr)? => $val $(($($other_valid),*))?,)*
730 }
731 );
732 };
733}
734
735#[derive(Debug, Clone, Copy, PartialEq, Eq)]
736pub enum Utf8EnumError<E> {
737 Utf8(std::str::Utf8Error),
738 InvalidVariant(E),
739}
740
741impl<E> std::fmt::Display for Utf8EnumError<E>
742where
743 E: std::fmt::Display,
744{
745 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
746 match self {
747 Utf8EnumError::Utf8(utf8_error) => utf8_error.fmt(f),
748 Utf8EnumError::InvalidVariant(variant_error) => variant_error.fmt(f),
749 }
750 }
751}
752
753impl<E> std::error::Error for Utf8EnumError<E> where E: std::error::Error {}