Skip to main content

enumset/repr/
primitive.rs

1use crate::repr::EnumSetTypeRepr;
2
3pub trait Primitive {
4    fn leading_zeros(&self) -> u32;
5    fn trailing_zeros(&self) -> u32;
6}
7
8macro_rules! prim {
9    ($name:ty, $width:expr, $preferred_array_len:expr) => {
10        const _: () = {
11            fn lo(v: $name) -> u64 {
12                v as u64
13            }
14            fn hi(v: $name) -> u64 {
15                ((v as u128) >> 64) as u64
16            }
17
18            impl EnumSetTypeRepr for $name {
19                const PREFERRED_ARRAY_LEN: usize = $preferred_array_len;
20                const WIDTH: u32 = $width;
21                const EMPTY: Self = 0;
22
23                #[inline(always)]
24                fn is_empty(&self) -> bool {
25                    *self == 0
26                }
27
28                #[inline(always)]
29                fn add_bit(&mut self, bit: u32) {
30                    *self |= 1 << bit as $name;
31                }
32                #[inline(always)]
33                fn remove_bit(&mut self, bit: u32) {
34                    *self &= !(1 << bit as $name);
35                }
36                #[inline(always)]
37                fn has_bit(&self, bit: u32) -> bool {
38                    (self & (1 << bit as $name)) != 0
39                }
40
41                #[inline(always)]
42                fn count_ones(&self) -> u32 {
43                    (*self).count_ones()
44                }
45
46                #[inline(always)]
47                fn and_not(&self, other: Self) -> Self {
48                    (*self) & !other
49                }
50
51                type Iter = PrimitiveIter<Self>;
52                #[inline]
53                fn iter(self) -> Self::Iter {
54                    PrimitiveIter(self)
55                }
56
57                #[inline(always)]
58                fn from_u8(v: u8) -> Self {
59                    v as $name
60                }
61                #[inline(always)]
62                fn from_u16(v: u16) -> Self {
63                    v as $name
64                }
65                #[inline(always)]
66                fn from_u32(v: u32) -> Self {
67                    v as $name
68                }
69                #[inline(always)]
70                fn from_u64(v: u64) -> Self {
71                    v as $name
72                }
73                #[inline(always)]
74                fn from_u128(v: u128) -> Self {
75                    v as $name
76                }
77                #[inline(always)]
78                fn from_usize(v: usize) -> Self {
79                    v as $name
80                }
81
82                #[inline(always)]
83                fn to_u8(&self) -> u8 {
84                    (*self) as u8
85                }
86                #[inline(always)]
87                fn to_u16(&self) -> u16 {
88                    (*self) as u16
89                }
90                #[inline(always)]
91                fn to_u32(&self) -> u32 {
92                    (*self) as u32
93                }
94                #[inline(always)]
95                fn to_u64(&self) -> u64 {
96                    (*self) as u64
97                }
98                #[inline(always)]
99                fn to_u128(&self) -> u128 {
100                    (*self) as u128
101                }
102                #[inline(always)]
103                fn to_usize(&self) -> usize {
104                    (*self) as usize
105                }
106
107                #[inline(always)]
108                fn from_u8_opt(v: u8) -> Option<Self> {
109                    v.try_into().ok()
110                }
111                #[inline(always)]
112                fn from_u16_opt(v: u16) -> Option<Self> {
113                    v.try_into().ok()
114                }
115                #[inline(always)]
116                fn from_u32_opt(v: u32) -> Option<Self> {
117                    v.try_into().ok()
118                }
119                #[inline(always)]
120                fn from_u64_opt(v: u64) -> Option<Self> {
121                    v.try_into().ok()
122                }
123                #[inline(always)]
124                fn from_u128_opt(v: u128) -> Option<Self> {
125                    v.try_into().ok()
126                }
127                #[inline(always)]
128                fn from_usize_opt(v: usize) -> Option<Self> {
129                    v.try_into().ok()
130                }
131
132                #[inline(always)]
133                fn to_u8_opt(&self) -> Option<u8> {
134                    (*self).try_into().ok()
135                }
136                #[inline(always)]
137                fn to_u16_opt(&self) -> Option<u16> {
138                    (*self).try_into().ok()
139                }
140                #[inline(always)]
141                fn to_u32_opt(&self) -> Option<u32> {
142                    (*self).try_into().ok()
143                }
144                #[inline(always)]
145                fn to_u64_opt(&self) -> Option<u64> {
146                    (*self).try_into().ok()
147                }
148                #[inline(always)]
149                fn to_u128_opt(&self) -> Option<u128> {
150                    (*self).try_into().ok()
151                }
152                #[inline(always)]
153                fn to_usize_opt(&self) -> Option<usize> {
154                    (*self).try_into().ok()
155                }
156
157                #[inline(always)]
158                fn to_u64_array<const O: usize>(&self) -> [u64; O] {
159                    let mut array = [0; O];
160                    if O > 0 {
161                        array[0] = lo(*self);
162                    }
163                    if O > 1 && $preferred_array_len == 2 {
164                        array[1] = hi(*self);
165                    }
166                    array
167                }
168                #[inline(always)]
169                fn to_u64_array_opt<const O: usize>(&self) -> Option<[u64; O]> {
170                    if O == 0 && *self != 0 {
171                        None
172                    } else if O == 1 && hi(*self) != 0 {
173                        None
174                    } else {
175                        Some(self.to_u64_array())
176                    }
177                }
178
179                #[inline(always)]
180                fn from_u64_array<const O: usize>(v: [u64; O]) -> Self {
181                    if O == 0 {
182                        0
183                    } else if O > 1 && $preferred_array_len == 2 {
184                        Self::from_u128(v[0] as u128 | ((v[1] as u128) << 64))
185                    } else {
186                        Self::from_u64(v[0])
187                    }
188                }
189                #[inline(always)]
190                fn from_u64_array_opt<const O: usize>(v: [u64; O]) -> Option<Self> {
191                    if O == 0 {
192                        Some(0)
193                    } else if O == 1 {
194                        Self::from_u64_opt(v[0])
195                    } else {
196                        for i in 2..O {
197                            if v[i] != 0 {
198                                return None;
199                            }
200                        }
201                        Self::from_u128_opt(v[0] as u128 | ((v[1] as u128) << 64))
202                    }
203                }
204
205                #[inline(always)]
206                fn to_u64_slice(&self, out: &mut [u64]) {
207                    if out.len() > 0 {
208                        out[0] = lo(*self);
209                    }
210                    if out.len() > 1 && $preferred_array_len == 2 {
211                        out[1] = hi(*self);
212                    }
213                    for i in $preferred_array_len..out.len() {
214                        out[i] = 0;
215                    }
216                }
217                #[inline(always)]
218                fn to_u64_slice_opt(&self, out: &mut [u64]) -> Option<()> {
219                    if out.len() == 0 && *self != 0 {
220                        None
221                    } else if out.len() == 1 && hi(*self) != 0 {
222                        None
223                    } else {
224                        self.to_u64_slice(out);
225                        Some(())
226                    }
227                }
228
229                #[inline(always)]
230                fn from_u64_slice(v: &[u64]) -> Self {
231                    if v.len() == 0 {
232                        0
233                    } else if v.len() > 1 && $preferred_array_len == 2 {
234                        Self::from_u128(v[0] as u128 | ((v[1] as u128) << 64))
235                    } else {
236                        Self::from_u64(v[0])
237                    }
238                }
239                #[inline(always)]
240                fn from_u64_slice_opt(v: &[u64]) -> Option<Self> {
241                    if v.len() == 0 {
242                        Some(0)
243                    } else if v.len() == 1 {
244                        Self::from_u64_opt(v[0])
245                    } else {
246                        for i in 2..v.len() {
247                            if v[i] != 0 {
248                                return None;
249                            }
250                        }
251                        Self::from_u128_opt(v[0] as u128 | ((v[1] as u128) << 64))
252                    }
253                }
254            }
255            impl Primitive for $name {
256                #[inline(always)]
257                fn leading_zeros(&self) -> u32 {
258                    (*self).leading_zeros()
259                }
260                #[inline(always)]
261                fn trailing_zeros(&self) -> u32 {
262                    (*self).trailing_zeros()
263                }
264            }
265        };
266    };
267}
268prim!(u8, 8, 1);
269prim!(u16, 16, 1);
270prim!(u32, 32, 1);
271prim!(u64, 64, 1);
272prim!(u128, 128, 2);
273
274#[derive(Copy, Clone, Debug)]
275#[repr(transparent)]
276pub struct PrimitiveIter<T: EnumSetTypeRepr + Primitive>(pub T);
277
278impl<T: EnumSetTypeRepr + Primitive> Iterator for PrimitiveIter<T> {
279    type Item = u32;
280
281    fn next(&mut self) -> Option<Self::Item> {
282        if self.0.is_empty() {
283            None
284        } else {
285            let bit = self.0.trailing_zeros();
286            self.0.remove_bit(bit);
287            Some(bit)
288        }
289    }
290
291    fn size_hint(&self) -> (usize, Option<usize>) {
292        let left = self.0.count_ones() as usize;
293        (left, Some(left))
294    }
295}
296
297impl<T: EnumSetTypeRepr + Primitive> DoubleEndedIterator for PrimitiveIter<T> {
298    fn next_back(&mut self) -> Option<Self::Item> {
299        if self.0.is_empty() {
300            None
301        } else {
302            let bit = T::WIDTH - 1 - self.0.leading_zeros();
303            self.0.remove_bit(bit);
304            Some(bit)
305        }
306    }
307}
308
309impl<T: EnumSetTypeRepr + Primitive> ExactSizeIterator for PrimitiveIter<T> {}