Skip to main content

arrow_buffer/util/
bit_iterator.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Types for iterating over packed bitmasks
19
20use crate::bit_chunk_iterator::{UnalignedBitChunk, UnalignedBitChunkIterator};
21use crate::bit_util::{ceil, get_bit_raw};
22
23/// Iterator over the bits within a packed bitmask
24///
25/// To efficiently iterate over just the set bits see [`BitIndexIterator`] and [`BitSliceIterator`]
26#[derive(Clone)]
27pub struct BitIterator<'a> {
28    buffer: &'a [u8],
29    current_offset: usize,
30    end_offset: usize,
31}
32
33impl<'a> BitIterator<'a> {
34    /// Create a new [`BitIterator`] from the provided `buffer`,
35    /// and `offset` and `len` in bits
36    ///
37    /// # Panics
38    ///
39    /// Panics if `buffer` is too short for the provided offset and length
40    pub fn new(buffer: &'a [u8], offset: usize, len: usize) -> Self {
41        let end_offset = offset.checked_add(len).unwrap();
42        let required_len = ceil(end_offset, 8);
43        assert!(
44            buffer.len() >= required_len,
45            "BitIterator buffer too small, expected {required_len} got {}",
46            buffer.len()
47        );
48
49        Self {
50            buffer,
51            current_offset: offset,
52            end_offset,
53        }
54    }
55}
56
57impl Iterator for BitIterator<'_> {
58    type Item = bool;
59
60    #[inline]
61    fn next(&mut self) -> Option<Self::Item> {
62        if self.current_offset == self.end_offset {
63            return None;
64        }
65        // Safety:
66        // offsets in bounds
67        let v = unsafe { get_bit_raw(self.buffer.as_ptr(), self.current_offset) };
68        self.current_offset += 1;
69        Some(v)
70    }
71
72    fn size_hint(&self) -> (usize, Option<usize>) {
73        let remaining_bits = self.end_offset - self.current_offset;
74        (remaining_bits, Some(remaining_bits))
75    }
76
77    fn count(self) -> usize
78    where
79        Self: Sized,
80    {
81        self.len()
82    }
83
84    #[inline]
85    fn nth(&mut self, n: usize) -> Option<Self::Item> {
86        // Check if we can advance to the desired offset.
87        // When n is 0 it means we want the next() value
88        // and when n is 1 we want the next().next() value
89        // so adding n to the current offset and not n - 1
90        match self.current_offset.checked_add(n) {
91            // Yes, and still within bounds
92            Some(new_offset) if new_offset < self.end_offset => {
93                self.current_offset = new_offset;
94            }
95
96            // Either overflow or would exceed end_offset
97            _ => {
98                self.current_offset = self.end_offset;
99                return None;
100            }
101        }
102
103        self.next()
104    }
105
106    fn last(mut self) -> Option<Self::Item> {
107        // If already at the end, return None
108        if self.current_offset == self.end_offset {
109            return None;
110        }
111
112        // Go to the one before the last bit
113        self.current_offset = self.end_offset - 1;
114
115        // Return the last bit
116        self.next()
117    }
118
119    fn max(self) -> Option<Self::Item>
120    where
121        Self: Sized,
122        Self::Item: Ord,
123    {
124        if self.current_offset == self.end_offset {
125            return None;
126        }
127
128        // true is greater than false so we only need to check if there's any true bit
129        let mut bit_index_iter = BitIndexIterator::new(
130            self.buffer,
131            self.current_offset,
132            self.end_offset - self.current_offset,
133        );
134
135        if bit_index_iter.next().is_some() {
136            return Some(true);
137        }
138
139        // We know the iterator is not empty and there are no set bits so false is the max
140        Some(false)
141    }
142}
143
144impl ExactSizeIterator for BitIterator<'_> {}
145
146impl DoubleEndedIterator for BitIterator<'_> {
147    fn next_back(&mut self) -> Option<Self::Item> {
148        if self.current_offset == self.end_offset {
149            return None;
150        }
151        self.end_offset -= 1;
152        // Safety:
153        // offsets in bounds
154        let v = unsafe { get_bit_raw(self.buffer.as_ptr(), self.end_offset) };
155        Some(v)
156    }
157
158    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
159        // Check if we can advance to the desired offset.
160        // When n is 0 it means we want the next_back() value
161        // and when n is 1 we want the next_back().next_back() value
162        // so subtracting n to the current offset and not n - 1
163        match self.end_offset.checked_sub(n) {
164            // Yes, and still within bounds
165            Some(new_offset) if self.current_offset < new_offset => {
166                self.end_offset = new_offset;
167            }
168
169            // Either underflow or would exceed current_offset
170            _ => {
171                self.current_offset = self.end_offset;
172                return None;
173            }
174        }
175
176        self.next_back()
177    }
178}
179
180/// Iterator of contiguous ranges of set bits within a provided packed bitmask
181///
182/// Returns `(usize, usize)` each representing an interval where the corresponding
183/// bits in the provides mask are set
184///
185/// the first value is the start of the range (inclusive) and the second value is the end of the range (exclusive)
186///
187#[derive(Debug)]
188pub struct BitSliceIterator<'a> {
189    iter: UnalignedBitChunkIterator<'a>,
190    len: usize,
191    current_offset: i64,
192    current_chunk: u64,
193}
194
195impl<'a> BitSliceIterator<'a> {
196    /// Create a new [`BitSliceIterator`] from the provided `buffer`,
197    /// and `offset` and `len` in bits
198    #[inline]
199    pub fn new(buffer: &'a [u8], offset: usize, len: usize) -> Self {
200        let chunk = UnalignedBitChunk::new(buffer, offset, len);
201        let mut iter = chunk.iter();
202
203        let current_offset = -(chunk.lead_padding() as i64);
204        let current_chunk = iter.next().unwrap_or(0);
205
206        Self {
207            iter,
208            len,
209            current_offset,
210            current_chunk,
211        }
212    }
213
214    /// Returns `Some((chunk_offset, bit_offset))` for the next chunk that has at
215    /// least one bit set, or None if there is no such chunk.
216    ///
217    /// Where `chunk_offset` is the bit offset to the current `u64` chunk
218    /// and `bit_offset` is the offset of the first `1` bit in that chunk
219    #[inline]
220    fn advance_to_set_bit(&mut self) -> Option<(i64, u32)> {
221        loop {
222            if self.current_chunk != 0 {
223                // Find the index of the first 1
224                let bit_pos = self.current_chunk.trailing_zeros();
225                return Some((self.current_offset, bit_pos));
226            }
227
228            self.current_chunk = self.iter.next()?;
229            self.current_offset += 64;
230        }
231    }
232}
233
234impl Iterator for BitSliceIterator<'_> {
235    type Item = (usize, usize);
236
237    #[inline]
238    fn next(&mut self) -> Option<Self::Item> {
239        // Used as termination condition
240        if self.len == 0 {
241            return None;
242        }
243
244        let (start_chunk, start_bit) = self.advance_to_set_bit()?;
245
246        // Set bits up to start
247        self.current_chunk |= (1 << start_bit) - 1;
248
249        loop {
250            if self.current_chunk != u64::MAX {
251                // Find the index of the first 0
252                let end_bit = self.current_chunk.trailing_ones();
253
254                // Zero out up to end_bit
255                self.current_chunk &= !((1 << end_bit) - 1);
256
257                return Some((
258                    (start_chunk + start_bit as i64) as usize,
259                    (self.current_offset + end_bit as i64) as usize,
260                ));
261            }
262
263            match self.iter.next() {
264                Some(next) => {
265                    self.current_chunk = next;
266                    self.current_offset += 64;
267                }
268                None => {
269                    return Some((
270                        (start_chunk + start_bit as i64) as usize,
271                        std::mem::replace(&mut self.len, 0),
272                    ));
273                }
274            }
275        }
276    }
277}
278
279/// An iterator of `usize` whose index in a provided bitmask is true
280///
281/// This provides the best performance on most masks, apart from those which contain
282/// large runs and therefore favour [`BitSliceIterator`]
283#[derive(Debug)]
284pub struct BitIndexIterator<'a> {
285    current_chunk: u64,
286    chunk_offset: i64,
287    iter: UnalignedBitChunkIterator<'a>,
288}
289
290impl<'a> BitIndexIterator<'a> {
291    /// Create a new [`BitIndexIterator`] from the provide `buffer`,
292    /// and `offset` and `len` in bits
293    pub fn new(buffer: &'a [u8], offset: usize, len: usize) -> Self {
294        let chunks = UnalignedBitChunk::new(buffer, offset, len);
295        let mut iter = chunks.iter();
296
297        let current_chunk = iter.next().unwrap_or(0);
298        let chunk_offset = -(chunks.lead_padding() as i64);
299
300        Self {
301            current_chunk,
302            chunk_offset,
303            iter,
304        }
305    }
306}
307
308impl Iterator for BitIndexIterator<'_> {
309    type Item = usize;
310
311    #[inline(always)]
312    fn next(&mut self) -> Option<Self::Item> {
313        loop {
314            if self.current_chunk != 0 {
315                let bit_pos = self.current_chunk.trailing_zeros();
316                self.current_chunk &= self.current_chunk - 1;
317                return Some((self.chunk_offset + bit_pos as i64) as usize);
318            }
319
320            self.current_chunk = self.iter.next()?;
321            self.chunk_offset += 64;
322        }
323    }
324}
325
326/// An iterator of u32 whose index in a provided bitmask is true
327/// Respects arbitrary offsets and slice lead/trail padding exactly like BitIndexIterator
328#[derive(Debug)]
329pub struct BitIndexU32Iterator<'a> {
330    curr: u64,
331    chunk_offset: i64,
332    iter: UnalignedBitChunkIterator<'a>,
333}
334
335impl<'a> BitIndexU32Iterator<'a> {
336    /// Create a new [BitIndexU32Iterator] from the provided buffer,
337    /// offset and len in bits.
338    pub fn new(buffer: &'a [u8], offset: usize, len: usize) -> Self {
339        // Build the aligned chunks (including prefix/suffix masked)
340        let chunks = UnalignedBitChunk::new(buffer, offset, len);
341        let mut iter = chunks.iter();
342
343        // First 64-bit word (masked for lead padding), or 0 if empty
344        let curr = iter.next().unwrap_or(0);
345        // Negative lead padding ensures the first bit in curr maps to index 0
346        let chunk_offset = -(chunks.lead_padding() as i64);
347
348        Self {
349            curr,
350            chunk_offset,
351            iter,
352        }
353    }
354}
355
356impl Iterator for BitIndexU32Iterator<'_> {
357    type Item = u32;
358
359    #[inline(always)]
360    fn next(&mut self) -> Option<u32> {
361        loop {
362            if self.curr != 0 {
363                // Position of least-significant set bit
364                let tz = self.curr.trailing_zeros();
365                // Clear that bit
366                self.curr &= self.curr - 1;
367                // Return global index = chunk_offset + tz
368                return Some((self.chunk_offset + tz as i64) as u32);
369            }
370            // Advance to next 64-bit chunk
371            let next_chunk = self.iter.next()?;
372            // Move offset forward by 64 bits
373            self.chunk_offset += 64;
374            self.curr = next_chunk;
375        }
376    }
377}
378
379/// Calls the provided closure for each index in the provided null mask that is set,
380/// using an adaptive strategy based on the null count
381///
382/// Ideally this would be encapsulated in an [`Iterator`] that would determine the optimal
383/// strategy up front, and then yield indexes based on this.
384///
385/// Unfortunately, external iteration based on the resulting [`Iterator`] would match the strategy
386/// variant on each call to [`Iterator::next`], and LLVM generally cannot eliminate this.
387///
388/// One solution to this might be internal iteration, e.g. [`Iterator::try_fold`], however,
389/// it is currently [not possible] to override this for custom iterators in stable Rust.
390///
391/// As such this is the next best option
392///
393/// [not possible]: https://github.com/rust-lang/rust/issues/69595
394#[inline]
395pub fn try_for_each_valid_idx<E, F: FnMut(usize) -> Result<(), E>>(
396    len: usize,
397    offset: usize,
398    null_count: usize,
399    nulls: Option<&[u8]>,
400    f: F,
401) -> Result<(), E> {
402    let valid_count = len - null_count;
403
404    if valid_count == len {
405        (0..len).try_for_each(f)
406    } else if null_count != len {
407        BitIndexIterator::new(nulls.unwrap(), offset, len).try_for_each(f)
408    } else {
409        Ok(())
410    }
411}
412
413// Note: further tests located in arrow_select::filter module
414
415#[cfg(test)]
416mod tests {
417    use super::*;
418    use crate::BooleanBuffer;
419    use rand::rngs::StdRng;
420    use rand::{RngExt, SeedableRng};
421    use std::fmt::Debug;
422    use std::iter::Copied;
423    use std::slice::Iter;
424
425    #[test]
426    fn test_bit_iterator_size_hint() {
427        let mut b = BitIterator::new(&[0b00000011], 0, 2);
428        assert_eq!(
429            b.size_hint(),
430            (2, Some(2)),
431            "Expected size_hint to be (2, Some(2))"
432        );
433
434        b.next();
435        assert_eq!(
436            b.size_hint(),
437            (1, Some(1)),
438            "Expected size_hint to be (1, Some(1)) after one bit consumed"
439        );
440
441        b.next();
442        assert_eq!(
443            b.size_hint(),
444            (0, Some(0)),
445            "Expected size_hint to be (0, Some(0)) after all bits consumed"
446        );
447    }
448
449    #[test]
450    fn test_bit_iterator() {
451        let mask = &[0b00010010, 0b00100011, 0b00000101, 0b00010001, 0b10010011];
452        let actual: Vec<_> = BitIterator::new(mask, 0, 5).collect();
453        assert_eq!(actual, &[false, true, false, false, true]);
454
455        let actual: Vec<_> = BitIterator::new(mask, 4, 5).collect();
456        assert_eq!(actual, &[true, false, false, false, true]);
457
458        let actual: Vec<_> = BitIterator::new(mask, 12, 14).collect();
459        assert_eq!(
460            actual,
461            &[
462                false, true, false, false, true, false, true, false, false, false, false, false,
463                true, false
464            ]
465        );
466
467        assert_eq!(BitIterator::new(mask, 0, 0).count(), 0);
468        assert_eq!(BitIterator::new(mask, 40, 0).count(), 0);
469    }
470
471    #[test]
472    #[should_panic(expected = "BitIterator buffer too small, expected 3 got 2")]
473    fn test_bit_iterator_bounds() {
474        let mask = &[223, 23];
475        BitIterator::new(mask, 17, 0);
476    }
477
478    #[test]
479    fn test_bit_index_u32_iterator_basic() {
480        let mask = &[0b00010010, 0b00100011];
481
482        let result: Vec<u32> = BitIndexU32Iterator::new(mask, 0, 16).collect();
483        let expected: Vec<u32> = BitIndexIterator::new(mask, 0, 16)
484            .map(|i| i as u32)
485            .collect();
486        assert_eq!(result, expected);
487
488        let result: Vec<u32> = BitIndexU32Iterator::new(mask, 4, 8).collect();
489        let expected: Vec<u32> = BitIndexIterator::new(mask, 4, 8)
490            .map(|i| i as u32)
491            .collect();
492        assert_eq!(result, expected);
493
494        let result: Vec<u32> = BitIndexU32Iterator::new(mask, 10, 4).collect();
495        let expected: Vec<u32> = BitIndexIterator::new(mask, 10, 4)
496            .map(|i| i as u32)
497            .collect();
498        assert_eq!(result, expected);
499
500        let result: Vec<u32> = BitIndexU32Iterator::new(mask, 0, 0).collect();
501        let expected: Vec<u32> = BitIndexIterator::new(mask, 0, 0)
502            .map(|i| i as u32)
503            .collect();
504        assert_eq!(result, expected);
505    }
506
507    #[test]
508    fn test_bit_index_u32_iterator_all_set() {
509        let mask = &[0xFF, 0xFF];
510        let result: Vec<u32> = BitIndexU32Iterator::new(mask, 0, 16).collect();
511        let expected: Vec<u32> = BitIndexIterator::new(mask, 0, 16)
512            .map(|i| i as u32)
513            .collect();
514        assert_eq!(result, expected);
515    }
516
517    #[test]
518    fn test_bit_index_u32_iterator_none_set() {
519        let mask = &[0x00, 0x00];
520        let result: Vec<u32> = BitIndexU32Iterator::new(mask, 0, 16).collect();
521        let expected: Vec<u32> = BitIndexIterator::new(mask, 0, 16)
522            .map(|i| i as u32)
523            .collect();
524        assert_eq!(result, expected);
525    }
526
527    #[test]
528    fn test_bit_index_u32_cross_chunk() {
529        let mut buf = vec![0u8; 16];
530        for bit in 60..68 {
531            let byte = (bit / 8) as usize;
532            let bit_in_byte = bit % 8;
533            buf[byte] |= 1 << bit_in_byte;
534        }
535        let offset = 58;
536        let len = 10;
537
538        let result: Vec<u32> = BitIndexU32Iterator::new(&buf, offset, len).collect();
539        let expected: Vec<u32> = BitIndexIterator::new(&buf, offset, len)
540            .map(|i| i as u32)
541            .collect();
542        assert_eq!(result, expected);
543    }
544
545    #[test]
546    fn test_bit_index_u32_unaligned_offset() {
547        let mask = &[0b0110_1100, 0b1010_0000];
548        let offset = 2;
549        let len = 12;
550
551        let result: Vec<u32> = BitIndexU32Iterator::new(mask, offset, len).collect();
552        let expected: Vec<u32> = BitIndexIterator::new(mask, offset, len)
553            .map(|i| i as u32)
554            .collect();
555        assert_eq!(result, expected);
556    }
557
558    #[test]
559    fn test_bit_index_u32_long_all_set() {
560        let len = 200;
561        let num_bytes = len / 8 + usize::from(len % 8 != 0);
562        let bytes = vec![0xFFu8; num_bytes];
563
564        let result: Vec<u32> = BitIndexU32Iterator::new(&bytes, 0, len).collect();
565        let expected: Vec<u32> = BitIndexIterator::new(&bytes, 0, len)
566            .map(|i| i as u32)
567            .collect();
568        assert_eq!(result, expected);
569    }
570
571    #[test]
572    fn test_bit_index_u32_none_set() {
573        let len = 50;
574        let num_bytes = len / 8 + usize::from(len % 8 != 0);
575        let bytes = vec![0u8; num_bytes];
576
577        let result: Vec<u32> = BitIndexU32Iterator::new(&bytes, 0, len).collect();
578        let expected: Vec<u32> = BitIndexIterator::new(&bytes, 0, len)
579            .map(|i| i as u32)
580            .collect();
581        assert_eq!(result, expected);
582    }
583
584    trait SharedBetweenBitIteratorAndSliceIter:
585        ExactSizeIterator<Item = bool> + DoubleEndedIterator<Item = bool>
586    {
587    }
588    impl<T: ?Sized + ExactSizeIterator<Item = bool> + DoubleEndedIterator<Item = bool>>
589        SharedBetweenBitIteratorAndSliceIter for T
590    {
591    }
592
593    fn get_bit_iterator_cases() -> impl Iterator<Item = (BooleanBuffer, Vec<bool>)> {
594        let mut rng = StdRng::seed_from_u64(42);
595
596        [0, 1, 6, 8, 100, 164]
597            .map(|len| {
598                let source = (0..len).map(|_| rng.random_bool(0.5)).collect::<Vec<_>>();
599
600                (BooleanBuffer::from(source.as_slice()), source)
601            })
602            .into_iter()
603    }
604
605    fn setup_and_assert(
606        setup_iters: impl Fn(&mut dyn SharedBetweenBitIteratorAndSliceIter),
607        assert_fn: impl Fn(BitIterator, Copied<Iter<bool>>),
608    ) {
609        for (boolean_buffer, source) in get_bit_iterator_cases() {
610            // Not using `boolean_buffer.iter()` in case the implementation change to not call BitIterator internally
611            // in which case the test would not test what it intends to test
612            let mut actual = BitIterator::new(boolean_buffer.values(), 0, boolean_buffer.len());
613            let mut expected = source.iter().copied();
614
615            setup_iters(&mut actual);
616            setup_iters(&mut expected);
617
618            assert_fn(actual, expected);
619        }
620    }
621
622    /// Trait representing an operation on a BitIterator
623    /// that can be compared against a slice iterator
624    trait BitIteratorOp {
625        /// What the operation returns (e.g. Option<bool> for last/max, usize for count, etc)
626        type Output: PartialEq + Debug;
627
628        /// The name of the operation, used for error messages
629        const NAME: &'static str;
630
631        /// Get the value of the operation for the provided iterator
632        /// This will be either a BitIterator or a slice iterator to make sure they produce the same result
633        fn get_value<T: SharedBetweenBitIteratorAndSliceIter>(iter: T) -> Self::Output;
634    }
635
636    /// Helper function that will assert that the provided operation
637    /// produces the same result for both BitIterator and slice iterator
638    /// under various consumption patterns (e.g. some calls to next/next_back/consume_all/etc)
639    fn assert_bit_iterator_cases<O: BitIteratorOp>() {
640        setup_and_assert(
641            |_iter: &mut dyn SharedBetweenBitIteratorAndSliceIter| {},
642            |actual, expected| {
643                let current_iterator_values: Vec<bool> = expected.clone().collect();
644                assert_eq!(
645                    O::get_value(actual),
646                    O::get_value(expected),
647                    "Failed on op {} for new iter (left actual, right expected) ({current_iterator_values:?})",
648                    O::NAME
649                );
650            },
651        );
652
653        setup_and_assert(
654            |iter: &mut dyn SharedBetweenBitIteratorAndSliceIter| {
655                iter.next();
656            },
657            |actual, expected| {
658                let current_iterator_values: Vec<bool> = expected.clone().collect();
659
660                assert_eq!(
661                    O::get_value(actual),
662                    O::get_value(expected),
663                    "Failed on op {} for new iter after consuming 1 element from the start (left actual, right expected) ({current_iterator_values:?})",
664                    O::NAME
665                );
666            },
667        );
668
669        setup_and_assert(
670            |iter: &mut dyn SharedBetweenBitIteratorAndSliceIter| {
671                iter.next_back();
672            },
673            |actual, expected| {
674                let current_iterator_values: Vec<bool> = expected.clone().collect();
675
676                assert_eq!(
677                    O::get_value(actual),
678                    O::get_value(expected),
679                    "Failed on op {} for new iter after consuming 1 element from the end (left actual, right expected) ({current_iterator_values:?})",
680                    O::NAME
681                );
682            },
683        );
684
685        setup_and_assert(
686            |iter: &mut dyn SharedBetweenBitIteratorAndSliceIter| {
687                iter.next();
688                iter.next_back();
689            },
690            |actual, expected| {
691                let current_iterator_values: Vec<bool> = expected.clone().collect();
692
693                assert_eq!(
694                    O::get_value(actual),
695                    O::get_value(expected),
696                    "Failed on op {} for new iter after consuming 1 element from start and end (left actual, right expected) ({current_iterator_values:?})",
697                    O::NAME
698                );
699            },
700        );
701
702        setup_and_assert(
703            |iter: &mut dyn SharedBetweenBitIteratorAndSliceIter| {
704                while iter.len() > 1 {
705                    iter.next();
706                }
707            },
708            |actual, expected| {
709                let current_iterator_values: Vec<bool> = expected.clone().collect();
710
711                assert_eq!(
712                    O::get_value(actual),
713                    O::get_value(expected),
714                    "Failed on op {} for new iter after consuming all from the start but 1 (left actual, right expected) ({current_iterator_values:?})",
715                    O::NAME
716                );
717            },
718        );
719
720        setup_and_assert(
721            |iter: &mut dyn SharedBetweenBitIteratorAndSliceIter| {
722                while iter.len() > 1 {
723                    iter.next_back();
724                }
725            },
726            |actual, expected| {
727                let current_iterator_values: Vec<bool> = expected.clone().collect();
728
729                assert_eq!(
730                    O::get_value(actual),
731                    O::get_value(expected),
732                    "Failed on op {} for new iter after consuming all from the end but 1 (left actual, right expected) ({current_iterator_values:?})",
733                    O::NAME
734                );
735            },
736        );
737
738        setup_and_assert(
739            |iter: &mut dyn SharedBetweenBitIteratorAndSliceIter| {
740                while iter.next().is_some() {}
741            },
742            |actual, expected| {
743                let current_iterator_values: Vec<bool> = expected.clone().collect();
744
745                assert_eq!(
746                    O::get_value(actual),
747                    O::get_value(expected),
748                    "Failed on op {} for new iter after consuming all from the start (left actual, right expected) ({current_iterator_values:?})",
749                    O::NAME
750                );
751            },
752        );
753
754        setup_and_assert(
755            |iter: &mut dyn SharedBetweenBitIteratorAndSliceIter| {
756                while iter.next_back().is_some() {}
757            },
758            |actual, expected| {
759                let current_iterator_values: Vec<bool> = expected.clone().collect();
760
761                assert_eq!(
762                    O::get_value(actual),
763                    O::get_value(expected),
764                    "Failed on op {} for new iter after consuming all from the end (left actual, right expected) ({current_iterator_values:?})",
765                    O::NAME
766                );
767            },
768        );
769    }
770
771    #[test]
772    fn assert_bit_iterator_count() {
773        struct CountOp;
774
775        impl BitIteratorOp for CountOp {
776            type Output = usize;
777            const NAME: &'static str = "count";
778
779            fn get_value<T: SharedBetweenBitIteratorAndSliceIter>(iter: T) -> Self::Output {
780                iter.count()
781            }
782        }
783
784        assert_bit_iterator_cases::<CountOp>()
785    }
786
787    #[test]
788    fn assert_bit_iterator_last() {
789        struct LastOp;
790
791        impl BitIteratorOp for LastOp {
792            type Output = Option<bool>;
793            const NAME: &'static str = "last";
794
795            fn get_value<T: SharedBetweenBitIteratorAndSliceIter>(iter: T) -> Self::Output {
796                iter.last()
797            }
798        }
799
800        assert_bit_iterator_cases::<LastOp>()
801    }
802
803    #[test]
804    fn assert_bit_iterator_max() {
805        struct MaxOp;
806
807        impl BitIteratorOp for MaxOp {
808            type Output = Option<bool>;
809            const NAME: &'static str = "max";
810
811            fn get_value<T: SharedBetweenBitIteratorAndSliceIter>(iter: T) -> Self::Output {
812                iter.max()
813            }
814        }
815
816        assert_bit_iterator_cases::<MaxOp>()
817    }
818
819    #[test]
820    fn assert_bit_iterator_nth_0() {
821        struct NthOp<const BACK: bool>;
822
823        impl<const BACK: bool> BitIteratorOp for NthOp<BACK> {
824            type Output = Option<bool>;
825            const NAME: &'static str = if BACK { "nth_back(0)" } else { "nth(0)" };
826
827            fn get_value<T: SharedBetweenBitIteratorAndSliceIter>(mut iter: T) -> Self::Output {
828                if BACK { iter.nth_back(0) } else { iter.nth(0) }
829            }
830        }
831
832        assert_bit_iterator_cases::<NthOp<false>>();
833        assert_bit_iterator_cases::<NthOp<true>>();
834    }
835
836    #[test]
837    fn assert_bit_iterator_nth_1() {
838        struct NthOp<const BACK: bool>;
839
840        impl<const BACK: bool> BitIteratorOp for NthOp<BACK> {
841            type Output = Option<bool>;
842            const NAME: &'static str = if BACK { "nth_back(1)" } else { "nth(1)" };
843
844            fn get_value<T: SharedBetweenBitIteratorAndSliceIter>(mut iter: T) -> Self::Output {
845                if BACK { iter.nth_back(1) } else { iter.nth(1) }
846            }
847        }
848
849        assert_bit_iterator_cases::<NthOp<false>>();
850        assert_bit_iterator_cases::<NthOp<true>>();
851    }
852
853    #[test]
854    fn assert_bit_iterator_nth_after_end() {
855        struct NthOp<const BACK: bool>;
856
857        impl<const BACK: bool> BitIteratorOp for NthOp<BACK> {
858            type Output = Option<bool>;
859            const NAME: &'static str = if BACK {
860                "nth_back(iter.len() + 1)"
861            } else {
862                "nth(iter.len() + 1)"
863            };
864
865            fn get_value<T: SharedBetweenBitIteratorAndSliceIter>(mut iter: T) -> Self::Output {
866                if BACK {
867                    iter.nth_back(iter.len() + 1)
868                } else {
869                    iter.nth(iter.len() + 1)
870                }
871            }
872        }
873
874        assert_bit_iterator_cases::<NthOp<false>>();
875        assert_bit_iterator_cases::<NthOp<true>>();
876    }
877
878    #[test]
879    fn assert_bit_iterator_nth_len() {
880        struct NthOp<const BACK: bool>;
881
882        impl<const BACK: bool> BitIteratorOp for NthOp<BACK> {
883            type Output = Option<bool>;
884            const NAME: &'static str = if BACK {
885                "nth_back(iter.len())"
886            } else {
887                "nth(iter.len())"
888            };
889
890            fn get_value<T: SharedBetweenBitIteratorAndSliceIter>(mut iter: T) -> Self::Output {
891                if BACK {
892                    iter.nth_back(iter.len())
893                } else {
894                    iter.nth(iter.len())
895                }
896            }
897        }
898
899        assert_bit_iterator_cases::<NthOp<false>>();
900        assert_bit_iterator_cases::<NthOp<true>>();
901    }
902
903    #[test]
904    fn assert_bit_iterator_nth_last() {
905        struct NthOp<const BACK: bool>;
906
907        impl<const BACK: bool> BitIteratorOp for NthOp<BACK> {
908            type Output = Option<bool>;
909            const NAME: &'static str = if BACK {
910                "nth_back(iter.len().saturating_sub(1))"
911            } else {
912                "nth(iter.len().saturating_sub(1))"
913            };
914
915            fn get_value<T: SharedBetweenBitIteratorAndSliceIter>(mut iter: T) -> Self::Output {
916                if BACK {
917                    iter.nth_back(iter.len().saturating_sub(1))
918                } else {
919                    iter.nth(iter.len().saturating_sub(1))
920                }
921            }
922        }
923
924        assert_bit_iterator_cases::<NthOp<false>>();
925        assert_bit_iterator_cases::<NthOp<true>>();
926    }
927
928    #[test]
929    fn assert_bit_iterator_nth_and_reuse() {
930        setup_and_assert(
931            |_| {},
932            |actual, expected| {
933                {
934                    let mut actual = actual.clone();
935                    let mut expected = expected.clone();
936                    for _ in 0..expected.len() {
937                        #[expect(clippy::iter_nth_zero)]
938                        let actual_val = actual.nth(0);
939                        #[expect(clippy::iter_nth_zero)]
940                        let expected_val = expected.nth(0);
941                        assert_eq!(actual_val, expected_val, "Failed on nth(0)");
942                    }
943                }
944
945                {
946                    let mut actual = actual.clone();
947                    let mut expected = expected.clone();
948                    for _ in 0..expected.len() {
949                        let actual_val = actual.nth(1);
950                        let expected_val = expected.nth(1);
951                        assert_eq!(actual_val, expected_val, "Failed on nth(1)");
952                    }
953                }
954
955                {
956                    let mut actual = actual.clone();
957                    let mut expected = expected.clone();
958                    for _ in 0..expected.len() {
959                        let actual_val = actual.nth(2);
960                        let expected_val = expected.nth(2);
961                        assert_eq!(actual_val, expected_val, "Failed on nth(2)");
962                    }
963                }
964            },
965        );
966    }
967
968    #[test]
969    fn assert_bit_iterator_nth_back_and_reuse() {
970        setup_and_assert(
971            |_| {},
972            |actual, expected| {
973                {
974                    let mut actual = actual.clone();
975                    let mut expected = expected.clone();
976                    for _ in 0..expected.len() {
977                        let actual_val = actual.nth_back(0);
978                        let expected_val = expected.nth_back(0);
979                        assert_eq!(actual_val, expected_val, "Failed on nth_back(0)");
980                    }
981                }
982
983                {
984                    let mut actual = actual.clone();
985                    let mut expected = expected.clone();
986                    for _ in 0..expected.len() {
987                        let actual_val = actual.nth_back(1);
988                        let expected_val = expected.nth_back(1);
989                        assert_eq!(actual_val, expected_val, "Failed on nth_back(1)");
990                    }
991                }
992
993                {
994                    let mut actual = actual.clone();
995                    let mut expected = expected.clone();
996                    for _ in 0..expected.len() {
997                        let actual_val = actual.nth_back(2);
998                        let expected_val = expected.nth_back(2);
999                        assert_eq!(actual_val, expected_val, "Failed on nth_back(2)");
1000                    }
1001                }
1002            },
1003        );
1004    }
1005}