Skip to content

Commit

Permalink
Support standard #[default] attr for FromPrimitive
Browse files Browse the repository at this point in the history
rust-lang/rust#87517 started standardising
`#[default]` as an attribute on enum variants, support it compatibly
identically to `#[num_enum(default)]`.
  • Loading branch information
illicitonion committed Aug 16, 2021
1 parent 370feb9 commit 4f4ea0b
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 34 deletions.
20 changes: 20 additions & 0 deletions num_enum/tests/from_primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@ fn has_from_primitive_number() {
assert_eq!(two, Enum::NonZero);
}

#[test]
fn has_from_primitive_number_standard_default_attribute() {
#[derive(Debug, Eq, PartialEq, FromPrimitive)]
#[repr(u8)]
enum Enum {
Zero = 0,
#[default]
NonZero = 1,
}

let zero = Enum::from_primitive(0_u8);
assert_eq!(zero, Enum::Zero);

let one = Enum::from_primitive(1_u8);
assert_eq!(one, Enum::NonZero);

let two = Enum::from_primitive(2_u8);
assert_eq!(two, Enum::NonZero);
}

#[test]
fn from_primitive_number() {
#[derive(Debug, Eq, PartialEq, FromPrimitive)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: #[derive(FromPrimitive)] requires a variant marked with `#[num_enum(default)]`
error: #[derive(FromPrimitive)] requires a variant marked with `#[default]` or `#[num_enum(default)]`
--> $DIR/exhaustive_enum.rs:1:10
|
1 | #[derive(num_enum::FromPrimitive)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: #[derive(FromPrimitive)] requires a variant marked with `#[num_enum(default)]`
error: #[derive(FromPrimitive)] requires a variant marked with `#[default]` or `#[num_enum(default)]`
--> $DIR/missing_default.rs:1:10
|
1 | #[derive(num_enum::FromPrimitive)]
Expand Down
4 changes: 2 additions & 2 deletions num_enum/tests/try_build/compile_fail/multiple_defaults.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
#[repr(u8)]
enum Numbers {
Zero,
#[num_enum(default)]
#[default]
One,
#[num_enum(default)]
#[default]
Two,
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: Multiple variants marked `#[num_enum(default)]` found
--> $DIR/multiple_defaults.rs:7:16
error: Multiple variants marked `#[default]` or `#[num_enum(default)]` found
--> $DIR/multiple_defaults.rs:7:5
|
7 | #[num_enum(default)]
| ^^^^^^^
7 | #[default]
| ^^^^^^^^^^
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#[derive(num_enum::FromPrimitive, num_enum::TryFromPrimitive)]
#[repr(u8)]
enum Numbers {
Zero,
#[default]
One,
#[num_enum(default)]
Two,
}

fn main() {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: Multiple variants marked `#[default]` or `#[num_enum(default)]` found
--> $DIR/multiple_defaults_different_kinds.rs:7:16
|
7 | #[num_enum(default)]
| ^^^^^^^
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#[derive(num_enum::FromPrimitive, num_enum::TryFromPrimitive)]
#[repr(u8)]
enum Numbers {
Zero,
#[num_enum(default)]
One,
#[num_enum(default)]
Two,
}

fn main() {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: Multiple variants marked `#[default]` or `#[num_enum(default)]` found
--> $DIR/multiple_num_enum_defaults.rs:7:16
|
7 | #[num_enum(default)]
| ^^^^^^^
61 changes: 35 additions & 26 deletions num_enum_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,35 +270,44 @@ impl Parse for EnumInfo {
let mut is_default: bool = false;

for attribute in variant.attrs {
if !attribute.path.is_ident("num_enum") {
continue;
}
match attribute.parse_args_with(NumEnumVariantAttributes::parse) {
Ok(variant_attributes) => {
for variant_attribute in variant_attributes.items.iter() {
match variant_attribute {
NumEnumVariantAttributeItem::Default(default) => {
if has_default_variant {
die!(default.keyword =>
"Multiple variants marked `#[num_enum(default)]` found"
);
if attribute.path.is_ident("default") {
if has_default_variant {
die!(attribute =>
"Multiple variants marked `#[default]` or `#[num_enum(default)]` found"
);
}
attr_spans.default.push(attribute.span());
is_default = true;
} else if attribute.path.is_ident("num_enum") {
match attribute.parse_args_with(NumEnumVariantAttributes::parse) {
Ok(variant_attributes) => {
for variant_attribute in variant_attributes.items.iter() {
match variant_attribute {
NumEnumVariantAttributeItem::Default(default) => {
if has_default_variant {
die!(default.keyword =>
"Multiple variants marked `#[default]` or `#[num_enum(default)]` found"
);
}
attr_spans.default.push(default.span());
is_default = true;
}
NumEnumVariantAttributeItem::Alternatives(alternatives) => {
attr_spans.alternatives.push(alternatives.span());
alternative_values
.extend(alternatives.expressions.iter().cloned());
}
attr_spans.default.push(default.span());
is_default = true;
}
NumEnumVariantAttributeItem::Alternatives(alternatives) => {
attr_spans.alternatives.push(alternatives.span());
alternative_values
.extend(alternatives.expressions.iter().cloned());
}
}
}
Err(err) => {
die!(attribute =>
format!("Invalid attribute: {}", err)
);
}
}
Err(err) => {
die!(attribute =>
format!("Invalid attribute: {}", err)
);
}
} else {
continue;
}

has_default_variant |= is_default;
Expand Down Expand Up @@ -387,7 +396,7 @@ pub fn derive_into_primitive(input: TokenStream) -> TokenStream {
/// let two = Number::from(2u8);
/// assert_eq!(two, Number::NonZero);
/// ```
#[proc_macro_derive(FromPrimitive, attributes(num_enum))]
#[proc_macro_derive(FromPrimitive, attributes(num_enum, default))]
pub fn derive_from_primitive(input: TokenStream) -> TokenStream {
let enum_info: EnumInfo = parse_macro_input!(input);
let krate = Ident::new(&get_crate_name(), Span::call_site());
Expand All @@ -397,7 +406,7 @@ pub fn derive_from_primitive(input: TokenStream) -> TokenStream {
None => {
let span = Span::call_site();
let message =
"#[derive(FromPrimitive)] requires a variant marked with `#[num_enum(default)]`";
"#[derive(FromPrimitive)] requires a variant marked with `#[default]` or `#[num_enum(default)]`";
return syn::Error::new(span, message).to_compile_error().into();
}
};
Expand Down

0 comments on commit 4f4ea0b

Please sign in to comment.