zenum 0.0.0-reserved

swiss-army knife of derives for enums
#[macro_export]
macro_rules! FromStr {
    derive() (
        // <enum_parse: start> NOTE: generated by `generate.rs`
        $(#[$($enum_attr:tt)*])*
        $enum_vis:vis enum $enum_ident:ident
            // a best-effort parsing of generics
            //
            // what's missing:
            //
            // - more than 1 lifetime bound (e.g. 'a: 'b + 'c)
            // - more than 1 trait bound (e.g. T: A + B + C)
            // - support for "use" TypeParam in trait bounds
            // - `const` type parameters are totally unsupported
            // - `for<..>` lifetimes in `where` clause
            $(<
                $(
                    $(#[$($type_param_attr:tt)*])*
                    // lifetime parameter
                    $($type_param_lifetime:lifetime $(: $type_param_lifetime_super:lifetime)?)?
                    // type parameter
                    $($type_param_type:ident
                        $(:
                            $($type_param_lifetime_bound:lifetime)?
                            $($type_param_type_bound:path)?
                        )? $(= $type_param_default:ty)?
                    )?
                ),*
                $(,)?
            >)?
            $(where $(
                $($where_lifetime:lifetime: $where_lifetime_bounds:lifetime)?
                $($where_type_param_ty:ty: $where_type_param_bounds:path)?
            ),*)?
        {
            $(
                $(#[$($enum_variant_attr:tt)*])*
                $enum_variant:ident
                    // enum with named fields
                    $({
                        $(
                            $(#[$($enum_variant_named_field_attr:tt)*])*
                            $enum_variant_named_field_ident:ident: $enum_variant_named_field_ty:ty
                        ),* $(,)?
                    })?
                    // enum with unnamed fields
                    $((
                        $(
                            $(#[$($enum_variant_unnamed_field_attr:tt)*])*
                            $enum_variant_unnamed_field_ty:ty
                        ),* $(,)?
                    ))?
                    // discriminant
                    $(= $enum_variant_discriminant:expr)?
            ),* $(,)?
        }
        // <enum_parse: end>
    ) => {
        impl ::core::str::FromStr for $enum_ident {
            type Err = ();

            fn from_str(s: &::core::primitive::str) -> ::core::result::Result<Self, Self::Err> {
                // <rename_all: start> NOTE: generated by `generate.rs`
                const STREN_RENAME_ALL: Option<$crate::private::const_format::Case> = {
                    match $crate::extract_field!(rename_all: $(#[$($enum_attr)*])*) {
                        Some("lowercase") => Some($crate::private::const_format::Case::Lower),
                        Some("UPPERCASE") => Some($crate::private::const_format::Case::Upper),
                        Some("PascalCase") => Some($crate::private::const_format::Case::Pascal),
                        Some("camelCase") => Some($crate::private::const_format::Case::Camel),
                        Some("snake_case") => Some($crate::private::const_format::Case::Snake),
                        Some("SCREAMING_SNAKE_CASE") => Some($crate::private::const_format::Case::UpperSnake),
                        Some("kebab-case") => Some($crate::private::const_format::Case::Kebab),
                        Some("SCREAMING-KEBAB-CASE") => Some($crate::private::const_format::Case::UpperKebab),
                        Some(unknown) => panic!("invalid value for `#[stren(rename_all_fields)]`"),
                        None => None
                    }
                };
                // <rename_all: end>
                $(
                    #[allow(non_upper_case_globals)]
                    const $enum_variant: (&str, bool) = {
                        const FIELD_STR: &str = stringify!($enum_ident);

                        let rename: Option<&str> = $crate::extract_field!(rename: $(#[$($enum_variant_attr)*])*);

                        // actual string representation of the enum variant
                        let name = if let Some(rename) = rename {
                            // supplied #[stren(rename = "blabla")]
                            rename
                        } else if STREN_RENAME_ALL.is_some() {
                            // Apply "rename-all" rule to this string

                            // this is very bad, we have to do it like this because `if let Some(s) = Y` with `s`
                            // cannot be used in a `const` context
                            //
                            // Apparently every single branch gets evaluated in `const`, so we must make it always compile.
                            // The `or` path will never actually be taken
                            $crate::private::const_format::map_ascii_case!(STREN_RENAME_ALL.unwrap_or($crate::private::const_format::Case::Lower), FIELD_STR)
                        } else {
                            // default to stringified name of the enum variant
                            FIELD_STR
                        };
                        let is_disabled: Option<()> = $crate::extract_field!(disabled: $(#[$($enum_variant_attr)*])*);

                        (name, is_disabled.is_some())
                    };
                )*
                match s {
                    $(
                        v if v == $enum_variant.0
                        // not #[stren(disabled)]
                        && !$enum_variant.1 => Ok(Self::$enum_variant
                            // enum with named fields
                            $({
                                $(
                                    $enum_variant_named_field_ident:
                                    <$enum_variant_named_field_ty as ::core::default::Default>::default(),
                                )*
                            })?
                            // enum with unnamed fields
                            $((
                                $(
                                    <$enum_variant_unnamed_field_ty as ::core::default::Default>::default(),
                                )*
                            ))?
                        ),
                    )*
                    _ => Err(())
                }
            }
        }
    };
}