Skip to content

Commit 4f4ea0b

Browse files
committed
Support standard #[default] attr for FromPrimitive
rust-lang/rust#87517 started standardising `#[default]` as an attribute on enum variants, support it compatibly identically to `#[num_enum(default)]`.
1 parent 370feb9 commit 4f4ea0b

10 files changed

+99
-34
lines changed

num_enum/tests/from_primitive.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,26 @@ fn has_from_primitive_number() {
2828
assert_eq!(two, Enum::NonZero);
2929
}
3030

31+
#[test]
32+
fn has_from_primitive_number_standard_default_attribute() {
33+
#[derive(Debug, Eq, PartialEq, FromPrimitive)]
34+
#[repr(u8)]
35+
enum Enum {
36+
Zero = 0,
37+
#[default]
38+
NonZero = 1,
39+
}
40+
41+
let zero = Enum::from_primitive(0_u8);
42+
assert_eq!(zero, Enum::Zero);
43+
44+
let one = Enum::from_primitive(1_u8);
45+
assert_eq!(one, Enum::NonZero);
46+
47+
let two = Enum::from_primitive(2_u8);
48+
assert_eq!(two, Enum::NonZero);
49+
}
50+
3151
#[test]
3252
fn from_primitive_number() {
3353
#[derive(Debug, Eq, PartialEq, FromPrimitive)]

num_enum/tests/try_build/compile_fail/exhaustive_enum.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: #[derive(FromPrimitive)] requires a variant marked with `#[num_enum(default)]`
1+
error: #[derive(FromPrimitive)] requires a variant marked with `#[default]` or `#[num_enum(default)]`
22
--> $DIR/exhaustive_enum.rs:1:10
33
|
44
1 | #[derive(num_enum::FromPrimitive)]

num_enum/tests/try_build/compile_fail/missing_default.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: #[derive(FromPrimitive)] requires a variant marked with `#[num_enum(default)]`
1+
error: #[derive(FromPrimitive)] requires a variant marked with `#[default]` or `#[num_enum(default)]`
22
--> $DIR/missing_default.rs:1:10
33
|
44
1 | #[derive(num_enum::FromPrimitive)]

num_enum/tests/try_build/compile_fail/multiple_defaults.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
#[repr(u8)]
33
enum Numbers {
44
Zero,
5-
#[num_enum(default)]
5+
#[default]
66
One,
7-
#[num_enum(default)]
7+
#[default]
88
Two,
99
}
1010

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
error: Multiple variants marked `#[num_enum(default)]` found
2-
--> $DIR/multiple_defaults.rs:7:16
1+
error: Multiple variants marked `#[default]` or `#[num_enum(default)]` found
2+
--> $DIR/multiple_defaults.rs:7:5
33
|
4-
7 | #[num_enum(default)]
5-
| ^^^^^^^
4+
7 | #[default]
5+
| ^^^^^^^^^^
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#[derive(num_enum::FromPrimitive, num_enum::TryFromPrimitive)]
2+
#[repr(u8)]
3+
enum Numbers {
4+
Zero,
5+
#[default]
6+
One,
7+
#[num_enum(default)]
8+
Two,
9+
}
10+
11+
fn main() {
12+
13+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: Multiple variants marked `#[default]` or `#[num_enum(default)]` found
2+
--> $DIR/multiple_defaults_different_kinds.rs:7:16
3+
|
4+
7 | #[num_enum(default)]
5+
| ^^^^^^^
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#[derive(num_enum::FromPrimitive, num_enum::TryFromPrimitive)]
2+
#[repr(u8)]
3+
enum Numbers {
4+
Zero,
5+
#[num_enum(default)]
6+
One,
7+
#[num_enum(default)]
8+
Two,
9+
}
10+
11+
fn main() {
12+
13+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: Multiple variants marked `#[default]` or `#[num_enum(default)]` found
2+
--> $DIR/multiple_num_enum_defaults.rs:7:16
3+
|
4+
7 | #[num_enum(default)]
5+
| ^^^^^^^

num_enum_derive/src/lib.rs

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -270,35 +270,44 @@ impl Parse for EnumInfo {
270270
let mut is_default: bool = false;
271271

272272
for attribute in variant.attrs {
273-
if !attribute.path.is_ident("num_enum") {
274-
continue;
275-
}
276-
match attribute.parse_args_with(NumEnumVariantAttributes::parse) {
277-
Ok(variant_attributes) => {
278-
for variant_attribute in variant_attributes.items.iter() {
279-
match variant_attribute {
280-
NumEnumVariantAttributeItem::Default(default) => {
281-
if has_default_variant {
282-
die!(default.keyword =>
283-
"Multiple variants marked `#[num_enum(default)]` found"
284-
);
273+
if attribute.path.is_ident("default") {
274+
if has_default_variant {
275+
die!(attribute =>
276+
"Multiple variants marked `#[default]` or `#[num_enum(default)]` found"
277+
);
278+
}
279+
attr_spans.default.push(attribute.span());
280+
is_default = true;
281+
} else if attribute.path.is_ident("num_enum") {
282+
match attribute.parse_args_with(NumEnumVariantAttributes::parse) {
283+
Ok(variant_attributes) => {
284+
for variant_attribute in variant_attributes.items.iter() {
285+
match variant_attribute {
286+
NumEnumVariantAttributeItem::Default(default) => {
287+
if has_default_variant {
288+
die!(default.keyword =>
289+
"Multiple variants marked `#[default]` or `#[num_enum(default)]` found"
290+
);
291+
}
292+
attr_spans.default.push(default.span());
293+
is_default = true;
294+
}
295+
NumEnumVariantAttributeItem::Alternatives(alternatives) => {
296+
attr_spans.alternatives.push(alternatives.span());
297+
alternative_values
298+
.extend(alternatives.expressions.iter().cloned());
285299
}
286-
attr_spans.default.push(default.span());
287-
is_default = true;
288-
}
289-
NumEnumVariantAttributeItem::Alternatives(alternatives) => {
290-
attr_spans.alternatives.push(alternatives.span());
291-
alternative_values
292-
.extend(alternatives.expressions.iter().cloned());
293300
}
294301
}
295302
}
303+
Err(err) => {
304+
die!(attribute =>
305+
format!("Invalid attribute: {}", err)
306+
);
307+
}
296308
}
297-
Err(err) => {
298-
die!(attribute =>
299-
format!("Invalid attribute: {}", err)
300-
);
301-
}
309+
} else {
310+
continue;
302311
}
303312

304313
has_default_variant |= is_default;
@@ -387,7 +396,7 @@ pub fn derive_into_primitive(input: TokenStream) -> TokenStream {
387396
/// let two = Number::from(2u8);
388397
/// assert_eq!(two, Number::NonZero);
389398
/// ```
390-
#[proc_macro_derive(FromPrimitive, attributes(num_enum))]
399+
#[proc_macro_derive(FromPrimitive, attributes(num_enum, default))]
391400
pub fn derive_from_primitive(input: TokenStream) -> TokenStream {
392401
let enum_info: EnumInfo = parse_macro_input!(input);
393402
let krate = Ident::new(&get_crate_name(), Span::call_site());
@@ -397,7 +406,7 @@ pub fn derive_from_primitive(input: TokenStream) -> TokenStream {
397406
None => {
398407
let span = Span::call_site();
399408
let message =
400-
"#[derive(FromPrimitive)] requires a variant marked with `#[num_enum(default)]`";
409+
"#[derive(FromPrimitive)] requires a variant marked with `#[default]` or `#[num_enum(default)]`";
401410
return syn::Error::new(span, message).to_compile_error().into();
402411
}
403412
};

0 commit comments

Comments
 (0)