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::{set::MixedEnumSet, 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    /// Converts an enumset to a MixedEnumSet
58    pub const fn convert_mixed<T: crate::EnumSetTypeWithRepr>(a: EnumSet<T>) -> MixedEnumSet<T> {
59        MixedEnumSet { repr: a.repr }
60    }
61
62    /// Gets the underlying repr from an EnumSet
63    #[inline(always)]
64    pub const fn get<T: EnumSetType>(set: EnumSet<T>) -> T::Repr {
65        set.repr
66    }
67
68    /// Constructs an EnumSet from the underlying repr
69    #[inline(always)]
70    pub const fn new<T: EnumSetType>(set: T::Repr) -> EnumSet<T> {
71        EnumSet { repr: set }
72    }
73}
74
75/// Creates an [`EnumSet`](crate::EnumSet) literal, which can be used in const contexts.
76///
77/// The syntax used is `enum_set!(Type::A | Type::B | Type::C)`. Each variant must be of the same
78/// type, or an error will occur at compile-time.
79///
80/// This macro accepts trailing `|`s to allow easier use in other macros.
81///
82/// # Performance
83///
84/// This macro is designed for use in const contexts, not for execution as normal code. It may be
85/// significantly slower than normal code outside const contexts.
86///
87/// In normal code, directly use `Type::A | Type::B | Type::C` instead.
88///
89/// # Examples
90///
91/// ```rust
92/// # use enumset::*;
93/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C }
94/// const CONST_SET: EnumSet<Enum> = enum_set!(Enum::A | Enum::B);
95/// assert_eq!(CONST_SET, Enum::A | Enum::B);
96/// ```
97///
98/// This macro is strongly typed. For example, the following will not compile:
99///
100/// ```compile_fail
101/// # use enumset::*;
102/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C }
103/// # #[derive(EnumSetType, Debug)] enum Enum2 { A, B, C }
104/// let type_error = enum_set!(Enum::A | Enum2::B);
105/// ```
106#[macro_export]
107macro_rules! enum_set {
108    ($(|)*) => {
109        $crate::EnumSet::empty()
110    };
111    ($value:path $(|)*) => {
112        {
113            $crate::__internal::set::init_helper(&$value).const_only($value)
114        }
115    };
116    ($value:path | $($rest:path)|* $(|)*) => {
117        $crate::enum_set_union!($value, $($rest,)*)
118    };
119}
120
121/// Creates a [`MixedEnumSet`](crate::set::MixedEnumSet) literal, which can be used in const
122/// contexts.
123///
124/// The syntax used is `mixed_enum_set!(Type::A | Type::B | Type::C)`. Each variant must be of the same
125/// type, or an error will occur at compile-time.
126///
127/// This macro accepts trailing `|`s to allow easier use in other macros.
128///
129/// # Examples
130///
131/// ```rust
132/// # use enumset::{set::*, *};
133/// # #[derive(EnumSetType, Debug)] #[enumset(repr = "u32")] enum Enum { A, B, C }
134/// const CONST_SET: MixedEnumSet<Enum> = mixed_enum_set!(Enum::A | Enum::B);
135/// assert_eq!(CONST_SET, MixedEnumSet::from(Enum::A | Enum::B));
136/// ```
137///
138/// This macro is strongly typed. For example, the following will not compile:
139///
140/// ```compile_fail
141/// # use enumset::*;
142/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C }
143/// # #[derive(EnumSetType, Debug)] enum Enum2 { A, B, C }
144/// let type_error = enum_set!(Enum::A | Enum2::B);
145/// ```
146#[macro_export]
147macro_rules! mixed_enum_set {
148    ($($internal:tt)*) => {
149        $crate::__internal::set::convert_mixed($crate::enum_set!($($internal)*))
150    };
151}
152
153/// Computes the union of multiple enum variants or const [`EnumSet`](crate::EnumSet) values at
154/// compile time.
155///
156/// The syntax used is `enum_set_union!(ENUM_A, ENUM_B, ENUM_C)`, computing the equivalent of
157/// `ENUM_A | ENUM_B | ENUM_C` at compile time. Each variant must be of the same type, or an error
158/// will occur at compile-time.
159///
160/// # Performance
161///
162/// This macro is designed for use in const contexts, not for execution as normal code. It may be
163/// significantly slower than normal code outside const contexts.
164///
165/// In normal code, directly use the `|` operator instead.
166///
167/// # Examples
168///
169/// ```rust
170/// # use enumset::*;
171/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C }
172/// const CONST_SET: EnumSet<Enum> = enum_set_union!(Enum::A, Enum::B);
173/// assert_eq!(CONST_SET, Enum::A | Enum::B);
174/// ```
175#[macro_export]
176macro_rules! enum_set_union {
177    ($value:path $(,)?) => {
178        $crate::enum_set!($value)
179    };
180    ($value:path, $($rest:path),* $(,)?) => {
181        {
182            let op_helper = $crate::__internal::set::op_helper(&$value);
183            let value = $crate::enum_set!($value);
184            $(let value = {
185                let new = $crate::enum_set!($rest);
186                op_helper.const_union(value, new)
187            };)*
188            value
189        }
190    };
191}
192
193/// Computes the intersection of multiple enum variants or const [`EnumSet`](crate::EnumSet) values at
194/// compile time.
195///
196/// The syntax used is `enum_set_intersection!(ENUM_A, ENUM_B, ENUM_C)`, computing the equivalent
197/// of `ENUM_A & ENUM_B & ENUM_C` at compile time. Each variant must be of the same type, or an
198/// error will occur at compile-time.
199///
200/// # Performance
201///
202/// This macro is designed for use in const contexts, not for execution as normal code. It may be
203/// significantly slower than normal code outside const contexts.
204///
205/// In normal code, directly use the `&` operator instead.
206///
207/// # Examples
208///
209/// ```rust
210/// # use enumset::*;
211/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C, D }
212/// const SET_A: EnumSet<Enum> = enum_set!(Enum::A | Enum::B);
213/// const SET_B: EnumSet<Enum> = enum_set!(Enum::B | Enum::C);
214/// const CONST_SET: EnumSet<Enum> = enum_set_intersection!(SET_A, SET_B);
215/// assert_eq!(CONST_SET, Enum::B);
216/// ```
217#[macro_export]
218macro_rules! enum_set_intersection {
219    ($value:path $(,)?) => {
220        $crate::enum_set!($value)
221    };
222    ($value:path, $($rest:path),* $(,)?) => {
223        {
224            let op_helper = $crate::__internal::set::op_helper(&$value);
225            let value = $crate::enum_set!($value);
226            $(let value = {
227                let new = $crate::enum_set!($rest);
228                op_helper.const_intersection(value, new)
229            };)*
230            value
231        }
232    };
233}
234
235/// Computes the complement of an enum variant or const [`EnumSet`](crate::EnumSet) values at
236/// compile time.
237///
238/// # Performance
239///
240/// This macro is designed for use in const contexts, not for execution as normal code. It may be
241/// significantly slower than normal code outside const contexts.
242///
243/// In normal code, directly use the `!` operator instead.
244///
245/// # Examples
246///
247/// ```rust
248/// # use enumset::*;
249/// #[derive(EnumSetType, Debug)]
250/// enum Enum { A, B, C, D }
251///
252/// const SET: EnumSet<Enum> = enum_set!(Enum::B | Enum::C);
253/// const CONST_SET: EnumSet<Enum> = enum_set_complement!(SET);
254/// assert_eq!(CONST_SET, Enum::A | Enum::D);
255/// ```
256#[macro_export]
257macro_rules! enum_set_complement {
258    ($value:path $(,)?) => {{
259        let op_helper = $crate::__internal::set::op_helper(&$value);
260        let value = $crate::enum_set!($value);
261        op_helper.const_complement(value)
262    }};
263}
264
265/// Computes the difference of multiple enum variants or const [`EnumSet`](crate::EnumSet) values
266/// at compile time.
267///
268/// The syntax used is `enum_set_difference!(ENUM_A, ENUM_B, ENUM_C)`, computing the equivalent
269/// of `ENUM_A - ENUM_B - ENUM_C` at compile time. Each variant must be of the same type, or an
270/// 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_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_intersection(value, op_helper.const_complement(new))
301            };)*
302            value
303        }
304    };
305}
306
307/// Computes the symmetric difference of multiple enum variants or const
308/// [`EnumSet`](crate::EnumSet) values at compile time.
309///
310/// The syntax used is `enum_set_symmetric_difference!(ENUM_A, ENUM_B, ENUM_C)`, computing the
311/// equivalent of `ENUM_A ^ ENUM_B ^ ENUM_C` at compile time. Each variant must be of the same
312/// type, or an error will occur at compile-time.
313///
314/// # Performance
315///
316/// This macro is designed for use in const contexts, not for execution as normal code. It may be
317/// significantly slower than normal code outside const contexts.
318///
319/// In normal code, directly use the `^` operator instead.
320///
321/// # Examples
322///
323/// ```rust
324/// # use enumset::*;
325/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C, D }
326/// const SET_A: EnumSet<Enum> = enum_set!(Enum::A | Enum::B | Enum::D);
327/// const SET_B: EnumSet<Enum> = enum_set!(Enum::B | Enum::C);
328/// const CONST_SET: EnumSet<Enum> = enum_set_symmetric_difference!(SET_A, SET_B);
329/// assert_eq!(CONST_SET, Enum::A | Enum::C | Enum::D);
330/// ```
331#[macro_export]
332macro_rules! enum_set_symmetric_difference {
333    ($value:path $(,)?) => {
334        $crate::enum_set!($value)
335    };
336    ($value:path, $($rest:path),* $(,)?) => {
337        {
338            let op_helper = $crate::__internal::set::op_helper(&$value);
339            let value = $crate::enum_set!($value);
340            $(let value = {
341                let new = $crate::enum_set!($rest);
342                op_helper.const_symmetric_difference(value, new)
343            };)*
344            value
345        }
346    };
347}