From 52589af6bc4ff00a6a5b9011d4716fa7a9bc30d3 Mon Sep 17 00:00:00 2001 From: Lymia Aluysia Date: Mon, 6 Apr 2020 05:54:15 -0700 Subject: [PATCH] Use const fns for enum_set! instead of a weird hack. --- enumset/src/lib.rs | 26 ++++++++++++-------------- enumset_derive/src/lib.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/enumset/src/lib.rs b/enumset/src/lib.rs index 9c5bb46..c22d434 100644 --- a/enumset/src/lib.rs +++ b/enumset/src/lib.rs @@ -91,12 +91,6 @@ use num_traits::*; pub mod __internal { use super::*; - /// A struct used to type check [`enum_set!`]. - pub struct EnumSetSameTypeHack<'a, T: EnumSetType + 'static> { - pub unified: &'a [T], - pub enum_set: EnumSet, - } - /// A reexport of core to allow our macros to be generic to std vs core. pub use ::core as core_export; @@ -682,6 +676,8 @@ impl FromIterator> for EnumSet { /// The syntax used is `enum_set!(Type::A | Type::B | Type::C)`. Each variant must be of the same /// type, or a error will occur at compile-time. /// +/// This macro accepts trailing `|`s to allow easier use in other macros. +/// /// # Examples /// /// ```rust @@ -701,15 +697,17 @@ impl FromIterator> for EnumSet { /// ``` #[macro_export] macro_rules! enum_set { - () => { + ($(|)*) => { $crate::EnumSet { __enumset_underlying: 0 } }; - ($($value:path)|* $(|)*) => { - $crate::__internal::EnumSetSameTypeHack { - unified: &[$($value,)*], - enum_set: $crate::EnumSet { - __enumset_underlying: 0 $(| (1 << ($value as u32)))* - }, - }.enum_set + ($value:path $(|)*) => { + $value.__impl_enumset_internal__const_only() + }; + ($value:path | $($rest:path)|* $(|)*) => { + { + #[allow(deprecated)] let value = $value.__impl_enumset_internal__const_only(); + $(#[allow(deprecated)] let value = $rest.__impl_enumset_internal__const_merge(value);)* + value + } }; } diff --git a/enumset_derive/src/lib.rs b/enumset_derive/src/lib.rs index 83ac138..3dc9a45 100644 --- a/enumset_derive/src/lib.rs +++ b/enumset_derive/src/lib.rs @@ -432,6 +432,13 @@ fn enum_set_type_impl(info: EnumSetInfo) -> SynTokenStream { quote!((*self as u32) == (*other as u32)) }; + // used in the enum_set! macro `const fn`s. + let self_as_repr_mask = if is_uninhabited { + quote! { 0 } // impossible anyway + } else { + quote! { 1 << self as #repr } + }; + quote! { unsafe impl #enumset::__internal::EnumSetTypePrivate for #name { type Repr = #repr; @@ -455,6 +462,28 @@ fn enum_set_type_impl(info: EnumSetInfo) -> SynTokenStream { } impl #core::marker::Copy for #name { } + impl #name { + /// Creates a new enumset with only this variant. + #[deprecated(note = "This method is an internal implementation detail generated by \ + the `enumset` crate's procedural macro. It should not be used \ + directly. Use `EnumSet::only` instead.")] + #[doc(hidden)] + pub const fn __impl_enumset_internal__const_only(self) -> EnumSet<#name> { + EnumSet { __enumset_underlying: #self_as_repr_mask } + } + + /// Creates a new enumset with this variant added. + #[deprecated(note = "This method is an internal implementation detail generated by \ + the `enumset` crate's procedural macro. It should not be used \ + directly. Use the `|` operator instead.")] + #[doc(hidden)] + pub const fn __impl_enumset_internal__const_merge( + self, chain: EnumSet<#name>, + ) -> EnumSet<#name> { + EnumSet { __enumset_underlying: chain.__enumset_underlying | #self_as_repr_mask } + } + } + #ops } } -- 2.44.0