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}