Skip to content

Commit 88ce96f

Browse files
add ConstDefault
1 parent 5ac2ed7 commit 88ce96f

File tree

3 files changed

+83
-2
lines changed

3 files changed

+83
-2
lines changed

num_enum/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
#![cfg_attr(not(feature = "std"), no_std)]
99

1010
pub use ::num_enum_derive::{
11-
ConstFromPrimitive, ConstIntoPrimitive, ConstTryFromPrimitive, Default, FromPrimitive,
12-
IntoPrimitive, TryFromPrimitive, UnsafeFromPrimitive,
11+
ConstDefault, ConstFromPrimitive, ConstIntoPrimitive, ConstTryFromPrimitive, Default,
12+
FromPrimitive, IntoPrimitive, TryFromPrimitive, UnsafeFromPrimitive,
1313
};
1414

1515
use ::core::fmt;

num_enum/tests/const_default.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#![allow(non_upper_case_globals)]
2+
3+
// Guard against https://github.com/illicitonion/num_enum/issues/27
4+
mod alloc {}
5+
mod core {}
6+
mod num_enum {}
7+
mod std {}
8+
9+
#[test]
10+
fn default() {
11+
#[derive(Debug, Eq, PartialEq, ::num_enum::ConstDefault)]
12+
#[repr(u8)]
13+
enum Enum {
14+
#[allow(unused)]
15+
Zero = 0,
16+
#[num_enum(default)]
17+
NonZero = 1,
18+
}
19+
20+
const nz: Enum = Enum::const_default();
21+
assert_eq!(Enum::NonZero, nz);
22+
}
23+
24+
#[test]
25+
fn default_standard_default_attribute() {
26+
#[derive(Debug, Eq, PartialEq, ::num_enum::ConstDefault)]
27+
#[repr(u8)]
28+
enum Enum {
29+
#[allow(unused)]
30+
Zero = 0,
31+
#[default]
32+
NonZero = 1,
33+
}
34+
35+
const nz: Enum = Enum::const_default();
36+
assert_eq!(Enum::NonZero, nz);
37+
}

num_enum_derive/src/lib.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,3 +588,47 @@ pub fn derive_default(stream: TokenStream) -> TokenStream {
588588
}
589589
})
590590
}
591+
592+
/// Generates a `const_default() -> Self` method to obtain the default enum value in const contexts.
593+
///
594+
/// Whichever variant has the `#[default]` or `#[num_enum(default)]` attribute will be returned.
595+
/// ----------------------------------------------
596+
///
597+
/// ```rust
598+
/// #[derive(Debug, Eq, PartialEq, num_enum::ConstDefault)]
599+
/// #[repr(u8)]
600+
/// enum Number {
601+
/// Zero,
602+
/// #[default]
603+
/// One,
604+
/// }
605+
///
606+
/// const one: Number = Number::const_default();
607+
/// assert_eq!(one, Number::One);
608+
/// assert_eq!(Number::One, Number::const_default());
609+
/// ```
610+
#[proc_macro_derive(ConstDefault, attributes(num_enum, default))]
611+
pub fn derive_const_default(stream: TokenStream) -> TokenStream {
612+
let enum_info = parse_macro_input!(stream as EnumInfo);
613+
614+
let default_ident = match enum_info.default() {
615+
Some(ident) => ident,
616+
None => {
617+
let span = Span::call_site();
618+
let message =
619+
"#[derive(num_enum::ConstDefault)] requires enum to be exhaustive, or a variant marked with `#[default]` or `#[num_enum(default)]`";
620+
return syn::Error::new(span, message).to_compile_error().into();
621+
}
622+
};
623+
624+
let EnumInfo { ref name, .. } = enum_info;
625+
626+
TokenStream::from(quote! {
627+
impl #name {
628+
#[inline]
629+
pub const fn const_default() -> Self {
630+
Self::#default_ident
631+
}
632+
}
633+
})
634+
}

0 commit comments

Comments
 (0)