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::MixedEnumSet) literal, which can be used in const contexts.
122///
123/// The syntax used is `mixed_enum_set!(Type::A | Type::B | Type::C)`. Each variant must be of the same
124/// type, or an error will occur at compile-time.
125///
126/// This macro accepts trailing `|`s to allow easier use in other macros.
127///
128/// # Examples
129///
130/// ```rust
131/// # use enumset::{set::*, *};
132/// # #[derive(EnumSetType, Debug)] #[enumset(repr = "u32")] enum Enum { A, B, C }
133/// const CONST_SET: MixedEnumSet<Enum> = mixed_enum_set!(Enum::A | Enum::B);
134/// assert_eq!(CONST_SET, MixedEnumSet::from(Enum::A | Enum::B));
135/// ```
136///
137/// This macro is strongly typed. For example, the following will not compile:
138///
139/// ```compile_fail
140/// # use enumset::*;
141/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C }
142/// # #[derive(EnumSetType, Debug)] enum Enum2 { A, B, C }
143/// let type_error = enum_set!(Enum::A | Enum2::B);
144/// ```
145#[macro_export]
146macro_rules! mixed_enum_set {
147 ($($internal:tt)*) => {
148 $crate::__internal::set::convert_mixed($crate::enum_set!($($internal)*))
149 };
150}
151
152/// Computes the union of multiple enum variants or const [`EnumSet`] values at compile time.
153///
154/// The syntax used is `enum_set_union!(ENUM_A, ENUM_B, ENUM_C)`, computing the equivalent of
155/// `ENUM_A | ENUM_B | ENUM_C` at compile time. Each variant must be of the same type, or an error
156/// will occur at compile-time.
157///
158/// # Performance
159///
160/// This macro is designed for use in const contexts, not for execution as normal code. It may be
161/// significantly slower than normal code outside const contexts.
162///
163/// In normal code, directly use the `|` operator instead.
164///
165/// # Examples
166///
167/// ```rust
168/// # use enumset::*;
169/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C }
170/// const CONST_SET: EnumSet<Enum> = enum_set_union!(Enum::A, Enum::B);
171/// assert_eq!(CONST_SET, Enum::A | Enum::B);
172/// ```
173#[macro_export]
174macro_rules! enum_set_union {
175 ($value:path $(,)?) => {
176 $crate::enum_set!($value)
177 };
178 ($value:path, $($rest:path),* $(,)?) => {
179 {
180 let op_helper = $crate::__internal::set::op_helper(&$value);
181 let value = $crate::enum_set!($value);
182 $(let value = {
183 let new = $crate::enum_set!($rest);
184 op_helper.const_union(value, new)
185 };)*
186 value
187 }
188 };
189}
190
191/// Computes the intersection of multiple enum variants or const [`EnumSet`] values at compile time.
192///
193/// The syntax used is `enum_set_intersection!(ENUM_A, ENUM_B, ENUM_C)`, computing the equivalent
194/// of `ENUM_A & ENUM_B & ENUM_C` at compile time. Each variant must be of the same type, or an
195/// error will occur at compile-time.
196///
197/// # Performance
198///
199/// This macro is designed for use in const contexts, not for execution as normal code. It may be
200/// significantly slower than normal code outside const contexts.
201///
202/// In normal code, directly use the `&` operator instead.
203///
204/// # Examples
205///
206/// ```rust
207/// # use enumset::*;
208/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C, D }
209/// const SET_A: EnumSet<Enum> = enum_set!(Enum::A | Enum::B);
210/// const SET_B: EnumSet<Enum> = enum_set!(Enum::B | Enum::C);
211/// const CONST_SET: EnumSet<Enum> = enum_set_intersection!(SET_A, SET_B);
212/// assert_eq!(CONST_SET, Enum::B);
213/// ```
214#[macro_export]
215macro_rules! enum_set_intersection {
216 ($value:path $(,)?) => {
217 $crate::enum_set!($value)
218 };
219 ($value:path, $($rest:path),* $(,)?) => {
220 {
221 let op_helper = $crate::__internal::set::op_helper(&$value);
222 let value = $crate::enum_set!($value);
223 $(let value = {
224 let new = $crate::enum_set!($rest);
225 op_helper.const_intersection(value, new)
226 };)*
227 value
228 }
229 };
230}
231
232/// Computes the complement of an enum variant or const [`EnumSet`] value at compile time.
233///
234/// # Performance
235///
236/// This macro is designed for use in const contexts, not for execution as normal code. It may be
237/// significantly slower than normal code outside const contexts.
238///
239/// In normal code, directly use the `!` operator instead.
240///
241/// # Examples
242///
243/// ```rust
244/// # use enumset::*;
245/// #[derive(EnumSetType, Debug)]
246/// enum Enum { A, B, C, D }
247///
248/// const SET: EnumSet<Enum> = enum_set!(Enum::B | Enum::C);
249/// const CONST_SET: EnumSet<Enum> = enum_set_complement!(SET);
250/// assert_eq!(CONST_SET, Enum::A | Enum::D);
251/// ```
252#[macro_export]
253macro_rules! enum_set_complement {
254 ($value:path $(,)?) => {{
255 let op_helper = $crate::__internal::set::op_helper(&$value);
256 let value = $crate::enum_set!($value);
257 op_helper.const_complement(value)
258 }};
259}
260
261/// Computes the difference of multiple enum variants or const [`EnumSet`] values at compile time.
262///
263/// The syntax used is `enum_set_difference!(ENUM_A, ENUM_B, ENUM_C)`, computing the equivalent
264/// of `ENUM_A - ENUM_B - ENUM_C` at compile time. Each variant must be of the same type, or an
265/// error will occur at compile-time.
266///
267/// # Performance
268///
269/// This macro is designed for use in const contexts, not for execution as normal code. It may be
270/// significantly slower than normal code outside const contexts.
271///
272/// In normal code, directly use the `-` operator instead.
273///
274/// # Examples
275///
276/// ```rust
277/// # use enumset::*;
278/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C, D }
279/// const SET_A: EnumSet<Enum> = EnumSet::all();
280/// const SET_B: EnumSet<Enum> = enum_set!(Enum::B | Enum::C);
281/// const CONST_SET: EnumSet<Enum> = enum_set_difference!(SET_A, SET_B);
282/// assert_eq!(CONST_SET, Enum::A | Enum::D);
283/// ```
284#[macro_export]
285macro_rules! enum_set_difference {
286 ($value:path $(,)?) => {
287 $crate::enum_set!($value)
288 };
289 ($value:path, $($rest:path),* $(,)?) => {
290 {
291 let op_helper = $crate::__internal::set::op_helper(&$value);
292 let value = $crate::enum_set!($value);
293 $(let value = {
294 let new = $crate::enum_set!($rest);
295 op_helper.const_intersection(value, op_helper.const_complement(new))
296 };)*
297 value
298 }
299 };
300}
301
302/// Computes the symmetric difference of multiple enum variants or const [`EnumSet`] values at
303/// compile time.
304///
305/// The syntax used is `enum_set_symmetric_difference!(ENUM_A, ENUM_B, ENUM_C)`, computing the
306/// equivalent of `ENUM_A ^ ENUM_B ^ ENUM_C` at compile time. Each variant must be of the same
307/// type, or an error will occur at compile-time.
308///
309/// # Performance
310///
311/// This macro is designed for use in const contexts, not for execution as normal code. It may be
312/// significantly slower than normal code outside const contexts.
313///
314/// In normal code, directly use the `^` operator instead.
315///
316/// # Examples
317///
318/// ```rust
319/// # use enumset::*;
320/// # #[derive(EnumSetType, Debug)] enum Enum { A, B, C, D }
321/// const SET_A: EnumSet<Enum> = enum_set!(Enum::A | Enum::B | Enum::D);
322/// const SET_B: EnumSet<Enum> = enum_set!(Enum::B | Enum::C);
323/// const CONST_SET: EnumSet<Enum> = enum_set_symmetric_difference!(SET_A, SET_B);
324/// assert_eq!(CONST_SET, Enum::A | Enum::C | Enum::D);
325/// ```
326#[macro_export]
327macro_rules! enum_set_symmetric_difference {
328 ($value:path $(,)?) => {
329 $crate::enum_set!($value)
330 };
331 ($value:path, $($rest:path),* $(,)?) => {
332 {
333 let op_helper = $crate::__internal::set::op_helper(&$value);
334 let value = $crate::enum_set!($value);
335 $(let value = {
336 let new = $crate::enum_set!($rest);
337 op_helper.const_symmetric_difference(value, new)
338 };)*
339 value
340 }
341 };
342}