]> git.lizzy.rs Git - enumset.git/commitdiff
Use const fns for enum_set! instead of a weird hack.
authorLymia Aluysia <lymia@lymiahugs.com>
Mon, 6 Apr 2020 12:54:15 +0000 (05:54 -0700)
committerLymia Aluysia <lymia@lymiahugs.com>
Mon, 6 Apr 2020 12:54:15 +0000 (05:54 -0700)
enumset/src/lib.rs
enumset_derive/src/lib.rs

index 9c5bb464bcbe6a43da3475aafaa16224d2bc39c2..c22d434b9474bb1adbec421d271acfe8c949e40d 100644 (file)
@@ -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<T>,
-    }
-
     /// 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<T: EnumSetType> FromIterator<EnumSet<T>> for EnumSet<T> {
 /// 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<T: EnumSetType> FromIterator<EnumSet<T>> for EnumSet<T> {
 /// ```
 #[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
+        }
     };
 }
index 83ac1381cf89f0d44331bc42689bb53ba5a6a82c..3dc9a451772afcb9ff202c964892ae296cbba2e4 100644 (file)
@@ -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
     }
 }