1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#[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(())
}
}
}
};
}