abi_stable/sabi_types/
bitarray.rs
1use crate::const_utils::low_bit_mask_u64;
4
5use std::{
6 fmt::{self, Debug},
7 iter::ExactSizeIterator,
8 marker::PhantomData,
9};
10
11#[cfg(all(test, not(feature = "only_new_tests")))]
12mod tests;
13
14#[must_use = "BitArray64 is returned by value by every mutating method."]
65#[derive(StableAbi, PartialEq, Eq)]
66#[repr(transparent)]
67pub struct BitArray64<E> {
68 bits: u64,
69 _marker: PhantomData<E>,
70}
71
72impl<E> Copy for BitArray64<E> {}
73impl<E> Clone for BitArray64<E> {
74 fn clone(&self) -> Self {
75 Self {
76 bits: self.bits,
77 _marker: PhantomData,
78 }
79 }
80}
81
82impl<E> BitArray64<E> {
83 #[inline]
85 pub const fn with_count(count: usize) -> Self
86 where
87 E: BooleanEnum,
88 {
89 Self {
90 bits: low_bit_mask_u64(count as u32),
91 _marker: PhantomData,
92 }
93 }
94
95 #[inline]
97 pub const fn from_u64(bits: u64) -> Self {
98 Self {
99 bits,
100 _marker: PhantomData,
101 }
102 }
103
104 #[inline]
106 pub const fn empty() -> Self {
107 Self {
108 bits: 0,
109 _marker: PhantomData,
110 }
111 }
112}
113
114impl<E> BitArray64<E> {
115 pub const fn at(self, index: usize) -> E
122 where
123 E: BooleanEnum,
124 {
125 Self::assert_index(index);
126
127 bool_to_enum((self.bits & (1u64 << index)) != 0)
128 }
129
130 pub const fn set(mut self, index: usize, value: E) -> Self
137 where
138 E: BooleanEnum,
139 {
140 if enum_to_bool(value) {
141 self.bits |= 1u64 << index;
142 } else {
143 self.bits &= !(1u64 << index);
144 }
145 self
146 }
147
148 #[track_caller]
149 const fn assert_index(index: usize) {
150 use const_panic::{concat_panic, FmtArg, PanicVal};
151
152 if index >= 64 {
153 concat_panic(&[&[
154 PanicVal::write_str("index out of bounds: the length is "),
155 PanicVal::from_usize(64, FmtArg::DEBUG),
156 PanicVal::write_str(" but the index is "),
157 PanicVal::from_usize(index, FmtArg::DEBUG),
158 ]])
159 }
160 }
161}
162
163impl<E> BitArray64<E> {
164 pub const fn truncated(mut self, length: usize) -> Self {
166 self.bits &= low_bit_mask_u64(length as u32);
167 self
168 }
169
170 #[inline]
172 pub const fn bits(self) -> u64 {
173 self.bits
174 }
175
176 #[allow(clippy::missing_const_for_fn)]
178 pub fn iter(self) -> BitArray64Iter<E> {
179 BitArray64Iter {
180 count: 64,
181 bits: self.bits(),
182 _marker: PhantomData,
183 }
184 }
185
186 pub fn eq(self, other: Self, count: usize) -> bool {
188 let all_accessible = low_bit_mask_u64(count as u32);
189 let implication = (!self.bits | other.bits) & all_accessible;
190 println!(
191 "self:{:b}\nother:{:b}\nall_accessible:{:b}\nimplication:{:b}",
192 self.bits, other.bits, all_accessible, implication,
193 );
194 implication == all_accessible
195 }
196}
197
198impl<E> Debug for BitArray64<E>
199where
200 E: BooleanEnum,
201{
202 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203 f.debug_list().entries(self.iter()).finish()
204 }
205}
206
207pub unsafe trait BooleanEnum: Debug + Copy + 'static {
220 const FALSE: Self;
222 const TRUE: Self;
224}
225
226const _: () = assert!(std::mem::size_of::<bool>() == 1);
227unsafe impl BooleanEnum for bool {
228 const FALSE: Self = false;
229 const TRUE: Self = true;
230}
231
232pub const fn bool_to_enum<E>(b: bool) -> E
238where
239 E: BooleanEnum,
240{
241 if b {
242 E::TRUE
243 } else {
244 E::FALSE
245 }
246}
247
248pub const fn enum_to_bool<E>(b: E) -> bool
254where
255 E: BooleanEnum,
256{
257 enum_as_u8(b) == EnumConsts::<E>::TRUE_U8
258}
259
260const fn enum_as_u8<E: BooleanEnum>(x: E) -> u8 {
261 unsafe { const_transmute!(E, u8, x) }
263}
264
265struct EnumConsts<E: BooleanEnum>(E);
266
267impl<E: BooleanEnum> EnumConsts<E> {
268 const TRUE_U8: u8 = enum_as_u8(E::TRUE);
269}
270
271#[derive(Debug, Clone)]
277pub struct BitArray64Iter<E> {
278 count: usize,
279 bits: u64,
280 _marker: PhantomData<E>,
281}
282
283impl<E> BitArray64Iter<E>
284where
285 E: BooleanEnum,
286{
287 #[inline]
288 fn next_inner<F>(&mut self, f: F) -> Option<E>
289 where
290 F: FnOnce(&mut Self) -> E,
291 {
292 if self.count == 0 {
293 None
294 } else {
295 Some(f(self))
296 }
297 }
298}
299impl<E> Iterator for BitArray64Iter<E>
300where
301 E: BooleanEnum,
302{
303 type Item = E;
304
305 fn next(&mut self) -> Option<E> {
306 self.next_inner(|this| {
307 this.count -= 1;
308 let cond = (this.bits & 1) != 0;
309 this.bits >>= 1;
310 bool_to_enum(cond)
311 })
312 }
313
314 #[inline]
315 fn size_hint(&self) -> (usize, Option<usize>) {
316 (self.len(), Some(self.len()))
317 }
318}
319
320impl<E> DoubleEndedIterator for BitArray64Iter<E>
321where
322 E: BooleanEnum,
323{
324 fn next_back(&mut self) -> Option<E> {
325 self.next_inner(|this| {
326 this.count -= 1;
327 bool_to_enum((this.bits & (1 << this.count)) != 0)
328 })
329 }
330}
331
332impl<E> ExactSizeIterator for BitArray64Iter<E>
333where
334 E: BooleanEnum,
335{
336 #[inline]
337 fn len(&self) -> usize {
338 self.count
339 }
340}