/rust/registry/src/index.crates.io-1949cf8c6b5b557f/enumset-1.1.2/src/set.rs
Line | Count | Source |
1 | | use crate::repr::EnumSetTypeRepr; |
2 | | use crate::traits::EnumSetType; |
3 | | use crate::EnumSetTypeWithRepr; |
4 | | use core::cmp::Ordering; |
5 | | use core::fmt::{Debug, Formatter}; |
6 | | use core::hash::{Hash, Hasher}; |
7 | | use core::iter::Sum; |
8 | | use core::ops::{ |
9 | | BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Sub, SubAssign, |
10 | | }; |
11 | | |
12 | | #[cfg(feature = "serde")] |
13 | | use { |
14 | | serde2 as serde, |
15 | | serde2::{Deserialize, Serialize}, |
16 | | }; |
17 | | |
18 | | /// An efficient set type for enums. |
19 | | /// |
20 | | /// It is implemented using a bitset stored using the smallest integer that can fit all bits |
21 | | /// in the underlying enum. In general, an enum variant with a discriminator of `n` is stored in |
22 | | /// the nth least significant bit (corresponding with a mask of, e.g. `1 << enum as u32`). |
23 | | /// |
24 | | /// # Numeric representation |
25 | | /// |
26 | | /// `EnumSet` is internally implemented using integer types, and as such can be easily converted |
27 | | /// from and to numbers. |
28 | | /// |
29 | | /// Each bit of the underlying integer corresponds to at most one particular enum variant. If the |
30 | | /// corresponding bit for a variant is set, it present in the set. Bits that do not correspond to |
31 | | /// any variant are always unset. |
32 | | /// |
33 | | /// By default, each enum variant is stored in a bit corresponding to its discriminator. An enum |
34 | | /// variant with a discriminator of `n` is stored in the `n + 1`th least significant bit |
35 | | /// (corresponding to a mask of e.g. `1 << enum as u32`). |
36 | | /// |
37 | | /// # Array representation |
38 | | /// |
39 | | /// Sets with more than 128 variants are instead stored with an underlying array of `u64`s. This |
40 | | /// is treated as if it was a single large integer. The `n`th least significant bit of this integer |
41 | | /// is stored in the `n % 64`th least significant bit of the `n / 64`th element in the array. |
42 | | /// |
43 | | /// # Serialization |
44 | | /// |
45 | | /// When the `serde` feature is enabled, `EnumSet`s can be serialized and deserialized using |
46 | | /// the `serde` crate. The exact serialization format can be controlled with additional attributes |
47 | | /// on the enum type. These attributes are valid regardless of whether the `serde` feature |
48 | | /// is enabled. |
49 | | /// |
50 | | /// By default, `EnumSet` is serialized by directly writing out a single integer containing the |
51 | | /// numeric representation of the bitset. The integer type used is the smallest one that can fit |
52 | | /// the largest variant in the enum. If no integer type is large enough, instead the `EnumSet` is |
53 | | /// serialized as an array of `u64`s containing the array representation. |
54 | | /// |
55 | | /// The `#[enumset(serialize_repr = "…")]` attribute can be used to override the representation |
56 | | /// used. Valid values are as follows: |
57 | | /// |
58 | | /// * `u8`, `u16`, `u32`, `u64`, and `u128` serialize the type as the corresponding integer type. |
59 | | /// * `array` serializes the set as an list of `u64`s corresponding to the array representation. |
60 | | /// * `list` serializes the set as a list of enum variants. This requires your enum type implement |
61 | | /// [`Serialize`] and [`Deserialize`]. |
62 | | /// * `map` serializes the set as a map of enum variants to booleans. The set contains a value if |
63 | | /// the boolean is `true`. This requires your enum type implement `Serialize` and `Deserialize`. |
64 | | /// |
65 | | /// The representation used is determined statically at compile time, and there is currently no |
66 | | /// support for reading different formats with the same deserializer. |
67 | | /// |
68 | | /// By default, unknown bits are ignored and silently removed from the bitset. To override this |
69 | | /// behavior, you can add a `#[enumset(serialize_deny_unknown)]` attribute. This will cause |
70 | | /// deserialization to fail if an invalid bit is set. |
71 | | /// |
72 | | /// # FFI, Safety and `repr` |
73 | | /// |
74 | | /// If an enum type `T` is annotated with |
75 | | /// [`#[enumset(repr = "…")]`](derive@crate::EnumSetType#options) where `…` is a primitive integer |
76 | | /// type, then several things happen: |
77 | | /// |
78 | | /// * `T` will implement |
79 | | /// <code>[EnumSetTypeWithRepr](crate::traits::EnumSetTypeWithRepr)<Repr = R></code> in |
80 | | /// addition to [`EnumSetType`]. |
81 | | /// * The `EnumSet` methods with `repr` in their name, such as [`as_repr`][EnumSet::as_repr] and |
82 | | /// [`from_repr`][EnumSet::from_repr], will be available for `EnumSet<T>`. |
83 | | /// * The in-memory representation of `EnumSet<T>` is guaranteed to be `R`. |
84 | | /// |
85 | | /// That last guarantee makes it sound to send `EnumSet<T>` across an FFI boundary. For example: |
86 | | /// |
87 | | /// ``` |
88 | | /// # use enumset::*; |
89 | | /// # |
90 | | /// # mod ffi_impl { |
91 | | /// # // This example “foreign” function is actually written in Rust, but for the sake |
92 | | /// # // of example, we'll pretend it's written in C. |
93 | | /// # #[no_mangle] |
94 | | /// # extern "C" fn some_foreign_function(set: u32) -> u32 { |
95 | | /// # set & 0b100 |
96 | | /// # } |
97 | | /// # } |
98 | | /// # |
99 | | /// extern "C" { |
100 | | /// // This function is written in C like: |
101 | | /// // uint32_t some_foreign_function(uint32_t set) { … } |
102 | | /// fn some_foreign_function(set: EnumSet<MyEnum>) -> EnumSet<MyEnum>; |
103 | | /// } |
104 | | /// |
105 | | /// #[derive(Debug, EnumSetType)] |
106 | | /// #[enumset(repr = "u32")] |
107 | | /// enum MyEnum { A, B, C } |
108 | | /// |
109 | | /// let set: EnumSet<MyEnum> = enum_set!(MyEnum::A | MyEnum::C); |
110 | | /// |
111 | | /// let new_set: EnumSet<MyEnum> = unsafe { some_foreign_function(set) }; |
112 | | /// assert_eq!(new_set, enum_set!(MyEnum::C)); |
113 | | /// ``` |
114 | | /// |
115 | | /// When an `EnumSet<T>` is received via FFI, all bits that don't correspond to an enum variant |
116 | | /// of `T` must be set to `0`. Behavior is **undefined** if any of these bits are set to `1`. |
117 | | #[cfg_attr( |
118 | | not(feature = "serde"), |
119 | | doc = "\n\n", |
120 | | doc = "[`Serialize`]: https://docs.rs/serde/latest/serde/trait.Serialize.html\n", |
121 | | doc = "[`Deserialize`]: https://docs.rs/serde/latest/serde/trait.Deserialize.html\n" |
122 | | )] |
123 | | #[derive(Copy, Clone, PartialEq, Eq)] |
124 | | #[repr(transparent)] |
125 | | pub struct EnumSet<T: EnumSetType> { |
126 | | #[doc(hidden)] |
127 | | /// This is public due to the `enum_set!` macro. |
128 | | /// This is **NOT** public API and may change at any time. |
129 | | pub __priv_repr: T::Repr, |
130 | | } |
131 | | |
132 | | //region EnumSet operations |
133 | | impl<T: EnumSetType> EnumSet<T> { |
134 | | /// An empty `EnumSet`. |
135 | | /// |
136 | | /// This is available as a constant for use in constant expressions. |
137 | | pub const EMPTY: Self = EnumSet { __priv_repr: T::Repr::EMPTY }; |
138 | | |
139 | | /// An `EnumSet` containing all valid variants of the enum. |
140 | | /// |
141 | | /// This is available as a constant for use in constant expressions. |
142 | | pub const ALL: Self = EnumSet { __priv_repr: T::ALL_BITS }; |
143 | | |
144 | | /// Creates an empty `EnumSet`. |
145 | | #[inline(always)] |
146 | 442 | pub fn new() -> Self { |
147 | 442 | Self::EMPTY |
148 | 442 | } Unexecuted instantiation: <enumset::set::EnumSet<neqo_http3::headers_checks::PseudoHeaderState>>::new <enumset::set::EnumSet<neqo_transport::tracking::PacketNumberSpace>>::new Line | Count | Source | 146 | 442 | pub fn new() -> Self { | 147 | 442 | Self::EMPTY | 148 | 442 | } |
|
149 | | |
150 | | /// Returns an `EnumSet` containing a single element. |
151 | | #[inline(always)] |
152 | 0 | pub fn only(t: T) -> Self { |
153 | 0 | let mut set = Self::new(); |
154 | 0 | set.insert(t); |
155 | 0 | set |
156 | 0 | } Unexecuted instantiation: <enumset::set::EnumSet<neqo_http3::headers_checks::PseudoHeaderState>>::only Unexecuted instantiation: <enumset::set::EnumSet<neqo_transport::tracking::PacketNumberSpace>>::only |
157 | | |
158 | | /// Creates an empty `EnumSet`. |
159 | | /// |
160 | | /// This is an alias for [`EnumSet::new`]. |
161 | | #[inline(always)] |
162 | 1.69k | pub fn empty() -> Self { |
163 | 1.69k | Self::EMPTY |
164 | 1.69k | } Unexecuted instantiation: <enumset::set::EnumSet<neqo_http3::headers_checks::PseudoHeaderState>>::empty <enumset::set::EnumSet<neqo_transport::tracking::PacketNumberSpace>>::empty Line | Count | Source | 162 | 1.69k | pub fn empty() -> Self { | 163 | 1.69k | Self::EMPTY | 164 | 1.69k | } |
|
165 | | |
166 | | /// Returns an `EnumSet` containing all valid variants of the enum. |
167 | | #[inline(always)] |
168 | 0 | pub fn all() -> Self { |
169 | 0 | Self::ALL |
170 | 0 | } |
171 | | |
172 | | /// Total number of bits used by this type. Note that the actual amount of space used is |
173 | | /// rounded up to the next highest integer type (`u8`, `u16`, `u32`, `u64`, or `u128`). |
174 | | /// |
175 | | /// This is the same as [`EnumSet::variant_count`] except in enums with "sparse" variants. |
176 | | /// (e.g. `enum Foo { A = 10, B = 20 }`) |
177 | | #[inline(always)] |
178 | | pub fn bit_width() -> u32 { |
179 | | T::BIT_WIDTH |
180 | | } |
181 | | |
182 | | /// The number of valid variants that this type can contain. |
183 | | /// |
184 | | /// This is the same as [`EnumSet::bit_width`] except in enums with "sparse" variants. |
185 | | /// (e.g. `enum Foo { A = 10, B = 20 }`) |
186 | | #[inline(always)] |
187 | | pub fn variant_count() -> u32 { |
188 | | T::VARIANT_COUNT |
189 | | } |
190 | | |
191 | | /// Returns the number of elements in this set. |
192 | | #[inline(always)] |
193 | | pub fn len(&self) -> usize { |
194 | | self.__priv_repr.count_ones() as usize |
195 | | } |
196 | | /// Returns `true` if the set contains no elements. |
197 | | #[inline(always)] |
198 | | pub fn is_empty(&self) -> bool { |
199 | | self.__priv_repr.is_empty() |
200 | | } |
201 | | /// Removes all elements from the set. |
202 | | #[inline(always)] |
203 | | pub fn clear(&mut self) { |
204 | | self.__priv_repr = T::Repr::EMPTY; |
205 | | } |
206 | | |
207 | | /// Returns `true` if `self` has no elements in common with `other`. This is equivalent to |
208 | | /// checking for an empty intersection. |
209 | | #[inline(always)] |
210 | | pub fn is_disjoint(&self, other: Self) -> bool { |
211 | | (*self & other).is_empty() |
212 | | } |
213 | | /// Returns `true` if the set is a superset of another, i.e., `self` contains at least all the |
214 | | /// values in `other`. |
215 | | #[inline(always)] |
216 | | pub fn is_superset(&self, other: Self) -> bool { |
217 | | (*self & other).__priv_repr == other.__priv_repr |
218 | | } |
219 | | /// Returns `true` if the set is a subset of another, i.e., `other` contains at least all |
220 | | /// the values in `self`. |
221 | | #[inline(always)] |
222 | | pub fn is_subset(&self, other: Self) -> bool { |
223 | | other.is_superset(*self) |
224 | | } |
225 | | |
226 | | /// Returns a set containing any elements present in either set. |
227 | | #[inline(always)] |
228 | 0 | pub fn union(&self, other: Self) -> Self { |
229 | 0 | EnumSet { __priv_repr: self.__priv_repr | other.__priv_repr } |
230 | 0 | } Unexecuted instantiation: <enumset::set::EnumSet<neqo_http3::headers_checks::PseudoHeaderState>>::union Unexecuted instantiation: <enumset::set::EnumSet<neqo_transport::tracking::PacketNumberSpace>>::union |
231 | | /// Returns a set containing every element present in both sets. |
232 | | #[inline(always)] |
233 | 0 | pub fn intersection(&self, other: Self) -> Self { |
234 | 0 | EnumSet { __priv_repr: self.__priv_repr & other.__priv_repr } |
235 | 0 | } |
236 | | /// Returns a set containing element present in `self` but not in `other`. |
237 | | #[inline(always)] |
238 | 0 | pub fn difference(&self, other: Self) -> Self { |
239 | 0 | EnumSet { __priv_repr: self.__priv_repr.and_not(other.__priv_repr) } |
240 | 0 | } |
241 | | /// Returns a set containing every element present in either `self` or `other`, but is not |
242 | | /// present in both. |
243 | | #[inline(always)] |
244 | | pub fn symmetrical_difference(&self, other: Self) -> Self { |
245 | | EnumSet { __priv_repr: self.__priv_repr ^ other.__priv_repr } |
246 | | } |
247 | | /// Returns a set containing all enum variants not in this set. |
248 | | #[inline(always)] |
249 | 0 | pub fn complement(&self) -> Self { |
250 | 0 | EnumSet { __priv_repr: !self.__priv_repr & T::ALL_BITS } |
251 | 0 | } Unexecuted instantiation: <enumset::set::EnumSet<neqo_http3::headers_checks::PseudoHeaderState>>::complement Unexecuted instantiation: <enumset::set::EnumSet<neqo_transport::tracking::PacketNumberSpace>>::complement |
252 | | |
253 | | /// Checks whether this set contains a value. |
254 | | #[inline(always)] |
255 | 2.57k | pub fn contains(&self, value: T) -> bool { |
256 | 2.57k | self.__priv_repr.has_bit(value.enum_into_u32()) |
257 | 2.57k | } Unexecuted instantiation: <enumset::set::EnumSet<neqo_http3::headers_checks::PseudoHeaderState>>::contains <enumset::set::EnumSet<neqo_transport::tracking::PacketNumberSpace>>::contains Line | Count | Source | 255 | 2.57k | pub fn contains(&self, value: T) -> bool { | 256 | 2.57k | self.__priv_repr.has_bit(value.enum_into_u32()) | 257 | 2.57k | } |
|
258 | | |
259 | | /// Adds a value to this set. |
260 | | /// |
261 | | /// If the set did not have this value present, `true` is returned. |
262 | | /// |
263 | | /// If the set did have this value present, `false` is returned. |
264 | | #[inline(always)] |
265 | 0 | pub fn insert(&mut self, value: T) -> bool { |
266 | 0 | let contains = !self.contains(value); |
267 | 0 | self.__priv_repr.add_bit(value.enum_into_u32()); |
268 | 0 | contains |
269 | 0 | } Unexecuted instantiation: <enumset::set::EnumSet<neqo_http3::headers_checks::PseudoHeaderState>>::insert Unexecuted instantiation: <enumset::set::EnumSet<neqo_transport::tracking::PacketNumberSpace>>::insert |
270 | | /// Removes a value from this set. Returns whether the value was present in the set. |
271 | | #[inline(always)] |
272 | 0 | pub fn remove(&mut self, value: T) -> bool { |
273 | 0 | let contains = self.contains(value); |
274 | 0 | self.__priv_repr.remove_bit(value.enum_into_u32()); |
275 | 0 | contains |
276 | 0 | } |
277 | | |
278 | | /// Adds all elements in another set to this one. |
279 | | #[inline(always)] |
280 | | pub fn insert_all(&mut self, other: Self) { |
281 | | self.__priv_repr = self.__priv_repr | other.__priv_repr |
282 | | } |
283 | | /// Removes all values in another set from this one. |
284 | | #[inline(always)] |
285 | | pub fn remove_all(&mut self, other: Self) { |
286 | | self.__priv_repr = self.__priv_repr.and_not(other.__priv_repr); |
287 | | } |
288 | | } |
289 | | |
290 | | impl<T: EnumSetType> Default for EnumSet<T> { |
291 | | /// Returns an empty set. |
292 | 442 | fn default() -> Self { |
293 | 442 | Self::new() |
294 | 442 | } |
295 | | } |
296 | | |
297 | | impl<T: EnumSetType, O: Into<EnumSet<T>>> Sub<O> for EnumSet<T> { |
298 | | type Output = Self; |
299 | | #[inline(always)] |
300 | 0 | fn sub(self, other: O) -> Self::Output { |
301 | 0 | self.difference(other.into()) |
302 | 0 | } |
303 | | } |
304 | | impl<T: EnumSetType, O: Into<EnumSet<T>>> BitAnd<O> for EnumSet<T> { |
305 | | type Output = Self; |
306 | | #[inline(always)] |
307 | 0 | fn bitand(self, other: O) -> Self::Output { |
308 | 0 | self.intersection(other.into()) |
309 | 0 | } Unexecuted instantiation: <enumset::set::EnumSet<neqo_http3::headers_checks::PseudoHeaderState> as core::ops::bit::BitAnd<neqo_http3::headers_checks::PseudoHeaderState>>::bitand Unexecuted instantiation: <enumset::set::EnumSet<neqo_http3::headers_checks::PseudoHeaderState> as core::ops::bit::BitAnd>::bitand |
310 | | } |
311 | | impl<T: EnumSetType, O: Into<EnumSet<T>>> BitOr<O> for EnumSet<T> { |
312 | | type Output = Self; |
313 | | #[inline(always)] |
314 | 0 | fn bitor(self, other: O) -> Self::Output { |
315 | 0 | self.union(other.into()) |
316 | 0 | } Unexecuted instantiation: <enumset::set::EnumSet<neqo_http3::headers_checks::PseudoHeaderState> as core::ops::bit::BitOr<neqo_http3::headers_checks::PseudoHeaderState>>::bitor Unexecuted instantiation: <enumset::set::EnumSet<neqo_http3::headers_checks::PseudoHeaderState> as core::ops::bit::BitOr>::bitor Unexecuted instantiation: <enumset::set::EnumSet<neqo_transport::tracking::PacketNumberSpace> as core::ops::bit::BitOr>::bitor |
317 | | } |
318 | | impl<T: EnumSetType, O: Into<EnumSet<T>>> BitXor<O> for EnumSet<T> { |
319 | | type Output = Self; |
320 | | #[inline(always)] |
321 | | fn bitxor(self, other: O) -> Self::Output { |
322 | | self.symmetrical_difference(other.into()) |
323 | | } |
324 | | } |
325 | | |
326 | | impl<T: EnumSetType, O: Into<EnumSet<T>>> SubAssign<O> for EnumSet<T> { |
327 | | #[inline(always)] |
328 | 0 | fn sub_assign(&mut self, rhs: O) { |
329 | 0 | *self = *self - rhs; |
330 | 0 | } |
331 | | } |
332 | | impl<T: EnumSetType, O: Into<EnumSet<T>>> BitAndAssign<O> for EnumSet<T> { |
333 | | #[inline(always)] |
334 | | fn bitand_assign(&mut self, rhs: O) { |
335 | | *self = *self & rhs; |
336 | | } |
337 | | } |
338 | | impl<T: EnumSetType, O: Into<EnumSet<T>>> BitOrAssign<O> for EnumSet<T> { |
339 | | #[inline(always)] |
340 | 0 | fn bitor_assign(&mut self, rhs: O) { |
341 | 0 | *self = *self | rhs; |
342 | 0 | } Unexecuted instantiation: <enumset::set::EnumSet<neqo_http3::headers_checks::PseudoHeaderState> as core::ops::bit::BitOrAssign<neqo_http3::headers_checks::PseudoHeaderState>>::bitor_assign Unexecuted instantiation: <enumset::set::EnumSet<neqo_transport::tracking::PacketNumberSpace> as core::ops::bit::BitOrAssign>::bitor_assign |
343 | | } |
344 | | impl<T: EnumSetType, O: Into<EnumSet<T>>> BitXorAssign<O> for EnumSet<T> { |
345 | | #[inline(always)] |
346 | | fn bitxor_assign(&mut self, rhs: O) { |
347 | | *self = *self ^ rhs; |
348 | | } |
349 | | } |
350 | | |
351 | | impl<T: EnumSetType> Not for EnumSet<T> { |
352 | | type Output = Self; |
353 | | #[inline(always)] |
354 | 0 | fn not(self) -> Self::Output { |
355 | 0 | self.complement() |
356 | 0 | } Unexecuted instantiation: <enumset::set::EnumSet<neqo_http3::headers_checks::PseudoHeaderState> as core::ops::bit::Not>::not Unexecuted instantiation: <enumset::set::EnumSet<neqo_transport::tracking::PacketNumberSpace> as core::ops::bit::Not>::not |
357 | | } |
358 | | |
359 | | impl<T: EnumSetType> From<T> for EnumSet<T> { |
360 | 0 | fn from(t: T) -> Self { |
361 | 0 | EnumSet::only(t) |
362 | 0 | } Unexecuted instantiation: <enumset::set::EnumSet<neqo_http3::headers_checks::PseudoHeaderState> as core::convert::From<neqo_http3::headers_checks::PseudoHeaderState>>::from Unexecuted instantiation: <enumset::set::EnumSet<neqo_transport::tracking::PacketNumberSpace> as core::convert::From<neqo_transport::tracking::PacketNumberSpace>>::from |
363 | | } |
364 | | |
365 | | impl<T: EnumSetType> PartialEq<T> for EnumSet<T> { |
366 | | fn eq(&self, other: &T) -> bool { |
367 | | self.__priv_repr == EnumSet::only(*other).__priv_repr |
368 | | } |
369 | | } |
370 | | impl<T: EnumSetType + Debug> Debug for EnumSet<T> { |
371 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { |
372 | 0 | let mut is_first = true; |
373 | 0 | f.write_str("EnumSet(")?; |
374 | 0 | for v in self.iter() { |
375 | 0 | if !is_first { |
376 | 0 | f.write_str(" | ")?; |
377 | 0 | } |
378 | 0 | is_first = false; |
379 | 0 | v.fmt(f)?; |
380 | | } |
381 | 0 | f.write_str(")")?; |
382 | 0 | Ok(()) |
383 | 0 | } |
384 | | } |
385 | | |
386 | | #[allow(clippy::derived_hash_with_manual_eq)] // This impl exists to change trait bounds only. |
387 | | impl<T: EnumSetType> Hash for EnumSet<T> { |
388 | | fn hash<H: Hasher>(&self, state: &mut H) { |
389 | | self.__priv_repr.hash(state) |
390 | | } |
391 | | } |
392 | | impl<T: EnumSetType> PartialOrd for EnumSet<T> { |
393 | | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
394 | | self.__priv_repr.partial_cmp(&other.__priv_repr) |
395 | | } |
396 | | } |
397 | | impl<T: EnumSetType> Ord for EnumSet<T> { |
398 | | fn cmp(&self, other: &Self) -> Ordering { |
399 | | self.__priv_repr.cmp(&other.__priv_repr) |
400 | | } |
401 | | } |
402 | | |
403 | | #[cfg(feature = "serde")] |
404 | | impl<T: EnumSetType> Serialize for EnumSet<T> { |
405 | | fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { |
406 | | T::serialize(*self, serializer) |
407 | | } |
408 | | } |
409 | | |
410 | | #[cfg(feature = "serde")] |
411 | | impl<'de, T: EnumSetType> Deserialize<'de> for EnumSet<T> { |
412 | | fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { |
413 | | T::deserialize(deserializer) |
414 | | } |
415 | | } |
416 | | //endregion |
417 | | |
418 | | //region EnumSet conversions |
419 | | impl<T: EnumSetType + EnumSetTypeWithRepr> EnumSet<T> { |
420 | | /// Returns a `T::Repr` representing the elements of this set. |
421 | | /// |
422 | | /// Unlike the other `as_*` methods, this method is zero-cost and guaranteed not to fail, |
423 | | /// panic or truncate any bits. |
424 | | /// |
425 | | /// In order to use this method, the definition of `T` must have the `#[enumset(repr = "…")]` |
426 | | /// annotation. |
427 | | #[inline(always)] |
428 | | pub fn as_repr(&self) -> <T as EnumSetTypeWithRepr>::Repr { |
429 | | self.__priv_repr |
430 | | } |
431 | | |
432 | | /// Constructs a bitset from a `T::Repr` without checking for invalid bits. |
433 | | /// |
434 | | /// Unlike the other `from_*` methods, this method is zero-cost and guaranteed not to fail, |
435 | | /// panic or truncate any bits, provided the conditions under “Safety” are upheld. |
436 | | /// |
437 | | /// In order to use this method, the definition of `T` must have the `#[enumset(repr = "…")]` |
438 | | /// annotation. |
439 | | /// |
440 | | /// # Safety |
441 | | /// |
442 | | /// All bits in the provided parameter `bits` that don't correspond to an enum variant of |
443 | | /// `T` must be set to `0`. Behavior is **undefined** if any of these bits are set to `1`. |
444 | | #[inline(always)] |
445 | | pub unsafe fn from_repr_unchecked(bits: <T as EnumSetTypeWithRepr>::Repr) -> Self { |
446 | | Self { __priv_repr: bits } |
447 | | } |
448 | | |
449 | | /// Constructs a bitset from a `T::Repr`. |
450 | | /// |
451 | | /// If a bit that doesn't correspond to an enum variant is set, this |
452 | | /// method will panic. |
453 | | /// |
454 | | /// In order to use this method, the definition of `T` must have the `#[enumset(repr = "…")]` |
455 | | /// annotation. |
456 | | #[inline(always)] |
457 | | pub fn from_repr(bits: <T as EnumSetTypeWithRepr>::Repr) -> Self { |
458 | | Self::try_from_repr(bits).expect("Bitset contains invalid variants.") |
459 | | } |
460 | | |
461 | | /// Attempts to constructs a bitset from a `T::Repr`. |
462 | | /// |
463 | | /// If a bit that doesn't correspond to an enum variant is set, this |
464 | | /// method will return `None`. |
465 | | /// |
466 | | /// In order to use this method, the definition of `T` must have the `#[enumset(repr = "…")]` |
467 | | /// annotation. |
468 | | #[inline(always)] |
469 | | pub fn try_from_repr(bits: <T as EnumSetTypeWithRepr>::Repr) -> Option<Self> { |
470 | | let mask = Self::all().__priv_repr; |
471 | | if bits.and_not(mask).is_empty() { |
472 | | Some(EnumSet { __priv_repr: bits }) |
473 | | } else { |
474 | | None |
475 | | } |
476 | | } |
477 | | |
478 | | /// Constructs a bitset from a `T::Repr`, ignoring invalid variants. |
479 | | /// |
480 | | /// In order to use this method, the definition of `T` must have the `#[enumset(repr = "…")]` |
481 | | /// annotation. |
482 | | #[inline(always)] |
483 | | pub fn from_repr_truncated(bits: <T as EnumSetTypeWithRepr>::Repr) -> Self { |
484 | | let mask = Self::all().as_repr(); |
485 | | let bits = bits & mask; |
486 | | EnumSet { __priv_repr: bits } |
487 | | } |
488 | | } |
489 | | |
490 | | /// Helper macro for generating conversion functions. |
491 | | macro_rules! conversion_impls { |
492 | | ( |
493 | | $(for_num!( |
494 | | $underlying:ty, $underlying_str:expr, |
495 | | $from_fn:ident $to_fn:ident $from_fn_opt:ident $to_fn_opt:ident, |
496 | | $from:ident $try_from:ident $from_truncated:ident $from_unchecked:ident, |
497 | | $to:ident $try_to:ident $to_truncated:ident |
498 | | );)* |
499 | | ) => { |
500 | | impl<T: EnumSetType> EnumSet<T> {$( |
501 | | #[doc = "Returns a `"] |
502 | | #[doc = $underlying_str] |
503 | | #[doc = "` representing the elements of this set.\n\nIf the underlying bitset will \ |
504 | | not fit in a `"] |
505 | | #[doc = $underlying_str] |
506 | | #[doc = "`, this method will panic."] |
507 | | #[inline(always)] |
508 | | pub fn $to(&self) -> $underlying { |
509 | | self.$try_to().expect("Bitset will not fit into this type.") |
510 | | } |
511 | | |
512 | | #[doc = "Tries to return a `"] |
513 | | #[doc = $underlying_str] |
514 | | #[doc = "` representing the elements of this set.\n\nIf the underlying bitset will \ |
515 | | not fit in a `"] |
516 | | #[doc = $underlying_str] |
517 | | #[doc = "`, this method will panic."] |
518 | | #[inline(always)] |
519 | | pub fn $try_to(&self) -> Option<$underlying> { |
520 | | EnumSetTypeRepr::$to_fn_opt(&self.__priv_repr) |
521 | | } |
522 | | |
523 | | #[doc = "Returns a truncated `"] |
524 | | #[doc = $underlying_str] |
525 | | #[doc = "` representing the elements of this set.\n\nIf the underlying bitset will \ |
526 | | not fit in a `"] |
527 | | #[doc = $underlying_str] |
528 | | #[doc = "`, this method will truncate any bits that don't fit."] |
529 | | #[inline(always)] |
530 | | pub fn $to_truncated(&self) -> $underlying { |
531 | | EnumSetTypeRepr::$to_fn(&self.__priv_repr) |
532 | | } |
533 | | |
534 | | #[doc = "Constructs a bitset from a `"] |
535 | | #[doc = $underlying_str] |
536 | | #[doc = "`.\n\nIf a bit that doesn't correspond to an enum variant is set, this \ |
537 | | method will panic."] |
538 | | #[inline(always)] |
539 | | pub fn $from(bits: $underlying) -> Self { |
540 | | Self::$try_from(bits).expect("Bitset contains invalid variants.") |
541 | | } |
542 | | |
543 | | #[doc = "Attempts to constructs a bitset from a `"] |
544 | | #[doc = $underlying_str] |
545 | | #[doc = "`.\n\nIf a bit that doesn't correspond to an enum variant is set, this \ |
546 | | method will return `None`."] |
547 | | #[inline(always)] |
548 | | pub fn $try_from(bits: $underlying) -> Option<Self> { |
549 | | let bits = T::Repr::$from_fn_opt(bits); |
550 | | let mask = T::ALL_BITS; |
551 | | bits.and_then(|bits| if bits.and_not(mask).is_empty() { |
552 | | Some(EnumSet { __priv_repr: bits }) |
553 | | } else { |
554 | | None |
555 | | }) |
556 | | } |
557 | | |
558 | | #[doc = "Constructs a bitset from a `"] |
559 | | #[doc = $underlying_str] |
560 | | #[doc = "`, ignoring bits that do not correspond to a variant."] |
561 | | #[inline(always)] |
562 | | pub fn $from_truncated(bits: $underlying) -> Self { |
563 | | let mask = Self::all().$to_truncated(); |
564 | | let bits = <T::Repr as EnumSetTypeRepr>::$from_fn(bits & mask); |
565 | | EnumSet { __priv_repr: bits } |
566 | | } |
567 | | |
568 | | #[doc = "Constructs a bitset from a `"] |
569 | | #[doc = $underlying_str] |
570 | | #[doc = "`, without checking for invalid bits."] |
571 | | /// |
572 | | /// # Safety |
573 | | /// |
574 | | /// All bits in the provided parameter `bits` that don't correspond to an enum variant |
575 | | /// of `T` must be set to `0`. Behavior is **undefined** if any of these bits are set |
576 | | /// to `1`. |
577 | | #[inline(always)] |
578 | | pub unsafe fn $from_unchecked(bits: $underlying) -> Self { |
579 | | EnumSet { __priv_repr: <T::Repr as EnumSetTypeRepr>::$from_fn(bits) } |
580 | | } |
581 | | )*} |
582 | | } |
583 | | } |
584 | | conversion_impls! { |
585 | | for_num!(u8, "u8", |
586 | | from_u8 to_u8 from_u8_opt to_u8_opt, |
587 | | from_u8 try_from_u8 from_u8_truncated from_u8_unchecked, |
588 | | as_u8 try_as_u8 as_u8_truncated); |
589 | | for_num!(u16, "u16", |
590 | | from_u16 to_u16 from_u16_opt to_u16_opt, |
591 | | from_u16 try_from_u16 from_u16_truncated from_u16_unchecked, |
592 | | as_u16 try_as_u16 as_u16_truncated); |
593 | | for_num!(u32, "u32", |
594 | | from_u32 to_u32 from_u32_opt to_u32_opt, |
595 | | from_u32 try_from_u32 from_u32_truncated from_u32_unchecked, |
596 | | as_u32 try_as_u32 as_u32_truncated); |
597 | | for_num!(u64, "u64", |
598 | | from_u64 to_u64 from_u64_opt to_u64_opt, |
599 | | from_u64 try_from_u64 from_u64_truncated from_u64_unchecked, |
600 | | as_u64 try_as_u64 as_u64_truncated); |
601 | | for_num!(u128, "u128", |
602 | | from_u128 to_u128 from_u128_opt to_u128_opt, |
603 | | from_u128 try_from_u128 from_u128_truncated from_u128_unchecked, |
604 | | as_u128 try_as_u128 as_u128_truncated); |
605 | | for_num!(usize, "usize", |
606 | | from_usize to_usize from_usize_opt to_usize_opt, |
607 | | from_usize try_from_usize from_usize_truncated from_usize_unchecked, |
608 | | as_usize try_as_usize as_usize_truncated); |
609 | | } |
610 | | |
611 | | impl<T: EnumSetType> EnumSet<T> { |
612 | | /// Returns an `[u64; O]` representing the elements of this set. |
613 | | /// |
614 | | /// If the underlying bitset will not fit in a `[u64; O]`, this method will panic. |
615 | | pub fn as_array<const O: usize>(&self) -> [u64; O] { |
616 | | self.try_as_array() |
617 | | .expect("Bitset will not fit into this type.") |
618 | | } |
619 | | |
620 | | /// Returns an `[u64; O]` representing the elements of this set. |
621 | | /// |
622 | | /// If the underlying bitset will not fit in a `[u64; O]`, this method will instead return |
623 | | /// `None`. |
624 | | pub fn try_as_array<const O: usize>(&self) -> Option<[u64; O]> { |
625 | | self.__priv_repr.to_u64_array_opt() |
626 | | } |
627 | | |
628 | | /// Returns an `[u64; O]` representing the elements of this set. |
629 | | /// |
630 | | /// If the underlying bitset will not fit in a `[u64; O]`, this method will truncate any bits |
631 | | /// that don't fit. |
632 | | pub fn as_array_truncated<const O: usize>(&self) -> [u64; O] { |
633 | | self.__priv_repr.to_u64_array() |
634 | | } |
635 | | |
636 | | /// Attempts to constructs a bitset from a `[u64; O]`. |
637 | | /// |
638 | | /// If a bit that doesn't correspond to an enum variant is set, this method will panic. |
639 | | pub fn from_array<const O: usize>(v: [u64; O]) -> Self { |
640 | | Self::try_from_array(v).expect("Bitset contains invalid variants.") |
641 | | } |
642 | | |
643 | | /// Attempts to constructs a bitset from a `[u64; O]`. |
644 | | /// |
645 | | /// If a bit that doesn't correspond to an enum variant is set, this method will return `None`. |
646 | | pub fn try_from_array<const O: usize>(bits: [u64; O]) -> Option<Self> { |
647 | | let bits = T::Repr::from_u64_array_opt::<O>(bits); |
648 | | let mask = T::ALL_BITS; |
649 | | bits.and_then(|bits| { |
650 | | if bits.and_not(mask).is_empty() { |
651 | | Some(EnumSet { __priv_repr: bits }) |
652 | | } else { |
653 | | None |
654 | | } |
655 | | }) |
656 | | } |
657 | | |
658 | | /// Constructs a bitset from a `[u64; O]`, ignoring bits that do not correspond to a variant. |
659 | | pub fn from_array_truncated<const O: usize>(bits: [u64; O]) -> Self { |
660 | | let bits = T::Repr::from_u64_array(bits) & T::ALL_BITS; |
661 | | EnumSet { __priv_repr: bits } |
662 | | } |
663 | | |
664 | | /// Constructs a bitset from a `[u64; O]`, without checking for invalid bits. |
665 | | /// |
666 | | /// # Safety |
667 | | /// |
668 | | /// All bits in the provided parameter `bits` that don't correspond to an enum variant |
669 | | /// of `T` must be set to `0`. Behavior is **undefined** if any of these bits are set |
670 | | /// to `1`. |
671 | | #[inline(always)] |
672 | | pub unsafe fn from_array_unchecked<const O: usize>(bits: [u64; O]) -> Self { |
673 | | EnumSet { __priv_repr: T::Repr::from_u64_array(bits) } |
674 | | } |
675 | | |
676 | | /// Returns a `Vec<u64>` representing the elements of this set. |
677 | | #[cfg(feature = "alloc")] |
678 | | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] |
679 | | pub fn to_vec(&self) -> alloc::vec::Vec<u64> { |
680 | | let mut vec = alloc::vec![0; T::Repr::PREFERRED_ARRAY_LEN]; |
681 | | self.__priv_repr.to_u64_slice(&mut vec); |
682 | | vec |
683 | | } |
684 | | |
685 | | /// Copies the elements of this set into a `&mut [u64]`. |
686 | | /// |
687 | | /// If the underlying bitset will not fit in the provided slice, this method will panic. |
688 | | pub fn copy_into_slice(&self, data: &mut [u64]) { |
689 | | self.try_copy_into_slice(data) |
690 | | .expect("Bitset will not fit into slice.") |
691 | | } |
692 | | |
693 | | /// Copies the elements of this set into a `&mut [u64]`. |
694 | | /// |
695 | | /// If the underlying bitset will not fit in the provided slice, this method will return |
696 | | /// `None`. Otherwise, it will return `Some(())`. |
697 | | #[must_use] |
698 | | pub fn try_copy_into_slice(&self, data: &mut [u64]) -> Option<()> { |
699 | | self.__priv_repr.to_u64_slice_opt(data) |
700 | | } |
701 | | |
702 | | /// Copies the elements of this set into a `&mut [u64]`. |
703 | | /// |
704 | | /// If the underlying bitset will not fit in the provided slice, this method will truncate any |
705 | | /// bits that don't fit. |
706 | | pub fn copy_into_slice_truncated(&self, data: &mut [u64]) { |
707 | | self.__priv_repr.to_u64_slice(data) |
708 | | } |
709 | | |
710 | | /// Attempts to constructs a bitset from a `&[u64]`. |
711 | | /// |
712 | | /// If a bit that doesn't correspond to an enum variant is set, this method will panic. |
713 | | pub fn from_slice(v: &[u64]) -> Self { |
714 | | Self::try_from_slice(v).expect("Bitset contains invalid variants.") |
715 | | } |
716 | | |
717 | | /// Attempts to constructs a bitset from a `&[u64]`. |
718 | | /// |
719 | | /// If a bit that doesn't correspond to an enum variant is set, this method will return `None`. |
720 | | pub fn try_from_slice(bits: &[u64]) -> Option<Self> { |
721 | | let bits = T::Repr::from_u64_slice_opt(bits); |
722 | | let mask = T::ALL_BITS; |
723 | | bits.and_then(|bits| { |
724 | | if bits.and_not(mask).is_empty() { |
725 | | Some(EnumSet { __priv_repr: bits }) |
726 | | } else { |
727 | | None |
728 | | } |
729 | | }) |
730 | | } |
731 | | |
732 | | /// Constructs a bitset from a `&[u64]`, ignoring bits that do not correspond to a variant. |
733 | | pub fn from_slice_truncated(bits: &[u64]) -> Self { |
734 | | let bits = T::Repr::from_u64_slice(bits) & T::ALL_BITS; |
735 | | EnumSet { __priv_repr: bits } |
736 | | } |
737 | | |
738 | | /// Constructs a bitset from a `&[u64]`, without checking for invalid bits. |
739 | | /// |
740 | | /// # Safety |
741 | | /// |
742 | | /// All bits in the provided parameter `bits` that don't correspond to an enum variant |
743 | | /// of `T` must be set to `0`. Behavior is **undefined** if any of these bits are set |
744 | | /// to `1`. |
745 | | #[inline(always)] |
746 | | pub unsafe fn from_slice_unchecked(bits: &[u64]) -> Self { |
747 | | EnumSet { __priv_repr: T::Repr::from_u64_slice(bits) } |
748 | | } |
749 | | } |
750 | | //endregion |
751 | | |
752 | | //region EnumSet iter |
753 | | /// The iterator used by [`EnumSet`]s. |
754 | | #[derive(Clone, Debug)] |
755 | | pub struct EnumSetIter<T: EnumSetType> { |
756 | | iter: <T::Repr as EnumSetTypeRepr>::Iter, |
757 | | } |
758 | | impl<T: EnumSetType> EnumSetIter<T> { |
759 | 0 | fn new(set: EnumSet<T>) -> EnumSetIter<T> { |
760 | 0 | EnumSetIter { iter: set.__priv_repr.iter() } |
761 | 0 | } |
762 | | } |
763 | | |
764 | | impl<T: EnumSetType> EnumSet<T> { |
765 | | /// Iterates the contents of the set in order from the least significant bit to the most |
766 | | /// significant bit. |
767 | | /// |
768 | | /// Note that iterator invalidation is impossible as the iterator contains a copy of this type, |
769 | | /// rather than holding a reference to it. |
770 | 0 | pub fn iter(&self) -> EnumSetIter<T> { |
771 | 0 | EnumSetIter::new(*self) |
772 | 0 | } |
773 | | } |
774 | | |
775 | | impl<T: EnumSetType> Iterator for EnumSetIter<T> { |
776 | | type Item = T; |
777 | | |
778 | 0 | fn next(&mut self) -> Option<Self::Item> { |
779 | 0 | self.iter.next().map(|x| unsafe { T::enum_from_u32(x) }) |
780 | 0 | } |
781 | | fn size_hint(&self) -> (usize, Option<usize>) { |
782 | | self.iter.size_hint() |
783 | | } |
784 | | } |
785 | | |
786 | | impl<T: EnumSetType> DoubleEndedIterator for EnumSetIter<T> { |
787 | | fn next_back(&mut self) -> Option<Self::Item> { |
788 | | self.iter |
789 | | .next_back() |
790 | | .map(|x| unsafe { T::enum_from_u32(x) }) |
791 | | } |
792 | | } |
793 | | |
794 | | impl<T: EnumSetType> ExactSizeIterator for EnumSetIter<T> {} |
795 | | |
796 | | impl<T: EnumSetType> Extend<T> for EnumSet<T> { |
797 | | fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { |
798 | | iter.into_iter().for_each(|v| { |
799 | | self.insert(v); |
800 | | }); |
801 | | } |
802 | | } |
803 | | |
804 | | impl<T: EnumSetType> FromIterator<T> for EnumSet<T> { |
805 | | fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self { |
806 | | let mut set = EnumSet::default(); |
807 | | set.extend(iter); |
808 | | set |
809 | | } |
810 | | } |
811 | | |
812 | | impl<T: EnumSetType> Extend<EnumSet<T>> for EnumSet<T> { |
813 | | fn extend<I: IntoIterator<Item = EnumSet<T>>>(&mut self, iter: I) { |
814 | | iter.into_iter().for_each(|v| { |
815 | | self.insert_all(v); |
816 | | }); |
817 | | } |
818 | | } |
819 | | |
820 | | impl<T: EnumSetType> FromIterator<EnumSet<T>> for EnumSet<T> { |
821 | | fn from_iter<I: IntoIterator<Item = EnumSet<T>>>(iter: I) -> Self { |
822 | | let mut set = EnumSet::default(); |
823 | | set.extend(iter); |
824 | | set |
825 | | } |
826 | | } |
827 | | |
828 | | impl<T: EnumSetType> IntoIterator for EnumSet<T> { |
829 | | type Item = T; |
830 | | type IntoIter = EnumSetIter<T>; |
831 | | |
832 | | fn into_iter(self) -> Self::IntoIter { |
833 | | self.iter() |
834 | | } |
835 | | } |
836 | | impl<T: EnumSetType> Sum for EnumSet<T> { |
837 | | fn sum<I: Iterator<Item = Self>>(iter: I) -> Self { |
838 | | iter.fold(EnumSet::empty(), |a, v| a | v) |
839 | | } |
840 | | } |
841 | | impl<'a, T: EnumSetType> Sum<&'a EnumSet<T>> for EnumSet<T> { |
842 | | fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self { |
843 | | iter.fold(EnumSet::empty(), |a, v| a | *v) |
844 | | } |
845 | | } |
846 | | impl<T: EnumSetType> Sum<T> for EnumSet<T> { |
847 | | fn sum<I: Iterator<Item = T>>(iter: I) -> Self { |
848 | | iter.fold(EnumSet::empty(), |a, v| a | v) |
849 | | } |
850 | | } |
851 | | impl<'a, T: EnumSetType> Sum<&'a T> for EnumSet<T> { |
852 | | fn sum<I: Iterator<Item = &'a T>>(iter: I) -> Self { |
853 | | iter.fold(EnumSet::empty(), |a, v| a | *v) |
854 | | } |
855 | | } |
856 | | //endregion |