Skip to main content

enumset/
macros.rs

1/// Everything in this module is internal API and may change at any time.
2#[doc(hidden)]
3pub mod __internal {
4    /// A reexport of core to allow our macros to be generic to std vs core.
5    pub use ::core as core_export;
6
7    /// A reexport of serde so our users don't have to also have a serde dependency.
8    #[cfg(feature = "serde")]
9    pub use serde;
10
11    /// Reexports of internal types
12    pub use crate::{
13        repr::{ArrayRepr, EnumSetTypeRepr},
14        traits::{EnumSetConstHelper, EnumSetTypePrivate},
15    };
16
17    #[cfg(feature = "serde")]
18    #[doc(hidden)]
19    #[macro_export]
20    macro_rules! __if_serde {
21        ($($tt:tt)*) => {
22            $($tt)*
23        };
24    }
25
26    #[cfg(not(feature = "serde"))]
27    #[doc(hidden)]
28    #[macro_export]
29    macro_rules! __if_serde {
30        ($($tt:tt)*) => {};
31    }
32
33    /// Macro to wrap serde-related code generated by the derive, discarding it
34    /// if serde support is not enabled.
35    pub use __if_serde;
36
37    pub use crate::macros::set;
38}
39
40/// Helper functions for sets.
41pub mod set {
42    use crate::__internal::EnumSetConstHelper;
43    use crate::{EnumSet, EnumSetType};
44
45    /// Retrieves the helper used in constant time operations.
46    #[inline(always)]
47    pub const fn op_helper<T: EnumSetConstHelper>(_: &T) -> T::ConstOpHelper {
48        T::CONST_OP_HELPER
49    }
50
51    /// Retrieves the helper used in constant time conversions.
52    #[inline(always)]
53    pub const fn init_helper<T: EnumSetConstHelper>(_: &T) -> T::ConstInitHelper {
54        T::CONST_INIT_HELPER
55    }
56
57    /// Gets the underlying repr from an EnumSet
58    #[inline(always)]
59    pub const fn get<T: EnumSetType>(set: EnumSet<T>) -> T::Repr {
60        set.repr
61    }
62
63    /// Constructs an EnumSet from the underlying repr
64    #[inline(always)]
65    pub const fn new<T: EnumSetType>(set: T::Repr) -> EnumSet<T> {
66        EnumSet { repr: set }
67    }
68}
69
70/// Creates a EnumSet literal, which can be used in const contexts.
71///
72/// The syntax used is `enum_set!(Type::A | Type::B | Type::C)`. Each variant must be of the same
73/// type, or an error will occur at compile-time.
74///
75/// This macro accepts trailing `|`s to allow easier use in other macros.
76///
77/// # Performance
78///
79/// This macro is designed for use in const contexts, not for execution as normal code. It may be
80/// significantly slower than normal code outside const contexts.
81///
82/// In normal code, directly use `Type::A | Type::B | Type::C` instead.
83///
84/// # Examples
85///
86/// ```rust
87/// # use enumset::*;
88/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C }
89/// const CONST_SET: EnumSet<Enum> = enum_set!(Enum::A | Enum::B);
90/// assert_eq!(CONST_SET, Enum::A | Enum::B);
91/// ```
92///
93/// This macro is strongly typed. For example, the following will not compile:
94///
95/// ```compile_fail
96/// # use enumset::*;
97/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C }
98/// # #[derive(EnumSetType, Debug)] enum Enum2 { A, B, C }
99/// let type_error = enum_set!(Enum::A | Enum2::B);
100/// ```
101#[macro_export]
102macro_rules! enum_set {
103    ($(|)*) => {
104        $crate::EnumSet::empty()
105    };
106    ($value:path $(|)*) => {
107        {
108            $crate::__internal::set::init_helper(&$value).const_only($value)
109        }
110    };
111    ($value:path | $($rest:path)|* $(|)*) => {
112        $crate::enum_set_union!($value, $($rest,)*)
113    };
114}
115
116/// Computes the union of multiple enums or constants enumset at compile time.
117///
118/// The syntax used is `enum_set_union!(ENUM_A, ENUM_B, ENUM_C)`, computing the equivalent of
119/// `ENUM_A | ENUM_B | ENUM_C` at compile time. Each variant must be of the same type, or an error
120/// will occur at compile-time.
121///
122/// # Performance
123///
124/// This macro is designed for use in const contexts, not for execution as normal code. It may be
125/// significantly slower than normal code outside const contexts.
126///
127/// In normal code, directly use the `|` operator instead.
128///
129/// # Examples
130///
131/// ```rust
132/// # use enumset::*;
133/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C }
134/// const CONST_SET: EnumSet<Enum> = enum_set_union!(Enum::A, Enum::B);
135/// assert_eq!(CONST_SET, Enum::A | Enum::B);
136/// ```
137#[macro_export]
138macro_rules! enum_set_union {
139    ($value:path $(,)?) => {
140        $crate::enum_set!($value)
141    };
142    ($value:path, $($rest:path),* $(,)?) => {
143        {
144            let op_helper = $crate::__internal::set::op_helper(&$value);
145            let value = $crate::enum_set!($value);
146            $(let value = {
147                let new = $crate::enum_set!($rest);
148                op_helper.const_union(value, new)
149            };)*
150            value
151        }
152    };
153}
154
155/// Computes the intersection of multiple enums or constants enumset at compile time.
156///
157/// The syntax used is `enum_set_intersection!(ENUM_A, ENUM_B, ENUM_C)`, computing the equivalent
158/// of `ENUM_A & ENUM_B & ENUM_C` at compile time. Each variant must be of the same type, or an
159/// error will occur at compile-time.
160///
161/// # Performance
162///
163/// This macro is designed for use in const contexts, not for execution as normal code. It may be
164/// significantly slower than normal code outside const contexts.
165///
166/// In normal code, directly use the `&` operator instead.
167///
168/// # Examples
169///
170/// ```rust
171/// # use enumset::*;
172/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C, D }
173/// const SET_A: EnumSet<Enum> = enum_set!(Enum::A | Enum::B);
174/// const SET_B: EnumSet<Enum> = enum_set!(Enum::B | Enum::C);
175/// const CONST_SET: EnumSet<Enum> = enum_set_intersection!(SET_A, SET_B);
176/// assert_eq!(CONST_SET, Enum::B);
177/// ```
178#[macro_export]
179macro_rules! enum_set_intersection {
180    ($value:path $(,)?) => {
181        $crate::enum_set!($value)
182    };
183    ($value:path, $($rest:path),* $(,)?) => {
184        {
185            let op_helper = $crate::__internal::set::op_helper(&$value);
186            let value = $crate::enum_set!($value);
187            $(let value = {
188                let new = $crate::enum_set!($rest);
189                op_helper.const_intersection(value, new)
190            };)*
191            value
192        }
193    };
194}
195
196/// Computes the complement of an enums or constants enumset at compile time.
197///
198/// # Performance
199///
200/// This macro is designed for use in const contexts, not for execution as normal code. It may be
201/// significantly slower than normal code outside const contexts.
202///
203/// In normal code, directly use the `!` operator instead.
204///
205/// # Examples
206///
207/// ```rust
208/// # use enumset::*;
209/// #[derive(EnumSetType, Debug)]
210/// enum Enum { A, B, C, D }
211///
212/// const SET: EnumSet<Enum> = enum_set!(Enum::B | Enum::C);
213/// const CONST_SET: EnumSet<Enum> = enum_set_complement!(SET);
214/// assert_eq!(CONST_SET, Enum::A | Enum::D);
215/// ```
216#[macro_export]
217macro_rules! enum_set_complement {
218    ($value:path $(,)?) => {{
219        let op_helper = $crate::__internal::set::op_helper(&$value);
220        let value = $crate::enum_set!($value);
221        op_helper.const_complement(value)
222    }};
223}
224
225/// Computes the difference of multiple enums or constants enumset at compile time.
226///
227/// The syntax used is `enum_set_difference!(ENUM_A, ENUM_B, ENUM_C)`, computing the equivalent
228/// of `ENUM_A - ENUM_B - ENUM_C` at compile time. Each variant must be of the same type, or an
229/// error will occur at compile-time.
230///
231/// # Performance
232///
233/// This macro is designed for use in const contexts, not for execution as normal code. It may be
234/// significantly slower than normal code outside const contexts.
235///
236/// In normal code, directly use the `-` operator instead.
237///
238/// # Examples
239///
240/// ```rust
241/// # use enumset::*;
242/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C, D }
243/// const SET_A: EnumSet<Enum> = enum_set!(Enum::A | Enum::B | Enum::D);
244/// const SET_B: EnumSet<Enum> = enum_set!(Enum::B | Enum::C);
245/// const CONST_SET: EnumSet<Enum> = enum_set_symmetric_difference!(SET_A, SET_B);
246/// assert_eq!(CONST_SET, Enum::A | Enum::C | Enum::D);
247/// ```
248#[macro_export]
249macro_rules! enum_set_difference {
250    ($value:path $(,)?) => {
251        $crate::enum_set!($value)
252    };
253    ($value:path, $($rest:path),* $(,)?) => {
254        {
255            let op_helper = $crate::__internal::set::op_helper(&$value);
256            let value = $crate::enum_set!($value);
257            $(let value = {
258                let new = $crate::enum_set!($rest);
259                op_helper.const_intersection(value, op_helper.const_complement(new))
260            };)*
261            value
262        }
263    };
264}
265
266/// Computes the symmetric difference of multiple enums or constants enumset at compile time.
267///
268/// The syntax used is `enum_set_symmetric_difference!(ENUM_A, ENUM_B, ENUM_C)`, computing the
269/// equivalent of `ENUM_A ^ ENUM_B ^ ENUM_C` at compile time. Each variant must be of the same
270/// type, or an error will occur at compile-time.
271///
272/// # Performance
273///
274/// This macro is designed for use in const contexts, not for execution as normal code. It may be
275/// significantly slower than normal code outside const contexts.
276///
277/// In normal code, directly use the `^` operator instead.
278///
279/// # Examples
280///
281/// ```rust
282/// # use enumset::*;
283/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C, D }
284/// const SET_A: EnumSet<Enum> = EnumSet::all();
285/// const SET_B: EnumSet<Enum> = enum_set!(Enum::B | Enum::C);
286/// const CONST_SET: EnumSet<Enum> = enum_set_difference!(SET_A, SET_B);
287/// assert_eq!(CONST_SET, Enum::A | Enum::D);
288/// ```
289#[macro_export]
290macro_rules! enum_set_symmetric_difference {
291    ($value:path $(,)?) => {
292        $crate::enum_set!($value)
293    };
294    ($value:path, $($rest:path),* $(,)?) => {
295        {
296            let op_helper = $crate::__internal::set::op_helper(&$value);
297            let value = $crate::enum_set!($value);
298            $(let value = {
299                let new = $crate::enum_set!($rest);
300                op_helper.const_symmetric_difference(value, new)
301            };)*
302            value
303        }
304    };
305}