Skip to main content

lance_select/
mask.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3
4use std::collections::HashSet;
5use std::io::Write;
6use std::ops::{Range, RangeBounds, RangeInclusive};
7use std::{collections::BTreeMap, io::Read};
8
9use arrow_array::{Array, BinaryArray, GenericBinaryArray};
10use arrow_buffer::{Buffer, NullBuffer, OffsetBuffer};
11use byteorder::{ReadBytesExt, WriteBytesExt};
12use itertools::Itertools;
13use lance_core::deepsize::DeepSizeOf;
14use roaring::{MultiOps, RoaringBitmap, RoaringTreemap};
15
16use lance_core::cache::{CacheCodecImpl, CacheEntryReader, CacheEntryWriter};
17use lance_core::utils::address::RowAddress;
18use lance_core::{Error, Result};
19
20mod nullable;
21
22pub use nullable::{NullableRowAddrMask, NullableRowAddrSet};
23
24/// A mask that selects or deselects rows based on an allow-list or block-list.
25#[derive(Clone, Debug, DeepSizeOf, PartialEq)]
26pub enum RowAddrMask {
27    AllowList(RowAddrTreeMap),
28    BlockList(RowAddrTreeMap),
29}
30
31impl Default for RowAddrMask {
32    fn default() -> Self {
33        // Empty block list means all rows are allowed
34        Self::BlockList(RowAddrTreeMap::new())
35    }
36}
37
38impl RowAddrMask {
39    // Create a mask allowing all rows, this is an alias for [default]
40    pub fn all_rows() -> Self {
41        Self::default()
42    }
43
44    // Create a mask that doesn't allow anything
45    pub fn allow_nothing() -> Self {
46        Self::AllowList(RowAddrTreeMap::new())
47    }
48
49    // Create a mask from an allow list
50    pub fn from_allowed(allow_list: RowAddrTreeMap) -> Self {
51        Self::AllowList(allow_list)
52    }
53
54    // Create a mask from a block list
55    pub fn from_block(block_list: RowAddrTreeMap) -> Self {
56        Self::BlockList(block_list)
57    }
58
59    pub fn block_list(&self) -> Option<&RowAddrTreeMap> {
60        match self {
61            Self::BlockList(block_list) => Some(block_list),
62            _ => None,
63        }
64    }
65
66    pub fn allow_list(&self) -> Option<&RowAddrTreeMap> {
67        match self {
68            Self::AllowList(allow_list) => Some(allow_list),
69            _ => None,
70        }
71    }
72
73    /// True if the row_id is selected by the mask, false otherwise
74    pub fn selected(&self, row_id: u64) -> bool {
75        match self {
76            Self::AllowList(allow_list) => allow_list.contains(row_id),
77            Self::BlockList(block_list) => !block_list.contains(row_id),
78        }
79    }
80
81    /// True if every row_id is selected. Lets callers (e.g. the FTS wand
82    /// loop) skip per-row mask checks entirely, which in turn lets the
83    /// deferred-row_id scoring path skip loading the row_id column.
84    pub fn is_select_all(&self) -> bool {
85        matches!(self, Self::BlockList(b) if b.is_empty())
86    }
87
88    /// Returns whether this mask selects every row in `rows`.
89    pub fn selects_all(&self, rows: &RowAddrTreeMap) -> bool {
90        match self {
91            Self::AllowList(allow_list) => (rows.clone() - allow_list).is_empty(),
92            Self::BlockList(block_list) => (rows.clone() & block_list).is_empty(),
93        }
94    }
95
96    /// Return the indices of the input row ids that were valid
97    pub fn selected_indices<'a>(&self, row_ids: impl Iterator<Item = &'a u64> + 'a) -> Vec<u64> {
98        row_ids
99            .enumerate()
100            .filter_map(|(idx, row_id)| {
101                if self.selected(*row_id) {
102                    Some(idx as u64)
103                } else {
104                    None
105                }
106            })
107            .collect()
108    }
109
110    /// Also block the given addrs
111    pub fn also_block(self, block_list: RowAddrTreeMap) -> Self {
112        match self {
113            Self::AllowList(allow_list) => Self::AllowList(allow_list - block_list),
114            Self::BlockList(existing) => Self::BlockList(existing | block_list),
115        }
116    }
117
118    /// Build a mask from serialized [`RowAddrTreeMap`] payloads.
119    ///
120    /// `allow` selects rows, `block` excludes them; each is the output of
121    /// [`RowAddrTreeMap::serialize_into`]. Returns `None` when neither is given,
122    /// which callers read as "no mask" rather than "select nothing".
123    ///
124    /// Bytes rather than treemaps on purpose: a caller living in a different
125    /// dynamically-linked extension module has its own copy of these Rust types
126    /// and cannot hand one over, but both sides agree on this encoding.
127    pub fn from_serialized_parts(
128        allow: Option<&[u8]>,
129        block: Option<&[u8]>,
130    ) -> Result<Option<Self>> {
131        // Name the offending side: the underlying failure is a bare "failed to
132        // fill whole buffer", which tells a caller holding two blobs nothing.
133        fn decode(bytes: &[u8], which: &str) -> Result<RowAddrTreeMap> {
134            RowAddrTreeMap::deserialize_from(bytes).map_err(|e| {
135                Error::invalid_input(format!(
136                    "row address {which} is not a serialized RowAddrTreeMap: {e}"
137                ))
138            })
139        }
140        let allow = allow.map(|b| decode(b, "allowlist")).transpose()?;
141        let block = block.map(|b| decode(b, "blocklist")).transpose()?;
142        Ok(match (allow, block) {
143            (Some(allow), Some(block)) => Some(Self::from_allowed(allow).also_block(block)),
144            (Some(allow), None) => Some(Self::from_allowed(allow)),
145            (None, Some(block)) => Some(Self::from_block(block)),
146            (None, None) => None,
147        })
148    }
149
150    /// Intersect two masks: a row survives only if both select it.
151    ///
152    /// Lets a planner apply a caller-supplied mask at one boundary rather than
153    /// at every branch that produces rows, which is how branches get missed.
154    pub fn intersect(self, other: Self) -> Self {
155        match (self, other) {
156            (Self::AllowList(a), Self::AllowList(b)) => Self::AllowList(a & b),
157            (Self::AllowList(a), Self::BlockList(b)) => Self::AllowList(a).also_block(b),
158            (Self::BlockList(a), Self::AllowList(b)) => Self::AllowList(b).also_block(a),
159            (Self::BlockList(a), Self::BlockList(b)) => Self::BlockList(a | b),
160        }
161    }
162
163    /// Also allow the given addrs
164    pub fn also_allow(self, allow_list: RowAddrTreeMap) -> Self {
165        match self {
166            Self::AllowList(existing) => Self::AllowList(existing | allow_list),
167            Self::BlockList(block_list) => Self::BlockList(block_list - allow_list),
168        }
169    }
170
171    /// Convert a mask into an arrow array
172    ///
173    /// A row addr mask is not very arrow-compatible.  We can't make it a batch with
174    /// two columns because the block list and allow list will have different lengths.  Also,
175    /// there is no Arrow type for compressed bitmaps.
176    ///
177    /// However, we need to shove it into some kind of Arrow container to pass it along the
178    /// datafusion stream.  Perhaps, in the future, we can add row addr masks as first class
179    /// types in datafusion, and this can be passed along as a mask / selection vector.
180    ///
181    /// We serialize this as a variable length binary array with two items.  The first item
182    /// is the block list and the second item is the allow list.
183    pub fn into_arrow(&self) -> Result<BinaryArray> {
184        // NOTE: This serialization format must be stable as it is used in IPC.
185        let (block_list, allow_list) = match self {
186            Self::AllowList(allow_list) => (None, Some(allow_list)),
187            Self::BlockList(block_list) => (Some(block_list), None),
188        };
189
190        let block_list_length = block_list
191            .as_ref()
192            .map(|bl| bl.serialized_size())
193            .unwrap_or(0);
194        let allow_list_length = allow_list
195            .as_ref()
196            .map(|al| al.serialized_size())
197            .unwrap_or(0);
198        let lengths = vec![block_list_length, allow_list_length];
199        let offsets = OffsetBuffer::from_lengths(lengths);
200        let mut value_bytes = vec![0; block_list_length + allow_list_length];
201        let mut validity = vec![false, false];
202        if let Some(block_list) = &block_list {
203            validity[0] = true;
204            block_list.serialize_into(&mut value_bytes[0..])?;
205        }
206        if let Some(allow_list) = &allow_list {
207            validity[1] = true;
208            allow_list.serialize_into(&mut value_bytes[block_list_length..])?;
209        }
210        let values = Buffer::from(value_bytes);
211        let nulls = NullBuffer::from(validity);
212        Ok(BinaryArray::try_new(offsets, values, Some(nulls))?)
213    }
214
215    /// Deserialize a row address mask from Arrow
216    pub fn from_arrow(array: &GenericBinaryArray<i32>) -> Result<Self> {
217        let block_list = if array.is_null(0) {
218            None
219        } else {
220            Some(RowAddrTreeMap::deserialize_from(array.value(0)))
221        }
222        .transpose()?;
223
224        let allow_list = if array.is_null(1) {
225            None
226        } else {
227            Some(RowAddrTreeMap::deserialize_from(array.value(1)))
228        }
229        .transpose()?;
230
231        let res = match (block_list, allow_list) {
232            (Some(bl), None) => Self::BlockList(bl),
233            (None, Some(al)) => Self::AllowList(al),
234            (Some(block), Some(allow)) => Self::AllowList(allow).also_block(block),
235            (None, None) => Self::all_rows(),
236        };
237        Ok(res)
238    }
239
240    /// Return the maximum number of row addresses that could be selected by this mask
241    ///
242    /// Will be None if this is a BlockList (unbounded)
243    pub fn max_len(&self) -> Option<u64> {
244        match self {
245            Self::AllowList(selection) => selection.len(),
246            Self::BlockList(_) => None,
247        }
248    }
249
250    /// Iterate over the row addresses that are selected by the mask
251    ///
252    /// This is only possible if this is an AllowList and the maps don't contain
253    /// any "full fragment" blocks.
254    pub fn iter_addrs(&self) -> Option<Box<dyn Iterator<Item = RowAddress> + '_>> {
255        match self {
256            Self::AllowList(allow_list) => {
257                if let Some(allow_iter) = allow_list.row_addrs() {
258                    Some(Box::new(allow_iter))
259                } else {
260                    None
261                }
262            }
263            Self::BlockList(_) => None, // Can't iterate over block list
264        }
265    }
266}
267
268impl std::ops::Not for RowAddrMask {
269    type Output = Self;
270
271    fn not(self) -> Self::Output {
272        match self {
273            Self::AllowList(allow_list) => Self::BlockList(allow_list),
274            Self::BlockList(block_list) => Self::AllowList(block_list),
275        }
276    }
277}
278
279impl std::ops::BitAnd for RowAddrMask {
280    type Output = Self;
281
282    fn bitand(self, rhs: Self) -> Self::Output {
283        match (self, rhs) {
284            (Self::AllowList(a), Self::AllowList(b)) => Self::AllowList(a & b),
285            (Self::AllowList(allow), Self::BlockList(block))
286            | (Self::BlockList(block), Self::AllowList(allow)) => Self::AllowList(allow - block),
287            (Self::BlockList(a), Self::BlockList(b)) => Self::BlockList(a | b),
288        }
289    }
290}
291
292impl std::ops::BitOr for RowAddrMask {
293    type Output = Self;
294
295    fn bitor(self, rhs: Self) -> Self::Output {
296        match (self, rhs) {
297            (Self::AllowList(a), Self::AllowList(b)) => Self::AllowList(a | b),
298            (Self::AllowList(allow), Self::BlockList(block))
299            | (Self::BlockList(block), Self::AllowList(allow)) => Self::BlockList(block - allow),
300            (Self::BlockList(a), Self::BlockList(b)) => Self::BlockList(a & b),
301        }
302    }
303}
304
305/// Common operations over a set of rows (either row ids or row addresses).
306///
307/// The concrete representation can be address-based (`RowAddrTreeMap`) or
308/// id-based (for example a future `RowIdSet`), but the semantics are the same:
309/// a set of unique rows.
310pub trait RowSetOps: Clone + Sized {
311    /// Logical row handle (`u64` for both row ids and row addresses).
312    type Row;
313
314    /// Returns true if the set is empty.
315    fn is_empty(&self) -> bool;
316
317    /// Returns the number of rows in the set, if it is known.
318    ///
319    /// Implementations that cannot always compute an exact size (for example
320    /// because of "full fragment" markers) should return `None`.
321    fn len(&self) -> Option<u64>;
322
323    /// Remove a value from the row set.
324    fn remove(&mut self, row: Self::Row) -> bool;
325
326    /// Returns whether this set contains the given row.
327    fn contains(&self, row: Self::Row) -> bool;
328
329    /// Returns the union of `other` and init self.
330    fn union_all(other: &[&Self]) -> Self;
331
332    /// Builds a row set from an iterator of rows.
333    fn from_sorted_iter<I>(iter: I) -> Result<Self>
334    where
335        I: IntoIterator<Item = Self::Row>;
336}
337
338/// A collection of row addresses.
339///
340/// Note: For stable row id mode, this may be split into a separate structure in the future.
341///
342/// These row ids may either be stable-style (where they can be an incrementing
343/// u64 sequence) or address style, where they are a fragment id and a row offset.
344/// When address style, this supports setting entire fragments as selected,
345/// without needing to enumerate all the ids in the fragment.
346///
347/// This is similar to a [RoaringTreemap] but it is optimized for the case where
348/// entire fragments are selected or deselected.
349#[derive(Clone, Debug, Default, PartialEq, DeepSizeOf)]
350pub struct RowAddrTreeMap {
351    /// The contents of the set. If there is a pair (k, Full) then the entire
352    /// fragment k is selected. If there is a pair (k, Partial(v)) then the
353    /// fragment k has the selected rows in v.
354    inner: BTreeMap<u32, RowAddrSelection>,
355}
356
357#[derive(Clone, Debug, PartialEq)]
358pub enum RowAddrSelection {
359    Full,
360    Partial(RoaringBitmap),
361}
362
363impl DeepSizeOf for RowAddrSelection {
364    fn deep_size_of_children(&self, _context: &mut lance_core::deepsize::Context) -> usize {
365        match self {
366            Self::Full => 0,
367            Self::Partial(bitmap) => bitmap.serialized_size(),
368        }
369    }
370}
371
372impl RowAddrSelection {
373    fn union_all(selections: &[&Self]) -> Self {
374        let mut is_full = false;
375
376        let res = Self::Partial(
377            selections
378                .iter()
379                .filter_map(|selection| match selection {
380                    Self::Full => {
381                        is_full = true;
382                        None
383                    }
384                    Self::Partial(bitmap) => Some(bitmap),
385                })
386                .union(),
387        );
388
389        if is_full { Self::Full } else { res }
390    }
391}
392
393impl RowSetOps for RowAddrTreeMap {
394    type Row = u64;
395
396    fn is_empty(&self) -> bool {
397        self.inner.is_empty()
398    }
399
400    fn len(&self) -> Option<u64> {
401        self.inner
402            .values()
403            .map(|row_addr_selection| match row_addr_selection {
404                RowAddrSelection::Full => None,
405                RowAddrSelection::Partial(indices) => Some(indices.len()),
406            })
407            .try_fold(0_u64, |acc, next| next.map(|next| next + acc))
408    }
409
410    fn remove(&mut self, row: Self::Row) -> bool {
411        let upper = (row >> 32) as u32;
412        let lower = row as u32;
413        match self.inner.get_mut(&upper) {
414            None => false,
415            Some(RowAddrSelection::Full) => {
416                let mut set = RoaringBitmap::full();
417                set.remove(lower);
418                self.inner.insert(upper, RowAddrSelection::Partial(set));
419                true
420            }
421            Some(RowAddrSelection::Partial(lower_set)) => {
422                let removed = lower_set.remove(lower);
423                if lower_set.is_empty() {
424                    self.inner.remove(&upper);
425                }
426                removed
427            }
428        }
429    }
430
431    fn contains(&self, row: Self::Row) -> bool {
432        let upper = (row >> 32) as u32;
433        let lower = row as u32;
434        match self.inner.get(&upper) {
435            None => false,
436            Some(RowAddrSelection::Full) => true,
437            Some(RowAddrSelection::Partial(fragment_set)) => fragment_set.contains(lower),
438        }
439    }
440
441    fn union_all(other: &[&Self]) -> Self {
442        let mut new_map = BTreeMap::new();
443
444        for map in other {
445            for (fragment, selection) in &map.inner {
446                new_map
447                    .entry(fragment)
448                    // I hate this allocation, but I can't think of a better way
449                    .or_insert_with(|| Vec::with_capacity(other.len()))
450                    .push(selection);
451            }
452        }
453
454        let new_map = new_map
455            .into_iter()
456            .map(|(&fragment, selections)| (fragment, RowAddrSelection::union_all(&selections)))
457            .collect();
458
459        Self { inner: new_map }
460    }
461
462    #[track_caller]
463    fn from_sorted_iter<I>(iter: I) -> Result<Self>
464    where
465        I: IntoIterator<Item = Self::Row>,
466    {
467        let mut iter = iter.into_iter().peekable();
468        let mut inner = BTreeMap::new();
469
470        while let Some(row_id) = iter.peek() {
471            let fragment_id = (row_id >> 32) as u32;
472            let next_bitmap_iter = iter
473                .peeking_take_while(|row_id| (row_id >> 32) as u32 == fragment_id)
474                .map(|row_id| row_id as u32);
475            let Ok(bitmap) = RoaringBitmap::from_sorted_iter(next_bitmap_iter) else {
476                return Err(Error::internal(
477                    "RowAddrTreeMap::from_sorted_iter called with non-sorted input",
478                ));
479            };
480            inner.insert(fragment_id, RowAddrSelection::Partial(bitmap));
481        }
482
483        Ok(Self { inner })
484    }
485}
486
487impl RowAddrTreeMap {
488    /// Create an empty set
489    pub fn new() -> Self {
490        Self::default()
491    }
492
493    /// An iterator of row addrs
494    ///
495    /// If there are any "full fragment" items then this can't be calculated and None
496    /// is returned
497    pub fn row_addrs(&self) -> Option<impl Iterator<Item = RowAddress> + '_> {
498        let inner_iters = self
499            .inner
500            .iter()
501            .filter_map(|(frag_id, row_addr_selection)| match row_addr_selection {
502                RowAddrSelection::Full => None,
503                RowAddrSelection::Partial(bitmap) => Some(
504                    bitmap
505                        .iter()
506                        .map(|row_offset| RowAddress::new_from_parts(*frag_id, row_offset)),
507                ),
508            })
509            .collect::<Vec<_>>();
510        if inner_iters.len() != self.inner.len() {
511            None
512        } else {
513            Some(inner_iters.into_iter().flatten())
514        }
515    }
516
517    /// Insert a single value into the set
518    ///
519    /// Returns true if the value was not already in the set.
520    ///
521    /// ```rust
522    /// use lance_select::{RowAddrTreeMap, RowSetOps};
523    ///
524    /// let mut set = RowAddrTreeMap::new();
525    /// assert_eq!(set.insert(10), true);
526    /// assert_eq!(set.insert(10), false);
527    /// assert_eq!(set.contains(10), true);
528    /// ```
529    pub fn insert(&mut self, value: u64) -> bool {
530        let fragment = (value >> 32) as u32;
531        let row_addr = value as u32;
532        match self.inner.get_mut(&fragment) {
533            None => {
534                let mut set = RoaringBitmap::new();
535                set.insert(row_addr);
536                self.inner.insert(fragment, RowAddrSelection::Partial(set));
537                true
538            }
539            Some(RowAddrSelection::Full) => false,
540            Some(RowAddrSelection::Partial(set)) => set.insert(row_addr),
541        }
542    }
543
544    /// Insert a range of values into the set
545    pub fn insert_range<R: RangeBounds<u64>>(&mut self, range: R) -> u64 {
546        // Separate the start and end into high and low bits.
547        let (mut start_high, mut start_low) = match range.start_bound() {
548            std::ops::Bound::Included(&start) => ((start >> 32) as u32, start as u32),
549            std::ops::Bound::Excluded(&start) => {
550                let start = start.saturating_add(1);
551                ((start >> 32) as u32, start as u32)
552            }
553            std::ops::Bound::Unbounded => (0, 0),
554        };
555
556        let (end_high, end_low) = match range.end_bound() {
557            std::ops::Bound::Included(&end) => ((end >> 32) as u32, end as u32),
558            std::ops::Bound::Excluded(&end) => {
559                let end = end.saturating_sub(1);
560                ((end >> 32) as u32, end as u32)
561            }
562            std::ops::Bound::Unbounded => (u32::MAX, u32::MAX),
563        };
564
565        let mut count = 0;
566
567        while start_high <= end_high {
568            let start = start_low;
569            let end = if start_high == end_high {
570                end_low
571            } else {
572                u32::MAX
573            };
574            let fragment = start_high;
575            match self.inner.get_mut(&fragment) {
576                None => {
577                    let mut set = RoaringBitmap::new();
578                    count += set.insert_range(start..=end);
579                    self.inner.insert(fragment, RowAddrSelection::Partial(set));
580                }
581                Some(RowAddrSelection::Full) => {}
582                Some(RowAddrSelection::Partial(set)) => {
583                    count += set.insert_range(start..=end);
584                }
585            }
586            start_high += 1;
587            start_low = 0;
588        }
589
590        count
591    }
592
593    /// Add a bitmap for a single fragment
594    pub fn insert_bitmap(&mut self, fragment: u32, bitmap: RoaringBitmap) {
595        self.inner
596            .insert(fragment, RowAddrSelection::Partial(bitmap));
597    }
598
599    /// Add a whole fragment to the set
600    pub fn insert_fragment(&mut self, fragment_id: u32) {
601        self.inner.insert(fragment_id, RowAddrSelection::Full);
602    }
603
604    pub fn get_fragment_bitmap(&self, fragment_id: u32) -> Option<&RoaringBitmap> {
605        match self.inner.get(&fragment_id) {
606            None => None,
607            Some(RowAddrSelection::Full) => None,
608            Some(RowAddrSelection::Partial(set)) => Some(set),
609        }
610    }
611
612    /// Get the selection for a fragment
613    pub fn get(&self, fragment_id: &u32) -> Option<&RowAddrSelection> {
614        self.inner.get(fragment_id)
615    }
616
617    /// Iterate over (fragment_id, selection) pairs
618    pub fn iter(&self) -> impl Iterator<Item = (&u32, &RowAddrSelection)> {
619        self.inner.iter()
620    }
621
622    pub fn retain_fragments(&mut self, frag_ids: impl IntoIterator<Item = u32>) {
623        let frag_id_set = frag_ids.into_iter().collect::<HashSet<_>>();
624        self.inner
625            .retain(|frag_id, _| frag_id_set.contains(frag_id));
626    }
627
628    /// Compute the serialized size of the set.
629    pub fn serialized_size(&self) -> usize {
630        // Starts at 4 because of the u32 num_entries
631        let mut size = 4;
632        for set in self.inner.values() {
633            // Each entry is 8 bytes for the fragment id and the bitmap size
634            size += 8;
635            if let RowAddrSelection::Partial(set) = set {
636                size += set.serialized_size();
637            }
638        }
639        size
640    }
641
642    /// Serialize the set into the given buffer
643    ///
644    /// The serialization format is stable and used for index serialization
645    ///
646    /// The serialization format is:
647    /// * u32: num_entries
648    ///
649    /// for each entry:
650    ///   * u32: fragment_id
651    ///   * u32: bitmap size
652    ///   * \[u8\]: bitmap
653    ///
654    /// If bitmap size is zero then the entire fragment is selected.
655    pub fn serialize_into<W: Write>(&self, mut writer: W) -> Result<()> {
656        writer.write_u32::<byteorder::LittleEndian>(self.inner.len() as u32)?;
657        for (fragment, set) in &self.inner {
658            writer.write_u32::<byteorder::LittleEndian>(*fragment)?;
659            if let RowAddrSelection::Partial(set) = set {
660                writer.write_u32::<byteorder::LittleEndian>(set.serialized_size() as u32)?;
661                set.serialize_into(&mut writer)?;
662            } else {
663                writer.write_u32::<byteorder::LittleEndian>(0)?;
664            }
665        }
666        Ok(())
667    }
668
669    /// Deserialize the set from the given buffer
670    pub fn deserialize_from<R: Read>(mut reader: R) -> Result<Self> {
671        let num_entries = reader.read_u32::<byteorder::LittleEndian>()?;
672        let mut inner = BTreeMap::new();
673        for _ in 0..num_entries {
674            let fragment = reader.read_u32::<byteorder::LittleEndian>()?;
675            let bitmap_size = reader.read_u32::<byteorder::LittleEndian>()?;
676            if bitmap_size == 0 {
677                inner.insert(fragment, RowAddrSelection::Full);
678            } else {
679                // Grow with the bytes that actually arrive instead of trusting the
680                // declared size. This is reachable from a public byte boundary, so
681                // a 12-byte payload could otherwise declare 4 GiB and abort the
682                // process on the allocation before any read fails.
683                let mut buffer = Vec::new();
684                let read = reader
685                    .by_ref()
686                    .take(u64::from(bitmap_size))
687                    .read_to_end(&mut buffer)?;
688                if read != bitmap_size as usize {
689                    return Err(Error::invalid_input(format!(
690                        "row addr treemap declares a {bitmap_size} byte bitmap for \
691                         fragment {fragment} but only {read} bytes remain"
692                    )));
693                }
694                let set = RoaringBitmap::deserialize_from(&buffer[..])?;
695                inner.insert(fragment, RowAddrSelection::Partial(set));
696            }
697        }
698        Ok(Self { inner })
699    }
700
701    /// Apply a mask to the row addrs
702    ///
703    /// For AllowList: only keep rows that are in the selection and not null
704    /// For BlockList: remove rows that are blocked (not null) and remove nulls
705    pub fn mask(&mut self, mask: &RowAddrMask) {
706        match mask {
707            RowAddrMask::AllowList(allow_list) => {
708                *self &= allow_list;
709            }
710            RowAddrMask::BlockList(block_list) => {
711                *self -= block_list;
712            }
713        }
714    }
715
716    /// Convert the set into an iterator of row addrs
717    ///
718    /// # Panics
719    ///
720    /// Panics if any selection is `Full` because the fragment size is unknown.
721    pub fn into_addr_iter(self) -> impl Iterator<Item = u64> {
722        self.inner
723            .into_iter()
724            .flat_map(|(fragment, selection)| match selection {
725                RowAddrSelection::Full => panic!("Size of full fragment is unknown"),
726                RowAddrSelection::Partial(bitmap) => bitmap.into_iter().map(move |val| {
727                    let fragment = fragment as u64;
728                    let row_offset = val as u64;
729                    (fragment << 32) | row_offset
730                }),
731            })
732    }
733
734    /// Iterate the selected row addresses as `(fragment_id, run)` pairs.
735    ///
736    /// Range-shaped counterpart to [`Self::into_addr_iter`]. A contiguous
737    /// run of N selected rows yields one item, not N. Uses roaring's
738    /// `Iter::next_range`, which walks each underlying container's runs
739    /// rather than its individual bits, so dense ranges cost
740    /// O(num_containers) (roughly num_rows / 65536) instead of O(num_rows).
741    ///
742    /// # Panics
743    ///
744    /// Panics if any selection is `Full` because the fragment size is unknown.
745    pub fn iter_runs(&self) -> impl Iterator<Item = (u32, RangeInclusive<u32>)> + '_ {
746        self.inner
747            .iter()
748            .flat_map(|(&fragment, selection)| match selection {
749                RowAddrSelection::Full => panic!("Size of full fragment is unknown"),
750                RowAddrSelection::Partial(bitmap) => {
751                    let mut iter = bitmap.iter();
752                    std::iter::from_fn(move || iter.next_range().map(|r| (fragment, r)))
753                }
754            })
755    }
756}
757
758impl CacheCodecImpl for RowAddrTreeMap {
759    const TYPE_ID: &'static str = "lance.RowAddrTreeMap";
760    const CURRENT_VERSION: u32 = 1;
761
762    fn serialize(&self, w: &mut CacheEntryWriter<'_>) -> Result<()> {
763        // A roaring bitmap has its own stable, portable serialization; it is
764        // the whole body, so write it raw rather than length-prefixed.
765        self.serialize_into(w.raw_writer())
766    }
767
768    fn deserialize(r: &mut CacheEntryReader<'_>) -> Result<Self> {
769        Self::deserialize_from(r.body().as_ref())
770    }
771}
772
773impl std::ops::BitOr<Self> for RowAddrTreeMap {
774    type Output = Self;
775
776    fn bitor(mut self, rhs: Self) -> Self::Output {
777        self |= rhs;
778        self
779    }
780}
781
782impl std::ops::BitOr<&Self> for RowAddrTreeMap {
783    type Output = Self;
784
785    fn bitor(mut self, rhs: &Self) -> Self::Output {
786        self |= rhs;
787        self
788    }
789}
790
791impl std::ops::BitOrAssign<Self> for RowAddrTreeMap {
792    fn bitor_assign(&mut self, rhs: Self) {
793        *self |= &rhs;
794    }
795}
796
797impl std::ops::BitOrAssign<&Self> for RowAddrTreeMap {
798    fn bitor_assign(&mut self, rhs: &Self) {
799        for (fragment, rhs_set) in &rhs.inner {
800            let lhs_set = self.inner.get_mut(fragment);
801            if let Some(lhs_set) = lhs_set {
802                match lhs_set {
803                    RowAddrSelection::Full => {
804                        // If the fragment is already selected then there is nothing to do
805                    }
806                    RowAddrSelection::Partial(lhs_bitmap) => match rhs_set {
807                        RowAddrSelection::Full => {
808                            *lhs_set = RowAddrSelection::Full;
809                        }
810                        RowAddrSelection::Partial(rhs_set) => {
811                            *lhs_bitmap |= rhs_set;
812                        }
813                    },
814                }
815            } else {
816                self.inner.insert(*fragment, rhs_set.clone());
817            }
818        }
819    }
820}
821
822impl std::ops::BitAnd<Self> for RowAddrTreeMap {
823    type Output = Self;
824
825    fn bitand(mut self, rhs: Self) -> Self::Output {
826        self &= &rhs;
827        self
828    }
829}
830
831impl std::ops::BitAnd<&Self> for RowAddrTreeMap {
832    type Output = Self;
833
834    fn bitand(mut self, rhs: &Self) -> Self::Output {
835        self &= rhs;
836        self
837    }
838}
839
840impl std::ops::BitAndAssign<Self> for RowAddrTreeMap {
841    fn bitand_assign(&mut self, rhs: Self) {
842        *self &= &rhs;
843    }
844}
845
846impl std::ops::BitAndAssign<&Self> for RowAddrTreeMap {
847    fn bitand_assign(&mut self, rhs: &Self) {
848        // Remove fragment that aren't on the RHS
849        self.inner
850            .retain(|fragment, _| rhs.inner.contains_key(fragment));
851
852        // For fragments that are on the RHS, intersect the bitmaps
853        for (fragment, mut lhs_set) in &mut self.inner {
854            match (&mut lhs_set, rhs.inner.get(fragment)) {
855                (_, None) => {} // Already handled by retain
856                (_, Some(RowAddrSelection::Full)) => {
857                    // Everything selected on RHS, so can leave LHS untouched.
858                }
859                (RowAddrSelection::Partial(lhs_set), Some(RowAddrSelection::Partial(rhs_set))) => {
860                    *lhs_set &= rhs_set;
861                }
862                (RowAddrSelection::Full, Some(RowAddrSelection::Partial(rhs_set))) => {
863                    *lhs_set = RowAddrSelection::Partial(rhs_set.clone());
864                }
865            }
866        }
867        // Some bitmaps might now be empty. If they are, we should remove them.
868        self.inner.retain(|_, set| match set {
869            RowAddrSelection::Partial(set) => !set.is_empty(),
870            RowAddrSelection::Full => true,
871        });
872    }
873}
874
875impl std::ops::Sub<Self> for RowAddrTreeMap {
876    type Output = Self;
877
878    fn sub(mut self, rhs: Self) -> Self {
879        self -= &rhs;
880        self
881    }
882}
883
884impl std::ops::Sub<&Self> for RowAddrTreeMap {
885    type Output = Self;
886
887    fn sub(mut self, rhs: &Self) -> Self {
888        self -= rhs;
889        self
890    }
891}
892
893impl std::ops::SubAssign<&Self> for RowAddrTreeMap {
894    fn sub_assign(&mut self, rhs: &Self) {
895        for (fragment, rhs_set) in &rhs.inner {
896            match self.inner.get_mut(fragment) {
897                None => {}
898                Some(RowAddrSelection::Full) => {
899                    // If the fragment is already selected then there is nothing to do
900                    match rhs_set {
901                        RowAddrSelection::Full => {
902                            self.inner.remove(fragment);
903                        }
904                        RowAddrSelection::Partial(rhs_set) => {
905                            // This generally won't be hit.
906                            let mut set = RoaringBitmap::full();
907                            set -= rhs_set;
908                            self.inner.insert(*fragment, RowAddrSelection::Partial(set));
909                        }
910                    }
911                }
912                Some(RowAddrSelection::Partial(lhs_set)) => match rhs_set {
913                    RowAddrSelection::Full => {
914                        self.inner.remove(fragment);
915                    }
916                    RowAddrSelection::Partial(rhs_set) => {
917                        *lhs_set -= rhs_set;
918                        if lhs_set.is_empty() {
919                            self.inner.remove(fragment);
920                        }
921                    }
922                },
923            }
924        }
925    }
926}
927
928impl FromIterator<u64> for RowAddrTreeMap {
929    fn from_iter<T: IntoIterator<Item = u64>>(iter: T) -> Self {
930        let mut inner = BTreeMap::new();
931        for row_addr in iter {
932            let upper = (row_addr >> 32) as u32;
933            let lower = row_addr as u32;
934            match inner.get_mut(&upper) {
935                None => {
936                    let mut set = RoaringBitmap::new();
937                    set.insert(lower);
938                    inner.insert(upper, RowAddrSelection::Partial(set));
939                }
940                Some(RowAddrSelection::Full) => {
941                    // If the fragment is already selected then there is nothing to do
942                }
943                Some(RowAddrSelection::Partial(set)) => {
944                    set.insert(lower);
945                }
946            }
947        }
948        Self { inner }
949    }
950}
951
952impl<'a> FromIterator<&'a u64> for RowAddrTreeMap {
953    fn from_iter<T: IntoIterator<Item = &'a u64>>(iter: T) -> Self {
954        Self::from_iter(iter.into_iter().copied())
955    }
956}
957
958impl From<Range<u64>> for RowAddrTreeMap {
959    fn from(range: Range<u64>) -> Self {
960        let mut map = Self::default();
961        map.insert_range(range);
962        map
963    }
964}
965
966impl From<RangeInclusive<u64>> for RowAddrTreeMap {
967    fn from(range: RangeInclusive<u64>) -> Self {
968        let mut map = Self::default();
969        map.insert_range(range);
970        map
971    }
972}
973
974impl From<RoaringTreemap> for RowAddrTreeMap {
975    fn from(roaring: RoaringTreemap) -> Self {
976        let mut inner = BTreeMap::new();
977        for (fragment, set) in roaring.bitmaps() {
978            inner.insert(fragment, RowAddrSelection::Partial(set.clone()));
979        }
980        Self { inner }
981    }
982}
983
984impl Extend<u64> for RowAddrTreeMap {
985    fn extend<T: IntoIterator<Item = u64>>(&mut self, iter: T) {
986        for row_addr in iter {
987            let upper = (row_addr >> 32) as u32;
988            let lower = row_addr as u32;
989            match self.inner.get_mut(&upper) {
990                None => {
991                    let mut set = RoaringBitmap::new();
992                    set.insert(lower);
993                    self.inner.insert(upper, RowAddrSelection::Partial(set));
994                }
995                Some(RowAddrSelection::Full) => {
996                    // If the fragment is already selected then there is nothing to do
997                }
998                Some(RowAddrSelection::Partial(set)) => {
999                    set.insert(lower);
1000                }
1001            }
1002        }
1003    }
1004}
1005
1006impl<'a> Extend<&'a u64> for RowAddrTreeMap {
1007    fn extend<T: IntoIterator<Item = &'a u64>>(&mut self, iter: T) {
1008        self.extend(iter.into_iter().copied())
1009    }
1010}
1011
1012// Extending with RowAddrTreeMap is basically a cumulative set union
1013impl Extend<Self> for RowAddrTreeMap {
1014    fn extend<T: IntoIterator<Item = Self>>(&mut self, iter: T) {
1015        for other in iter {
1016            for (fragment, set) in other.inner {
1017                match self.inner.get_mut(&fragment) {
1018                    None => {
1019                        self.inner.insert(fragment, set);
1020                    }
1021                    Some(RowAddrSelection::Full) => {
1022                        // If the fragment is already selected then there is nothing to do
1023                    }
1024                    Some(RowAddrSelection::Partial(lhs_set)) => match set {
1025                        RowAddrSelection::Full => {
1026                            self.inner.insert(fragment, RowAddrSelection::Full);
1027                        }
1028                        RowAddrSelection::Partial(rhs_set) => {
1029                            *lhs_set |= rhs_set;
1030                        }
1031                    },
1032                }
1033            }
1034        }
1035    }
1036}
1037
1038pub fn bitmap_to_ranges(bitmap: &RoaringBitmap) -> Vec<Range<u64>> {
1039    let mut ranges = Vec::new();
1040    let mut iter = bitmap.iter();
1041    while let Some(r) = iter.next_range() {
1042        ranges.push(*r.start() as u64..(*r.end() as u64 + 1));
1043    }
1044    ranges
1045}
1046
1047pub fn ranges_to_bitmap(ranges: &[Range<u64>], sorted: bool) -> RoaringBitmap {
1048    if ranges.is_empty() {
1049        return RoaringBitmap::new();
1050    }
1051    if sorted {
1052        let sample_size = ranges.len().min(10);
1053        let avg_len: u64 = ranges
1054            .iter()
1055            .take(sample_size)
1056            .map(|r| r.end - r.start)
1057            .sum::<u64>()
1058            / sample_size as u64;
1059        // from_sorted_iter appends each value in O(1) but must visit every u32.
1060        // insert_range bulk-fills containers but does a binary search per call.
1061        // Crossover is ~6: below that, iterating all values is cheaper.
1062        if avg_len <= 6 {
1063            return RoaringBitmap::from_sorted_iter(
1064                ranges.iter().flat_map(|r| r.start as u32..r.end as u32),
1065            )
1066            .unwrap();
1067        }
1068    }
1069    let mut bm = RoaringBitmap::new();
1070    for r in ranges {
1071        bm.insert_range(r.start as u32..r.end as u32);
1072    }
1073    bm
1074}
1075
1076/// A set of stable row ids backed by a 64-bit Roaring bitmap.
1077///
1078/// This is a thin wrapper around [`RoaringTreemap`]. It represents a
1079/// collection of unique row ids and provides the common row-set
1080/// operations defined by [`RowSetOps`].
1081#[derive(Clone, Debug, Default, PartialEq)]
1082pub struct RowIdSet {
1083    inner: RoaringTreemap,
1084}
1085
1086impl RowIdSet {
1087    /// Creates an empty set of row ids.
1088    pub fn new() -> Self {
1089        Self::default()
1090    }
1091    /// Returns an iterator over the contained row ids in ascending order.
1092    pub fn iter(&self) -> impl Iterator<Item = u64> + '_ {
1093        self.inner.iter()
1094    }
1095    /// Returns the union of `self` and `other`.
1096    pub fn union(mut self, other: &Self) -> Self {
1097        self.inner |= &other.inner;
1098        self
1099    }
1100    /// Returns the set difference `self \\ other`.
1101    pub fn difference(mut self, other: &Self) -> Self {
1102        self.inner -= &other.inner;
1103        self
1104    }
1105}
1106
1107impl RowSetOps for RowIdSet {
1108    type Row = u64;
1109    fn is_empty(&self) -> bool {
1110        self.inner.is_empty()
1111    }
1112    fn len(&self) -> Option<u64> {
1113        Some(self.inner.len())
1114    }
1115    fn remove(&mut self, row: Self::Row) -> bool {
1116        self.inner.remove(row)
1117    }
1118    fn contains(&self, row: Self::Row) -> bool {
1119        self.inner.contains(row)
1120    }
1121    fn union_all(other: &[&Self]) -> Self {
1122        let mut result = other
1123            .first()
1124            .map_or(Self::default(), |&first| first.clone());
1125        for set in other {
1126            result.inner |= &set.inner;
1127        }
1128        result
1129    }
1130    #[track_caller]
1131    fn from_sorted_iter<I>(iter: I) -> Result<Self>
1132    where
1133        I: IntoIterator<Item = Self::Row>,
1134    {
1135        let mut inner = RoaringTreemap::new();
1136        let mut last: Option<u64> = None;
1137        for value in iter {
1138            if let Some(prev) = last
1139                && value < prev
1140            {
1141                return Err(Error::internal(
1142                    "RowIdSet::from_sorted_iter called with non-sorted input",
1143                ));
1144            }
1145            inner.insert(value);
1146            last = Some(value);
1147        }
1148        Ok(Self { inner })
1149    }
1150}
1151
1152/// A mask over stable row ids based on an allow-list or block-list.
1153///
1154/// The semantics mirror [`RowAddrMask`], but operate on stable
1155/// row ids instead of physical row addresses.
1156#[derive(Clone, Debug, PartialEq)]
1157pub enum RowIdMask {
1158    /// Only the ids in the set are selected.
1159    AllowList(RowIdSet),
1160    /// All ids are selected except those in the set.
1161    BlockList(RowIdSet),
1162}
1163
1164impl Default for RowIdMask {
1165    fn default() -> Self {
1166        // Empty block list means all rows are allowed
1167        Self::BlockList(RowIdSet::default())
1168    }
1169}
1170impl RowIdMask {
1171    /// Create a mask allowing all rows, this is an alias for [`Default`].
1172    pub fn all_rows() -> Self {
1173        Self::default()
1174    }
1175    /// Create a mask that doesn't allow any row id.
1176    pub fn allow_nothing() -> Self {
1177        Self::AllowList(RowIdSet::default())
1178    }
1179    /// Create a mask from an allow list.
1180    pub fn from_allowed(allow_list: RowIdSet) -> Self {
1181        Self::AllowList(allow_list)
1182    }
1183    /// Create a mask from a block list.
1184    pub fn from_block(block_list: RowIdSet) -> Self {
1185        Self::BlockList(block_list)
1186    }
1187    /// True if the row id is selected by the mask, false otherwise.
1188    pub fn selected(&self, row_id: u64) -> bool {
1189        match self {
1190            Self::AllowList(allow_list) => allow_list.contains(row_id),
1191            Self::BlockList(block_list) => !block_list.contains(row_id),
1192        }
1193    }
1194    /// Return the indices of the input row ids that are selected by the mask.
1195    pub fn selected_indices<'a>(&self, row_ids: impl Iterator<Item = &'a u64> + 'a) -> Vec<u64> {
1196        row_ids
1197            .enumerate()
1198            .filter_map(|(idx, row_id)| {
1199                if self.selected(*row_id) {
1200                    Some(idx as u64)
1201                } else {
1202                    None
1203                }
1204            })
1205            .collect()
1206    }
1207    /// Also block the given ids.
1208    ///
1209    /// * `AllowList(a)` -> `AllowList(a \\ block_list)`
1210    /// * `BlockList(b)` -> `BlockList(b union block_list)`
1211    pub fn also_block(self, block_list: RowIdSet) -> Self {
1212        match self {
1213            Self::AllowList(allow_list) => Self::AllowList(allow_list.difference(&block_list)),
1214            Self::BlockList(existing) => Self::BlockList(existing.union(&block_list)),
1215        }
1216    }
1217    /// Also allow the given ids.
1218    ///
1219    /// * `AllowList(a)` -> `AllowList(a union allow_list)`
1220    /// * `BlockList(b)` -> `BlockList(b \\ allow_list)`
1221    pub fn also_allow(self, allow_list: RowIdSet) -> Self {
1222        match self {
1223            Self::AllowList(existing) => Self::AllowList(existing.union(&allow_list)),
1224            Self::BlockList(block_list) => Self::BlockList(block_list.difference(&allow_list)),
1225        }
1226    }
1227    /// Return the maximum number of row ids that could be selected by this mask.
1228    ///
1229    /// Will be `None` if this is a `BlockList` (unbounded).
1230    pub fn max_len(&self) -> Option<u64> {
1231        match self {
1232            Self::AllowList(selection) => selection.len(),
1233            Self::BlockList(_) => None,
1234        }
1235    }
1236    /// Iterate over the row ids that are selected by the mask.
1237    ///
1238    /// This is only possible if this is an `AllowList`. For a `BlockList`
1239    /// the domain of possible row ids is unbounded.
1240    pub fn iter_ids(&self) -> Option<Box<dyn Iterator<Item = u64> + '_>> {
1241        match self {
1242            Self::AllowList(allow_list) => Some(Box::new(allow_list.iter())),
1243            Self::BlockList(_) => None,
1244        }
1245    }
1246}
1247
1248#[cfg(test)]
1249mod tests {
1250    use super::*;
1251    use proptest::{prop_assert, prop_assert_eq};
1252
1253    fn rows(ids: &[u64]) -> RowAddrTreeMap {
1254        RowAddrTreeMap::from_iter(ids)
1255    }
1256
1257    fn assert_mask_selects(mask: &RowAddrMask, selected: &[u64], not_selected: &[u64]) {
1258        for &id in selected {
1259            assert!(mask.selected(id), "Expected row {} to be selected", id);
1260        }
1261        for &id in not_selected {
1262            assert!(!mask.selected(id), "Expected row {} to NOT be selected", id);
1263        }
1264    }
1265
1266    fn selected_in_range(mask: &RowAddrMask, range: std::ops::Range<u64>) -> Vec<u64> {
1267        range.filter(|val| mask.selected(*val)).collect()
1268    }
1269
1270    #[test]
1271    fn test_row_addr_mask_construction() {
1272        let full_mask = RowAddrMask::all_rows();
1273        assert_eq!(full_mask.max_len(), None);
1274        assert_mask_selects(&full_mask, &[0, 1, 4 << 32 | 3], &[]);
1275        assert_eq!(full_mask.allow_list(), None);
1276        assert_eq!(full_mask.block_list(), Some(&RowAddrTreeMap::default()));
1277        assert!(full_mask.iter_addrs().is_none());
1278
1279        let empty_mask = RowAddrMask::allow_nothing();
1280        assert_eq!(empty_mask.max_len(), Some(0));
1281        assert_mask_selects(&empty_mask, &[], &[0, 1, 4 << 32 | 3]);
1282        assert_eq!(empty_mask.allow_list(), Some(&RowAddrTreeMap::default()));
1283        assert_eq!(empty_mask.block_list(), None);
1284        let iter = empty_mask.iter_addrs();
1285        assert!(iter.is_some());
1286        assert_eq!(iter.unwrap().count(), 0);
1287
1288        let allow_list = RowAddrMask::from_allowed(rows(&[10, 20, 30]));
1289        assert_eq!(allow_list.max_len(), Some(3));
1290        assert_mask_selects(&allow_list, &[10, 20, 30], &[0, 15, 25, 40]);
1291        assert_eq!(allow_list.allow_list(), Some(&rows(&[10, 20, 30])));
1292        assert_eq!(allow_list.block_list(), None);
1293        let iter = allow_list.iter_addrs();
1294        assert!(iter.is_some());
1295        let ids: Vec<u64> = iter.unwrap().map(|addr| addr.into()).collect();
1296        assert_eq!(ids, vec![10, 20, 30]);
1297
1298        let mut full_frag = RowAddrTreeMap::default();
1299        full_frag.insert_fragment(2);
1300        let allow_list = RowAddrMask::from_allowed(full_frag);
1301        assert_eq!(allow_list.max_len(), None);
1302        assert_mask_selects(&allow_list, &[(2 << 32) + 5], &[(3 << 32) + 5]);
1303        assert!(allow_list.iter_addrs().is_none());
1304    }
1305
1306    #[test]
1307    fn test_row_addr_mask_selects_all_known_rows() {
1308        let partition_rows = rows(&[10, 20, 2_u64 << 32 | 3]);
1309
1310        assert!(RowAddrMask::all_rows().selects_all(&partition_rows));
1311        assert!(
1312            RowAddrMask::from_allowed(rows(&[10, 20, 30, 2_u64 << 32 | 3]))
1313                .selects_all(&partition_rows)
1314        );
1315        assert!(
1316            !RowAddrMask::from_allowed(rows(&[10, 2_u64 << 32 | 3])).selects_all(&partition_rows)
1317        );
1318        assert!(RowAddrMask::from_block(rows(&[30])).selects_all(&partition_rows));
1319        assert!(!RowAddrMask::from_block(rows(&[20, 30])).selects_all(&partition_rows));
1320        assert!(RowAddrMask::allow_nothing().selects_all(&RowAddrTreeMap::new()));
1321    }
1322
1323    #[test]
1324    fn test_selected_indices() {
1325        // Allow list
1326        let mask = RowAddrMask::from_allowed(rows(&[10, 20, 40]));
1327        assert!(mask.selected_indices(std::iter::empty()).is_empty());
1328        assert_eq!(mask.selected_indices([25, 20, 14, 10].iter()), &[1, 3]);
1329
1330        // Block list
1331        let mask = RowAddrMask::from_block(rows(&[10, 20, 40]));
1332        assert!(mask.selected_indices(std::iter::empty()).is_empty());
1333        assert_eq!(mask.selected_indices([25, 20, 14, 10].iter()), &[0, 2]);
1334    }
1335
1336    #[test]
1337    fn test_also_allow() {
1338        // Allow list
1339        let mask = RowAddrMask::from_allowed(rows(&[10, 20]));
1340        let new_mask = mask.also_allow(rows(&[20, 30, 40]));
1341        assert_eq!(new_mask, RowAddrMask::from_allowed(rows(&[10, 20, 30, 40])));
1342
1343        // Block list
1344        let mask = RowAddrMask::from_block(rows(&[10, 20, 30]));
1345        let new_mask = mask.also_allow(rows(&[20, 40]));
1346        assert_eq!(new_mask, RowAddrMask::from_block(rows(&[10, 30])));
1347    }
1348
1349    #[test]
1350    fn test_also_block() {
1351        // Allow list
1352        let mask = RowAddrMask::from_allowed(rows(&[10, 20, 30]));
1353        let new_mask = mask.also_block(rows(&[20, 40]));
1354        assert_eq!(new_mask, RowAddrMask::from_allowed(rows(&[10, 30])));
1355
1356        // Block list
1357        let mask = RowAddrMask::from_block(rows(&[10, 20]));
1358        let new_mask = mask.also_block(rows(&[20, 30, 40]));
1359        assert_eq!(new_mask, RowAddrMask::from_block(rows(&[10, 20, 30, 40])));
1360    }
1361
1362    #[test]
1363    fn test_iter_ids() {
1364        // Allow list
1365        let mask = RowAddrMask::from_allowed(rows(&[10, 20, 30]));
1366        let expected: Vec<_> = [10, 20, 30].into_iter().map(RowAddress::from).collect();
1367        assert_eq!(mask.iter_addrs().unwrap().collect::<Vec<_>>(), expected);
1368
1369        // Allow list with full fragment
1370        let mut inner = RowAddrTreeMap::default();
1371        inner.insert_fragment(10);
1372        let mask = RowAddrMask::from_allowed(inner);
1373        assert!(mask.iter_addrs().is_none());
1374
1375        // Block list
1376        let mask = RowAddrMask::from_block(rows(&[10, 20, 30]));
1377        assert!(mask.iter_addrs().is_none());
1378    }
1379
1380    #[test]
1381    fn test_row_addr_mask_intersect() {
1382        let a = rows(&[1, 2, 3]);
1383        let b = rows(&[3, 4]);
1384
1385        // allow & allow -> only rows in both
1386        assert_mask_selects(
1387            &RowAddrMask::from_allowed(a.clone()).intersect(RowAddrMask::from_allowed(b.clone())),
1388            &[3],
1389            &[1, 2, 4, 100],
1390        );
1391        // allow & block -> allowed minus blocked
1392        assert_mask_selects(
1393            &RowAddrMask::from_allowed(a.clone()).intersect(RowAddrMask::from_block(b.clone())),
1394            &[1, 2],
1395            &[3, 4, 100],
1396        );
1397        // block & allow -> same, order independent
1398        assert_mask_selects(
1399            &RowAddrMask::from_block(b.clone()).intersect(RowAddrMask::from_allowed(a.clone())),
1400            &[1, 2],
1401            &[3, 4, 100],
1402        );
1403        // block & block -> both exclusions apply
1404        assert_mask_selects(
1405            &RowAddrMask::from_block(a.clone()).intersect(RowAddrMask::from_block(b)),
1406            &[100],
1407            &[1, 2, 3, 4],
1408        );
1409        // all_rows is the identity, and intersecting with itself changes nothing
1410        let allow_a = RowAddrMask::from_allowed(a.clone());
1411        assert_eq!(allow_a.clone().intersect(RowAddrMask::all_rows()), allow_a);
1412        assert_eq!(allow_a.clone().intersect(allow_a.clone()), allow_a);
1413        // allow_nothing absorbs
1414        assert_mask_selects(
1415            &RowAddrMask::allow_nothing().intersect(RowAddrMask::from_allowed(a)),
1416            &[],
1417            &[1, 2, 3, 100],
1418        );
1419    }
1420
1421    #[test]
1422    fn test_row_addr_mask_from_serialized_parts() {
1423        fn ser(tm: &RowAddrTreeMap) -> Vec<u8> {
1424            let mut buf = Vec::new();
1425            tm.serialize_into(&mut buf).unwrap();
1426            buf
1427        }
1428        let allow = ser(&rows(&[1, 2, 3]));
1429        let block = ser(&rows(&[3, 4]));
1430
1431        // Neither part means "no mask", which is not the same as "select nothing".
1432        assert!(
1433            RowAddrMask::from_serialized_parts(None, None)
1434                .unwrap()
1435                .is_none()
1436        );
1437
1438        let m = RowAddrMask::from_serialized_parts(Some(&allow), None)
1439            .unwrap()
1440            .unwrap();
1441        assert_mask_selects(&m, &[1, 2, 3], &[4, 100]);
1442
1443        let m = RowAddrMask::from_serialized_parts(None, Some(&block))
1444            .unwrap()
1445            .unwrap();
1446        assert_mask_selects(&m, &[1, 2, 100], &[3, 4]);
1447
1448        // Block wins on the overlap.
1449        let m = RowAddrMask::from_serialized_parts(Some(&allow), Some(&block))
1450            .unwrap()
1451            .unwrap();
1452        assert_mask_selects(&m, &[1, 2], &[3, 4, 100]);
1453
1454        // Round trips through the same encoding the caller used.
1455        let again = RowAddrMask::from_serialized_parts(Some(&ser(m.allow_list().unwrap())), None)
1456            .unwrap()
1457            .unwrap();
1458        assert_mask_selects(&again, &[1, 2], &[3, 4]);
1459
1460        assert!(RowAddrMask::from_serialized_parts(Some(b"not a treemap"), None).is_err());
1461
1462        // A declared bitmap size must not be allocated before the bytes are
1463        // known to exist: this 12-byte payload claims ~4 GiB.
1464        let bomb = [
1465            1u8, 0, 0, 0, // one entry
1466            0, 0, 0, 0, // fragment zero
1467            0xff, 0xff, 0xff, 0xff, // declared bitmap size
1468        ];
1469        let err = RowAddrMask::from_serialized_parts(Some(&bomb), None).unwrap_err();
1470        assert!(
1471            err.to_string().contains("only 0 bytes remain"),
1472            "expected a length complaint, got: {err}"
1473        );
1474    }
1475
1476    #[test]
1477    fn test_row_addr_mask_not() {
1478        let allow_list = RowAddrMask::from_allowed(rows(&[1, 2, 3]));
1479        let block_list = !allow_list.clone();
1480        assert_eq!(block_list, RowAddrMask::from_block(rows(&[1, 2, 3])));
1481        // Can roundtrip by negating again
1482        assert_eq!(!block_list, allow_list);
1483    }
1484
1485    #[test]
1486    fn test_ops() {
1487        let mask = RowAddrMask::default();
1488        assert_mask_selects(&mask, &[1, 5], &[]);
1489
1490        let block_list = mask.also_block(rows(&[0, 5, 15]));
1491        assert_mask_selects(&block_list, &[1], &[5]);
1492
1493        let allow_list = RowAddrMask::from_allowed(rows(&[0, 2, 5]));
1494        assert_mask_selects(&allow_list, &[5], &[1]);
1495
1496        let combined = block_list & allow_list;
1497        assert_mask_selects(&combined, &[2], &[0, 5]);
1498
1499        let other = RowAddrMask::from_allowed(rows(&[3]));
1500        let combined = combined | other;
1501        assert_mask_selects(&combined, &[2, 3], &[0, 5]);
1502
1503        let block_list = RowAddrMask::from_block(rows(&[0]));
1504        let allow_list = RowAddrMask::from_allowed(rows(&[3]));
1505
1506        let combined = block_list | allow_list;
1507        assert_mask_selects(&combined, &[1], &[]);
1508    }
1509
1510    #[test]
1511    fn test_logical_and() {
1512        let allow1 = RowAddrMask::from_allowed(rows(&[0, 1]));
1513        let block1 = RowAddrMask::from_block(rows(&[1, 2]));
1514        let allow2 = RowAddrMask::from_allowed(rows(&[1, 2, 3, 4]));
1515        let block2 = RowAddrMask::from_block(rows(&[3, 4]));
1516
1517        fn check(lhs: &RowAddrMask, rhs: &RowAddrMask, expected: &[u64]) {
1518            for mask in [lhs.clone() & rhs.clone(), rhs.clone() & lhs.clone()] {
1519                assert_eq!(selected_in_range(&mask, 0..10), expected);
1520            }
1521        }
1522
1523        // Allow & Allow
1524        check(&allow1, &allow1, &[0, 1]);
1525        check(&allow1, &allow2, &[1]);
1526
1527        // Block & Block
1528        check(&block1, &block1, &[0, 3, 4, 5, 6, 7, 8, 9]);
1529        check(&block1, &block2, &[0, 5, 6, 7, 8, 9]);
1530
1531        // Allow & Block
1532        check(&allow1, &block1, &[0]);
1533        check(&allow1, &block2, &[0, 1]);
1534        check(&allow2, &block1, &[3, 4]);
1535        check(&allow2, &block2, &[1, 2]);
1536    }
1537
1538    #[test]
1539    fn test_logical_or() {
1540        let allow1 = RowAddrMask::from_allowed(rows(&[5, 6, 7, 8, 9]));
1541        let block1 = RowAddrMask::from_block(rows(&[5, 6]));
1542        let mixed1 = allow1.clone().also_block(rows(&[5, 6]));
1543        let allow2 = RowAddrMask::from_allowed(rows(&[2, 3, 4, 5, 6, 7, 8]));
1544        let block2 = RowAddrMask::from_block(rows(&[4, 5]));
1545        let mixed2 = allow2.clone().also_block(rows(&[4, 5]));
1546
1547        fn check(lhs: &RowAddrMask, rhs: &RowAddrMask, expected: &[u64]) {
1548            for mask in [lhs.clone() | rhs.clone(), rhs.clone() | lhs.clone()] {
1549                assert_eq!(selected_in_range(&mask, 0..10), expected);
1550            }
1551        }
1552
1553        check(&allow1, &allow1, &[5, 6, 7, 8, 9]);
1554        check(&block1, &block1, &[0, 1, 2, 3, 4, 7, 8, 9]);
1555        check(&mixed1, &mixed1, &[7, 8, 9]);
1556        check(&allow2, &allow2, &[2, 3, 4, 5, 6, 7, 8]);
1557        check(&block2, &block2, &[0, 1, 2, 3, 6, 7, 8, 9]);
1558        check(&mixed2, &mixed2, &[2, 3, 6, 7, 8]);
1559
1560        check(&allow1, &block1, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1561        check(&allow1, &mixed1, &[5, 6, 7, 8, 9]);
1562        check(&allow1, &allow2, &[2, 3, 4, 5, 6, 7, 8, 9]);
1563        check(&allow1, &block2, &[0, 1, 2, 3, 5, 6, 7, 8, 9]);
1564        check(&allow1, &mixed2, &[2, 3, 5, 6, 7, 8, 9]);
1565        check(&block1, &mixed1, &[0, 1, 2, 3, 4, 7, 8, 9]);
1566        check(&block1, &allow2, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1567        check(&block1, &block2, &[0, 1, 2, 3, 4, 6, 7, 8, 9]);
1568        check(&block1, &mixed2, &[0, 1, 2, 3, 4, 6, 7, 8, 9]);
1569        check(&mixed1, &allow2, &[2, 3, 4, 5, 6, 7, 8, 9]);
1570        check(&mixed1, &block2, &[0, 1, 2, 3, 6, 7, 8, 9]);
1571        check(&mixed1, &mixed2, &[2, 3, 6, 7, 8, 9]);
1572        check(&allow2, &block2, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1573        check(&allow2, &mixed2, &[2, 3, 4, 5, 6, 7, 8]);
1574        check(&block2, &mixed2, &[0, 1, 2, 3, 6, 7, 8, 9]);
1575    }
1576
1577    #[test]
1578    fn test_deserialize_legacy_format() {
1579        // Test that we can deserialize the old format where both allow_list
1580        // and block_list could be present in the serialized form.
1581        //
1582        // The old format (before this PR) used a struct with both allow_list and block_list
1583        // fields. The new format uses an enum. The deserialization code should handle
1584        // the case where both lists are present by converting to AllowList(allow - block).
1585
1586        // Create the RowIdTreeMaps and serialize them directly
1587        let allow = rows(&[1, 2, 3, 4, 5, 10, 15]);
1588        let block = rows(&[2, 4, 15]);
1589
1590        // Serialize using the stable RowIdTreeMap serialization format
1591        let block_bytes = {
1592            let mut buf = Vec::with_capacity(block.serialized_size());
1593            block.serialize_into(&mut buf).unwrap();
1594            buf
1595        };
1596        let allow_bytes = {
1597            let mut buf = Vec::with_capacity(allow.serialized_size());
1598            allow.serialize_into(&mut buf).unwrap();
1599            buf
1600        };
1601
1602        // Construct a binary array with both values present (simulating old format)
1603        let old_format_array =
1604            BinaryArray::from_opt_vec(vec![Some(&block_bytes), Some(&allow_bytes)]);
1605
1606        // Deserialize - should handle this by creating AllowList(allow - block)
1607        let deserialized = RowAddrMask::from_arrow(&old_format_array).unwrap();
1608
1609        // The expected result: AllowList([1, 2, 3, 4, 5, 10, 15] - [2, 4, 15]) = [1, 3, 5, 10]
1610        assert_mask_selects(&deserialized, &[1, 3, 5, 10], &[2, 4, 15]);
1611        assert!(
1612            deserialized.allow_list().is_some(),
1613            "Should deserialize to AllowList variant"
1614        );
1615    }
1616
1617    #[test]
1618    fn test_roundtrip_arrow() {
1619        let row_addrs = rows(&[1, 2, 3, 100, 2000]);
1620
1621        // Allow list
1622        let original = RowAddrMask::from_allowed(row_addrs.clone());
1623        let array = original.into_arrow().unwrap();
1624        assert_eq!(RowAddrMask::from_arrow(&array).unwrap(), original);
1625
1626        // Block list
1627        let original = RowAddrMask::from_block(row_addrs);
1628        let array = original.into_arrow().unwrap();
1629        assert_eq!(RowAddrMask::from_arrow(&array).unwrap(), original);
1630    }
1631
1632    #[test]
1633    fn test_deserialize_legacy_empty_lists() {
1634        // Case 1: Both None (should become all_rows)
1635        let array = BinaryArray::from_opt_vec(vec![None, None]);
1636        let mask = RowAddrMask::from_arrow(&array).unwrap();
1637        assert_mask_selects(&mask, &[0, 100, u64::MAX], &[]);
1638
1639        // Case 2: Only block list (no allow list)
1640        let block = rows(&[5, 10]);
1641        let block_bytes = {
1642            let mut buf = Vec::with_capacity(block.serialized_size());
1643            block.serialize_into(&mut buf).unwrap();
1644            buf
1645        };
1646        let array = BinaryArray::from_opt_vec(vec![Some(&block_bytes[..]), None]);
1647        let mask = RowAddrMask::from_arrow(&array).unwrap();
1648        assert_mask_selects(&mask, &[0, 15], &[5, 10]);
1649
1650        // Case 3: Only allow list (no block list)
1651        let allow = rows(&[5, 10]);
1652        let allow_bytes = {
1653            let mut buf = Vec::with_capacity(allow.serialized_size());
1654            allow.serialize_into(&mut buf).unwrap();
1655            buf
1656        };
1657        let array = BinaryArray::from_opt_vec(vec![None, Some(&allow_bytes[..])]);
1658        let mask = RowAddrMask::from_arrow(&array).unwrap();
1659        assert_mask_selects(&mask, &[5, 10], &[0, 15]);
1660    }
1661
1662    #[test]
1663    fn test_map_insert() {
1664        let mut map = RowAddrTreeMap::default();
1665
1666        assert!(!map.contains(20));
1667        assert!(map.insert(20));
1668        assert!(map.contains(20));
1669        assert!(!map.insert(20)); // Inserting again should be no-op
1670
1671        let bitmap = map.get_fragment_bitmap(0);
1672        assert!(bitmap.is_some());
1673        let bitmap = bitmap.unwrap();
1674        assert_eq!(bitmap.len(), 1);
1675
1676        assert!(map.get_fragment_bitmap(1).is_none());
1677
1678        map.insert_fragment(0);
1679        assert!(map.contains(0));
1680        assert!(!map.insert(0)); // Inserting into full fragment should be no-op
1681        assert!(map.get_fragment_bitmap(0).is_none());
1682    }
1683
1684    #[test]
1685    fn test_map_insert_range() {
1686        let ranges = &[
1687            (0..10),
1688            (40..500),
1689            ((u32::MAX as u64 - 10)..(u32::MAX as u64 + 20)),
1690        ];
1691
1692        for range in ranges {
1693            let mut mask = RowAddrTreeMap::default();
1694
1695            let count = mask.insert_range(range.clone());
1696            let expected = range.end - range.start;
1697            assert_eq!(count, expected);
1698
1699            let count = mask.insert_range(range.clone());
1700            assert_eq!(count, 0);
1701
1702            let new_range = range.start + 5..range.end + 5;
1703            let count = mask.insert_range(new_range.clone());
1704            assert_eq!(count, 5);
1705        }
1706
1707        let mut mask = RowAddrTreeMap::default();
1708        let count = mask.insert_range(..10);
1709        assert_eq!(count, 10);
1710        assert!(mask.contains(0));
1711
1712        let count = mask.insert_range(20..=24);
1713        assert_eq!(count, 5);
1714
1715        mask.insert_fragment(0);
1716        let count = mask.insert_range(100..200);
1717        assert_eq!(count, 0);
1718    }
1719
1720    #[test]
1721    fn test_map_remove() {
1722        let mut mask = RowAddrTreeMap::default();
1723
1724        assert!(!mask.remove(20));
1725
1726        mask.insert(20);
1727        assert!(mask.contains(20));
1728        assert!(mask.remove(20));
1729        assert!(!mask.contains(20));
1730
1731        mask.insert_range(10..=20);
1732        assert!(mask.contains(15));
1733        assert!(mask.remove(15));
1734        assert!(!mask.contains(15));
1735
1736        // We don't test removing from a full fragment, because that would take
1737        // a lot of memory.
1738    }
1739
1740    #[test]
1741    fn test_map_mask() {
1742        let mask = rows(&[0, 1, 2]);
1743        let mask2 = rows(&[0, 2, 3]);
1744
1745        let allow_list = RowAddrMask::AllowList(mask2.clone());
1746        let mut actual = mask.clone();
1747        actual.mask(&allow_list);
1748        assert_eq!(actual, rows(&[0, 2]));
1749
1750        let block_list = RowAddrMask::BlockList(mask2);
1751        let mut actual = mask;
1752        actual.mask(&block_list);
1753        assert_eq!(actual, rows(&[1]));
1754    }
1755
1756    #[test]
1757    #[should_panic(expected = "Size of full fragment is unknown")]
1758    fn test_map_insert_full_fragment_row() {
1759        let mut mask = RowAddrTreeMap::default();
1760        mask.insert_fragment(0);
1761
1762        let _ = mask.into_addr_iter().collect::<Vec<u64>>();
1763    }
1764
1765    #[test]
1766    fn test_map_into_addr_iter() {
1767        let mut mask = RowAddrTreeMap::default();
1768        mask.insert(0);
1769        mask.insert(1);
1770        mask.insert(1 << 32 | 5);
1771        mask.insert(2 << 32 | 10);
1772
1773        let expected = vec![0u64, 1, 1 << 32 | 5, 2 << 32 | 10];
1774        let actual: Vec<u64> = mask.into_addr_iter().collect();
1775        assert_eq!(actual, expected);
1776    }
1777
1778    #[test]
1779    fn test_map_iter_runs() {
1780        // Three contiguous regions across two fragments.
1781        let mut mask = RowAddrTreeMap::default();
1782        mask.insert_range(0..3);
1783        mask.insert_range(10..15);
1784        mask.insert_range((1u64 << 32) + 100..(1u64 << 32) + 103);
1785
1786        let runs: Vec<(u32, RangeInclusive<u32>)> = mask.iter_runs().collect();
1787        assert_eq!(runs, vec![(0, 0..=2), (0, 10..=14), (1, 100..=102)]);
1788    }
1789
1790    #[test]
1791    fn test_map_iter_runs_matches_into_addr_iter() {
1792        // Confirm iter_runs and into_addr_iter agree on a non-trivial shape.
1793        let mut mask = RowAddrTreeMap::default();
1794        mask.insert_range(5..7);
1795        mask.insert_range(11..12);
1796        mask.insert_range(20..25);
1797        mask.insert_range((1u64 << 32)..(1u64 << 32) + 3);
1798
1799        let from_runs: Vec<u64> = mask
1800            .iter_runs()
1801            .flat_map(|(frag, run)| {
1802                let frag = u64::from(frag);
1803                (*run.start()..=*run.end()).map(move |v| (frag << 32) | u64::from(v))
1804            })
1805            .collect();
1806        let from_bits: Vec<u64> = mask.clone().into_addr_iter().collect();
1807        assert_eq!(from_runs, from_bits);
1808    }
1809
1810    #[test]
1811    fn test_map_from() {
1812        let map = RowAddrTreeMap::from(10..12);
1813        assert!(map.contains(10));
1814        assert!(map.contains(11));
1815        assert!(!map.contains(12));
1816        assert!(!map.contains(3));
1817
1818        let map = RowAddrTreeMap::from(10..=12);
1819        assert!(map.contains(10));
1820        assert!(map.contains(11));
1821        assert!(map.contains(12));
1822        assert!(!map.contains(3));
1823    }
1824
1825    #[test]
1826    fn test_map_from_roaring() {
1827        let bitmap = RoaringTreemap::from_iter(&[0, 1, 1 << 32]);
1828        let map = RowAddrTreeMap::from(bitmap);
1829        assert!(map.contains(0) && map.contains(1) && map.contains(1 << 32));
1830        assert!(!map.contains(2));
1831    }
1832
1833    #[test]
1834    fn test_map_extend() {
1835        let mut map = RowAddrTreeMap::default();
1836        map.insert(0);
1837        map.insert_fragment(1);
1838
1839        let other_rows = [0, 2, 1 << 32 | 10, 3 << 32 | 5];
1840        map.extend(other_rows.iter().copied());
1841
1842        assert!(map.contains(0));
1843        assert!(map.contains(2));
1844        assert!(map.contains(1 << 32 | 5));
1845        assert!(map.contains(1 << 32 | 10));
1846        assert!(map.contains(3 << 32 | 5));
1847        assert!(!map.contains(3));
1848    }
1849
1850    #[test]
1851    fn test_map_extend_other_maps() {
1852        let mut map = RowAddrTreeMap::default();
1853        map.insert(0);
1854        map.insert_fragment(1);
1855        map.insert(4 << 32);
1856
1857        let mut other_map = rows(&[0, 2, 1 << 32 | 10, 3 << 32 | 5]);
1858        other_map.insert_fragment(4);
1859        map.extend(std::iter::once(other_map));
1860
1861        for id in [
1862            0,
1863            2,
1864            1 << 32 | 5,
1865            1 << 32 | 10,
1866            3 << 32 | 5,
1867            4 << 32,
1868            4 << 32 | 7,
1869        ] {
1870            assert!(map.contains(id), "Expected {} to be contained", id);
1871        }
1872        assert!(!map.contains(3));
1873    }
1874
1875    proptest::proptest! {
1876        #[test]
1877        fn test_map_serialization_roundtrip(
1878            values in proptest::collection::vec(
1879                (0..u32::MAX, proptest::option::of(proptest::collection::vec(0..u32::MAX, 0..1000))),
1880                0..10
1881            )
1882        ) {
1883            let mut mask = RowAddrTreeMap::default();
1884            for (fragment, rows) in values {
1885                if let Some(rows) = rows {
1886                    let bitmap = RoaringBitmap::from_iter(rows);
1887                    mask.insert_bitmap(fragment, bitmap);
1888                } else {
1889                    mask.insert_fragment(fragment);
1890                }
1891            }
1892
1893            let mut data = Vec::new();
1894            mask.serialize_into(&mut data).unwrap();
1895            let deserialized = RowAddrTreeMap::deserialize_from(data.as_slice()).unwrap();
1896            prop_assert_eq!(mask, deserialized);
1897        }
1898
1899        #[test]
1900        fn test_map_intersect(
1901            left_full_fragments in proptest::collection::vec(0..u32::MAX, 0..10),
1902            left_rows in proptest::collection::vec(0..u64::MAX, 0..1000),
1903            right_full_fragments in proptest::collection::vec(0..u32::MAX, 0..10),
1904            right_rows in proptest::collection::vec(0..u64::MAX, 0..1000),
1905        ) {
1906            let mut left = RowAddrTreeMap::default();
1907            for fragment in left_full_fragments.clone() {
1908                left.insert_fragment(fragment);
1909            }
1910            left.extend(left_rows.iter().copied());
1911
1912            let mut right = RowAddrTreeMap::default();
1913            for fragment in right_full_fragments.clone() {
1914                right.insert_fragment(fragment);
1915            }
1916            right.extend(right_rows.iter().copied());
1917
1918            let mut expected = RowAddrTreeMap::default();
1919            for fragment in &left_full_fragments {
1920                if right_full_fragments.contains(fragment) {
1921                    expected.insert_fragment(*fragment);
1922                }
1923            }
1924
1925            let left_in_right = left_rows.iter().filter(|row| {
1926                right_rows.contains(row)
1927                    || right_full_fragments.contains(&((*row >> 32) as u32))
1928            });
1929            expected.extend(left_in_right);
1930            let right_in_left = right_rows.iter().filter(|row| {
1931                left_rows.contains(row)
1932                    || left_full_fragments.contains(&((*row >> 32) as u32))
1933            });
1934            expected.extend(right_in_left);
1935
1936            let actual = left & right;
1937            prop_assert_eq!(expected, actual);
1938        }
1939
1940        #[test]
1941        fn test_map_union(
1942            left_full_fragments in proptest::collection::vec(0..u32::MAX, 0..10),
1943            left_rows in proptest::collection::vec(0..u64::MAX, 0..1000),
1944            right_full_fragments in proptest::collection::vec(0..u32::MAX, 0..10),
1945            right_rows in proptest::collection::vec(0..u64::MAX, 0..1000),
1946        ) {
1947            let mut left = RowAddrTreeMap::default();
1948            for fragment in left_full_fragments.clone() {
1949                left.insert_fragment(fragment);
1950            }
1951            left.extend(left_rows.iter().copied());
1952
1953            let mut right = RowAddrTreeMap::default();
1954            for fragment in right_full_fragments.clone() {
1955                right.insert_fragment(fragment);
1956            }
1957            right.extend(right_rows.iter().copied());
1958
1959            let mut expected = RowAddrTreeMap::default();
1960            for fragment in left_full_fragments {
1961                expected.insert_fragment(fragment);
1962            }
1963            for fragment in right_full_fragments {
1964                expected.insert_fragment(fragment);
1965            }
1966
1967            let combined_rows = left_rows.iter().chain(right_rows.iter());
1968            expected.extend(combined_rows);
1969
1970            let actual = left | right;
1971            for actual_key_val in &actual.inner {
1972                proptest::prop_assert!(expected.inner.contains_key(actual_key_val.0));
1973                let expected_val = expected.inner.get(actual_key_val.0).unwrap();
1974                prop_assert_eq!(
1975                    actual_key_val.1,
1976                    expected_val,
1977                    "error on key {}",
1978                    actual_key_val.0
1979                );
1980            }
1981            prop_assert_eq!(expected, actual);
1982        }
1983
1984        #[test]
1985        fn test_map_subassign_rows(
1986            left_full_fragments in proptest::collection::vec(0..u32::MAX, 0..10),
1987            left_rows in proptest::collection::vec(0..u64::MAX, 0..1000),
1988            right_rows in proptest::collection::vec(0..u64::MAX, 0..1000),
1989        ) {
1990            let mut left = RowAddrTreeMap::default();
1991            for fragment in left_full_fragments {
1992                left.insert_fragment(fragment);
1993            }
1994            left.extend(left_rows.iter().copied());
1995
1996            let mut right = RowAddrTreeMap::default();
1997            right.extend(right_rows.iter().copied());
1998
1999            let mut expected = left.clone();
2000            for row in right_rows {
2001                expected.remove(row);
2002            }
2003
2004            left -= &right;
2005            prop_assert_eq!(expected, left);
2006        }
2007
2008        #[test]
2009        fn test_map_subassign_frags(
2010            left_full_fragments in proptest::collection::vec(0..u32::MAX, 0..10),
2011            right_full_fragments in proptest::collection::vec(0..u32::MAX, 0..10),
2012            left_rows in proptest::collection::vec(0..u64::MAX, 0..1000),
2013        ) {
2014            let mut left = RowAddrTreeMap::default();
2015            for fragment in left_full_fragments {
2016                left.insert_fragment(fragment);
2017            }
2018            left.extend(left_rows.iter().copied());
2019
2020            let mut right = RowAddrTreeMap::default();
2021            for fragment in right_full_fragments.clone() {
2022                right.insert_fragment(fragment);
2023            }
2024
2025            let mut expected = left.clone();
2026            for fragment in right_full_fragments {
2027                expected.inner.remove(&fragment);
2028            }
2029
2030            left -= &right;
2031            prop_assert_eq!(expected, left);
2032        }
2033
2034        #[test]
2035        fn test_from_sorted_iter(
2036            mut rows in proptest::collection::vec(0..u64::MAX, 0..1000)
2037        ) {
2038            rows.sort();
2039            let num_rows = rows.len();
2040            let mask = RowAddrTreeMap::from_sorted_iter(rows).unwrap();
2041            prop_assert_eq!(mask.len(), Some(num_rows as u64));
2042        }
2043
2044
2045    }
2046
2047    #[test]
2048    fn test_row_addr_selection_deep_size_of() {
2049        use lance_core::deepsize::DeepSizeOf;
2050
2051        // Test Full variant - should have minimal size (just the enum discriminant)
2052        let full = RowAddrSelection::Full;
2053        let full_size = full.deep_size_of();
2054        // Full variant has no heap allocations beyond the enum itself
2055        assert!(full_size < 100); // Small sanity check
2056
2057        // Test Partial variant - should include bitmap size
2058        let mut bitmap = RoaringBitmap::new();
2059        bitmap.insert_range(0..100);
2060        let partial = RowAddrSelection::Partial(bitmap.clone());
2061        let partial_size = partial.deep_size_of();
2062        // Partial variant should be larger due to bitmap
2063        assert!(partial_size >= bitmap.serialized_size());
2064    }
2065
2066    #[test]
2067    fn test_row_addr_selection_union_all_with_full() {
2068        let full = RowAddrSelection::Full;
2069        let partial = RowAddrSelection::Partial(RoaringBitmap::from_iter(&[1, 2, 3]));
2070
2071        assert!(matches!(
2072            RowAddrSelection::union_all(&[&full, &partial]),
2073            RowAddrSelection::Full
2074        ));
2075
2076        let partial2 = RowAddrSelection::Partial(RoaringBitmap::from_iter(&[4, 5, 6]));
2077        let RowAddrSelection::Partial(bitmap) = RowAddrSelection::union_all(&[&partial, &partial2])
2078        else {
2079            panic!("Expected Partial");
2080        };
2081        assert!(bitmap.contains(1) && bitmap.contains(4));
2082    }
2083
2084    #[test]
2085    fn test_insert_range_unbounded_start() {
2086        let mut map = RowAddrTreeMap::default();
2087
2088        // Test exclusive start bound
2089        let count = map.insert_range((std::ops::Bound::Excluded(5), std::ops::Bound::Included(10)));
2090        assert_eq!(count, 5); // 6, 7, 8, 9, 10
2091        assert!(!map.contains(5));
2092        assert!(map.contains(6));
2093        assert!(map.contains(10));
2094
2095        // Test unbounded end
2096        let mut map2 = RowAddrTreeMap::default();
2097        let count = map2.insert_range(0..5);
2098        assert_eq!(count, 5);
2099        assert!(map2.contains(0));
2100        assert!(map2.contains(4));
2101        assert!(!map2.contains(5));
2102    }
2103
2104    #[test]
2105    fn test_remove_from_full_fragment() {
2106        let mut map = RowAddrTreeMap::default();
2107        map.insert_fragment(0);
2108
2109        // Verify it's a full fragment - get_fragment_bitmap returns None for Full
2110        for id in [0, 100, u32::MAX as u64] {
2111            assert!(map.contains(id));
2112        }
2113        assert!(map.get_fragment_bitmap(0).is_none());
2114
2115        // Remove a value from the full fragment
2116        assert!(map.remove(50));
2117
2118        // Now it should be partial (a full RoaringBitmap minus one value)
2119        assert!(map.contains(0) && !map.contains(50) && map.contains(100));
2120        assert!(map.get_fragment_bitmap(0).is_some());
2121    }
2122
2123    #[test]
2124    fn test_retain_fragments() {
2125        let mut map = RowAddrTreeMap::default();
2126        map.insert(0); // fragment 0
2127        map.insert(1 << 32 | 5); // fragment 1
2128        map.insert(2 << 32 | 10); // fragment 2
2129        map.insert_fragment(3); // fragment 3
2130
2131        map.retain_fragments([0, 2]);
2132
2133        assert!(map.contains(0) && map.contains(2 << 32 | 10));
2134        assert!(!map.contains(1 << 32 | 5) && !map.contains(3 << 32));
2135    }
2136
2137    #[test]
2138    fn test_bitor_assign_full_fragment() {
2139        // Test BitOrAssign when LHS has Full and RHS has Partial
2140        let mut map1 = RowAddrTreeMap::default();
2141        map1.insert_fragment(0);
2142        let mut map2 = RowAddrTreeMap::default();
2143        map2.insert(5);
2144
2145        map1 |= &map2;
2146        // Full | Partial = Full
2147        assert!(map1.contains(0) && map1.contains(5) && map1.contains(100));
2148
2149        // Test BitOrAssign when LHS has Partial and RHS has Full
2150        let mut map3 = RowAddrTreeMap::default();
2151        map3.insert(5);
2152        let mut map4 = RowAddrTreeMap::default();
2153        map4.insert_fragment(0);
2154
2155        map3 |= &map4;
2156        // Partial | Full = Full
2157        assert!(map3.contains(0) && map3.contains(5) && map3.contains(100));
2158    }
2159
2160    #[test]
2161    fn test_bitand_assign_full_fragments() {
2162        // Test BitAndAssign when both have Full for same fragment
2163        let mut map1 = RowAddrTreeMap::default();
2164        map1.insert_fragment(0);
2165        let mut map2 = RowAddrTreeMap::default();
2166        map2.insert_fragment(0);
2167
2168        map1 &= &map2;
2169        // Full & Full = Full
2170        assert!(map1.contains(0) && map1.contains(100));
2171
2172        // Test BitAndAssign when LHS Full, RHS Partial
2173        let mut map3 = RowAddrTreeMap::default();
2174        map3.insert_fragment(0);
2175        let mut map4 = RowAddrTreeMap::default();
2176        map4.insert(5);
2177        map4.insert(10);
2178
2179        map3 &= &map4;
2180        // Full & Partial([5,10]) = Partial([5,10])
2181        assert!(map3.contains(5) && map3.contains(10));
2182        assert!(!map3.contains(0) && !map3.contains(100));
2183
2184        // Test that empty intersection results in removal
2185        let mut map5 = RowAddrTreeMap::default();
2186        map5.insert(5);
2187        let mut map6 = RowAddrTreeMap::default();
2188        map6.insert(10);
2189
2190        map5 &= &map6;
2191        assert!(map5.is_empty());
2192    }
2193
2194    #[test]
2195    fn test_sub_assign_with_full_fragments() {
2196        // Test SubAssign when LHS is Full and RHS is Partial
2197        let mut map1 = RowAddrTreeMap::default();
2198        map1.insert_fragment(0);
2199        let mut map2 = RowAddrTreeMap::default();
2200        map2.insert(5);
2201        map2.insert(10);
2202
2203        map1 -= &map2;
2204        // Full - Partial([5,10]) = Full minus those values
2205        assert!(map1.contains(0) && map1.contains(100));
2206        assert!(!map1.contains(5) && !map1.contains(10));
2207
2208        // Test SubAssign when both are Full for same fragment
2209        let mut map3 = RowAddrTreeMap::default();
2210        map3.insert_fragment(0);
2211        let mut map4 = RowAddrTreeMap::default();
2212        map4.insert_fragment(0);
2213
2214        map3 -= &map4;
2215        // Full - Full = empty
2216        assert!(map3.is_empty());
2217
2218        // Test SubAssign when LHS is Partial and RHS is Full
2219        let mut map5 = RowAddrTreeMap::default();
2220        map5.insert(5);
2221        map5.insert(10);
2222        let mut map6 = RowAddrTreeMap::default();
2223        map6.insert_fragment(0);
2224
2225        map5 -= &map6;
2226        // Partial - Full = empty
2227        assert!(map5.is_empty());
2228    }
2229
2230    #[test]
2231    fn test_from_iterator_with_full_fragment() {
2232        // Test that inserting into a full fragment is a no-op
2233        let mut map = RowAddrTreeMap::default();
2234        map.insert_fragment(0);
2235
2236        // Extend with values that would go into fragment 0
2237        map.extend([5u64, 10, 100].iter());
2238
2239        // Should still be full fragment
2240        for id in [0, 5, 10, 100, u32::MAX as u64] {
2241            assert!(map.contains(id));
2242        }
2243    }
2244
2245    #[test]
2246    fn test_insert_range_excluded_end() {
2247        // Test excluded end bound (line 391-393)
2248        let mut map = RowAddrTreeMap::default();
2249        // Using RangeFrom with small range won't hit the unbounded case
2250        // Instead test Bound::Excluded for end
2251        let count = map.insert_range((std::ops::Bound::Included(5), std::ops::Bound::Excluded(10)));
2252        assert_eq!(count, 5); // 5, 6, 7, 8, 9
2253        assert!(map.contains(5));
2254        assert!(map.contains(9));
2255        assert!(!map.contains(10));
2256    }
2257
2258    #[test]
2259    fn test_bitand_assign_owned() {
2260        // Test BitAndAssign<Self> (owned, not reference)
2261        let mut map1 = RowAddrTreeMap::default();
2262        map1.insert(5);
2263        map1.insert(10);
2264
2265        // Using owned rhs (not reference)
2266        map1 &= rows(&[5, 15]);
2267
2268        assert!(map1.contains(5));
2269        assert!(!map1.contains(10) && !map1.contains(15));
2270    }
2271
2272    #[test]
2273    fn test_from_iter_with_full_fragment() {
2274        // When we collect into RowAddrTreeMap, it should handle duplicates
2275        let map: RowAddrTreeMap = vec![5u64, 10, 100].into_iter().collect();
2276        assert!(map.contains(5) && map.contains(10));
2277
2278        // Test that extending a map with full fragment ignores new values
2279        let mut map = RowAddrTreeMap::default();
2280        map.insert_fragment(0);
2281        for val in [5, 10, 100] {
2282            map.insert(val); // This should be no-op since fragment is full
2283        }
2284        // Still full fragment
2285        for id in [0, 5, u32::MAX as u64] {
2286            assert!(map.contains(id));
2287        }
2288    }
2289
2290    // ============================================================================
2291    // Tests for bitmap_to_ranges / ranges_to_bitmap
2292    // ============================================================================
2293
2294    #[test]
2295    fn test_bitmap_to_ranges_empty() {
2296        let bm = RoaringBitmap::new();
2297        assert!(bitmap_to_ranges(&bm).is_empty());
2298    }
2299
2300    #[test]
2301    fn test_bitmap_to_ranges_single() {
2302        let bm = RoaringBitmap::from_iter([5]);
2303        assert_eq!(bitmap_to_ranges(&bm), vec![5..6]);
2304    }
2305
2306    #[test]
2307    fn test_bitmap_to_ranges_contiguous() {
2308        let mut bm = RoaringBitmap::new();
2309        bm.insert_range(10..20);
2310        assert_eq!(bitmap_to_ranges(&bm), vec![10..20]);
2311    }
2312
2313    #[test]
2314    fn test_bitmap_to_ranges_multiple() {
2315        let mut bm = RoaringBitmap::new();
2316        bm.insert_range(0..3);
2317        bm.insert_range(10..15);
2318        bm.insert(100);
2319        assert_eq!(bitmap_to_ranges(&bm), vec![0..3, 10..15, 100..101]);
2320    }
2321
2322    #[test]
2323    fn test_ranges_to_bitmap_empty() {
2324        let bm = ranges_to_bitmap(&[], true);
2325        assert!(bm.is_empty());
2326    }
2327
2328    #[test]
2329    fn test_ranges_to_bitmap_sorted_short_ranges() {
2330        // avg len = 1, uses from_sorted_iter path
2331        let ranges = vec![0..1, 5..6, 10..11];
2332        let bm = ranges_to_bitmap(&ranges, true);
2333        assert!(bm.contains(0) && bm.contains(5) && bm.contains(10));
2334        assert_eq!(bm.len(), 3);
2335    }
2336
2337    #[test]
2338    fn test_ranges_to_bitmap_sorted_long_ranges() {
2339        // avg len = 100, uses insert_range path
2340        let ranges = vec![0..100, 200..300];
2341        let bm = ranges_to_bitmap(&ranges, true);
2342        assert_eq!(bm.len(), 200);
2343        assert!(bm.contains(0) && bm.contains(99));
2344        assert!(!bm.contains(100));
2345        assert!(bm.contains(200) && bm.contains(299));
2346    }
2347
2348    #[test]
2349    fn test_ranges_to_bitmap_unsorted() {
2350        let ranges = vec![200..300, 0..100];
2351        let bm = ranges_to_bitmap(&ranges, false);
2352        assert_eq!(bm.len(), 200);
2353        assert!(bm.contains(0) && bm.contains(250));
2354    }
2355
2356    #[test]
2357    fn test_bitmap_ranges_roundtrip() {
2358        let mut original = RoaringBitmap::new();
2359        original.insert_range(0..50);
2360        original.insert_range(100..200);
2361        original.insert(500);
2362        original.insert_range(1000..1010);
2363
2364        let ranges = bitmap_to_ranges(&original);
2365        let reconstructed = ranges_to_bitmap(&ranges, true);
2366        assert_eq!(original, reconstructed);
2367    }
2368
2369    // ============================================================================
2370    // Tests for RowIdSet
2371    // ============================================================================
2372
2373    fn row_ids(ids: &[u64]) -> RowIdSet {
2374        let mut set = RowIdSet::new();
2375        for &id in ids {
2376            set.inner.insert(id);
2377        }
2378        set
2379    }
2380
2381    #[test]
2382    fn test_row_id_set_construction() {
2383        let set = RowIdSet::new();
2384        assert!(set.is_empty());
2385        assert_eq!(set.len(), Some(0));
2386
2387        let set = row_ids(&[10, 20, 30]);
2388        assert!(!set.is_empty());
2389        assert_eq!(set.len(), Some(3));
2390        assert!(set.contains(10));
2391        assert!(set.contains(20));
2392        assert!(set.contains(30));
2393        assert!(!set.contains(15));
2394    }
2395
2396    #[test]
2397    fn test_row_id_set_remove() {
2398        let mut set = row_ids(&[10, 20, 30]);
2399
2400        assert!(!set.remove(15)); // Not present
2401        assert_eq!(set.len(), Some(3));
2402
2403        assert!(set.remove(20)); // Present
2404        assert_eq!(set.len(), Some(2));
2405        assert!(!set.contains(20));
2406        assert!(set.contains(10));
2407        assert!(set.contains(30));
2408
2409        assert!(!set.remove(20)); // Already removed
2410    }
2411
2412    #[test]
2413    fn test_row_id_set_union() {
2414        let set1 = row_ids(&[10, 20, 30]);
2415        let set2 = row_ids(&[20, 30, 40]);
2416
2417        let result = set1.union(&set2);
2418        assert_eq!(result.len(), Some(4));
2419        for id in [10, 20, 30, 40] {
2420            assert!(result.contains(id));
2421        }
2422    }
2423
2424    #[test]
2425    fn test_row_id_set_difference() {
2426        let set1 = row_ids(&[10, 20, 30, 40]);
2427        let set2 = row_ids(&[20, 40]);
2428
2429        let result = set1.difference(&set2);
2430        assert_eq!(result.len(), Some(2));
2431        assert!(result.contains(10));
2432        assert!(result.contains(30));
2433        assert!(!result.contains(20));
2434        assert!(!result.contains(40));
2435    }
2436
2437    #[test]
2438    fn test_row_id_set_union_all() {
2439        let set1 = row_ids(&[10, 20]);
2440        let set2 = row_ids(&[20, 30]);
2441        let set3 = row_ids(&[30, 40]);
2442
2443        let result = RowIdSet::union_all(&[&set1, &set2, &set3]);
2444        assert_eq!(result.len(), Some(4));
2445        for id in [10, 20, 30, 40] {
2446            assert!(result.contains(id));
2447        }
2448
2449        // Empty slice should return empty set
2450        let result = RowIdSet::union_all(&[]);
2451        assert!(result.is_empty());
2452    }
2453
2454    #[test]
2455    fn test_row_id_set_iter() {
2456        let set = row_ids(&[10, 20, 30]);
2457        let collected: Vec<u64> = set.iter().collect();
2458        assert_eq!(collected, vec![10, 20, 30]);
2459
2460        let empty = RowIdSet::new();
2461        assert_eq!(empty.iter().count(), 0);
2462    }
2463
2464    #[test]
2465    fn test_row_id_set_from_sorted_iter() {
2466        // Valid sorted input
2467        let set = RowIdSet::from_sorted_iter([10, 20, 30, 40]).unwrap();
2468        assert_eq!(set.len(), Some(4));
2469        for id in [10, 20, 30, 40] {
2470            assert!(set.contains(id));
2471        }
2472
2473        // Empty iterator
2474        let set = RowIdSet::from_sorted_iter(std::iter::empty()).unwrap();
2475        assert!(set.is_empty());
2476
2477        // Single element
2478        let set = RowIdSet::from_sorted_iter([42]).unwrap();
2479        assert_eq!(set.len(), Some(1));
2480        assert!(set.contains(42));
2481    }
2482
2483    #[test]
2484    fn test_row_id_set_from_sorted_iter_unsorted() {
2485        // Non-sorted input should return error
2486        let result = RowIdSet::from_sorted_iter([30, 10, 20]);
2487        assert!(result.is_err());
2488        assert!(result.unwrap_err().to_string().contains("non-sorted"));
2489    }
2490
2491    #[test]
2492    fn test_row_id_set_large_values() {
2493        // Test with large u64 values
2494        let large_ids = [u64::MAX - 10, u64::MAX - 5, u64::MAX - 1];
2495        let set = row_ids(&large_ids);
2496
2497        for &id in &large_ids {
2498            assert!(set.contains(id));
2499        }
2500        assert!(!set.contains(u64::MAX));
2501        assert_eq!(set.len(), Some(3));
2502    }
2503
2504    // ============================================================================
2505    // Tests for RowIdMask
2506    // ============================================================================
2507
2508    fn assert_row_id_mask_selects(mask: &RowIdMask, selected: &[u64], not_selected: &[u64]) {
2509        for &id in selected {
2510            assert!(mask.selected(id), "Expected row id {} to be selected", id);
2511        }
2512        for &id in not_selected {
2513            assert!(
2514                !mask.selected(id),
2515                "Expected row id {} to NOT be selected",
2516                id
2517            );
2518        }
2519    }
2520
2521    #[test]
2522    fn test_row_id_mask_construction() {
2523        let full_mask = RowIdMask::all_rows();
2524        assert_eq!(full_mask.max_len(), None);
2525        assert_row_id_mask_selects(&full_mask, &[0, 1, 100, u64::MAX - 1], &[]);
2526
2527        let empty_mask = RowIdMask::allow_nothing();
2528        assert_eq!(empty_mask.max_len(), Some(0));
2529        assert_row_id_mask_selects(&empty_mask, &[], &[0, 1, 100]);
2530
2531        let allow_list = RowIdMask::from_allowed(row_ids(&[10, 20, 30]));
2532        assert_eq!(allow_list.max_len(), Some(3));
2533        assert_row_id_mask_selects(&allow_list, &[10, 20, 30], &[0, 15, 25, 40]);
2534
2535        let block_list = RowIdMask::from_block(row_ids(&[10, 20, 30]));
2536        assert_eq!(block_list.max_len(), None);
2537        assert_row_id_mask_selects(&block_list, &[0, 15, 25, 40], &[10, 20, 30]);
2538    }
2539
2540    #[test]
2541    fn test_row_id_mask_selected_indices() {
2542        // Allow list
2543        let mask = RowIdMask::from_allowed(row_ids(&[10, 20, 40]));
2544        assert!(mask.selected_indices(std::iter::empty()).is_empty());
2545        assert_eq!(mask.selected_indices([25, 20, 14, 10].iter()), &[1, 3]);
2546
2547        // Block list
2548        let mask = RowIdMask::from_block(row_ids(&[10, 20, 40]));
2549        assert!(mask.selected_indices(std::iter::empty()).is_empty());
2550        assert_eq!(mask.selected_indices([25, 20, 14, 10].iter()), &[0, 2]);
2551    }
2552
2553    #[test]
2554    fn test_row_id_mask_also_allow() {
2555        // Allow list
2556        let mask = RowIdMask::from_allowed(row_ids(&[10, 20]));
2557        let new_mask = mask.also_allow(row_ids(&[20, 30, 40]));
2558        assert_eq!(
2559            new_mask,
2560            RowIdMask::from_allowed(row_ids(&[10, 20, 30, 40]))
2561        );
2562
2563        // Block list
2564        let mask = RowIdMask::from_block(row_ids(&[10, 20, 30]));
2565        let new_mask = mask.also_allow(row_ids(&[20, 40]));
2566        assert_eq!(new_mask, RowIdMask::from_block(row_ids(&[10, 30])));
2567    }
2568
2569    #[test]
2570    fn test_row_id_mask_also_block() {
2571        // Allow list
2572        let mask = RowIdMask::from_allowed(row_ids(&[10, 20, 30]));
2573        let new_mask = mask.also_block(row_ids(&[20, 40]));
2574        assert_eq!(new_mask, RowIdMask::from_allowed(row_ids(&[10, 30])));
2575
2576        // Block list
2577        let mask = RowIdMask::from_block(row_ids(&[10, 20]));
2578        let new_mask = mask.also_block(row_ids(&[20, 30, 40]));
2579        assert_eq!(new_mask, RowIdMask::from_block(row_ids(&[10, 20, 30, 40])));
2580    }
2581
2582    #[test]
2583    fn test_row_id_mask_iter_ids() {
2584        // Allow list
2585        let mask = RowIdMask::from_allowed(row_ids(&[10, 20, 30]));
2586        let ids: Vec<u64> = mask.iter_ids().unwrap().collect();
2587        assert_eq!(ids, vec![10, 20, 30]);
2588
2589        // Empty allow list
2590        let mask = RowIdMask::allow_nothing();
2591        let iter = mask.iter_ids();
2592        assert!(iter.is_some());
2593        assert_eq!(iter.unwrap().count(), 0);
2594
2595        // Block list
2596        let mask = RowIdMask::from_block(row_ids(&[10, 20, 30]));
2597        assert!(mask.iter_ids().is_none());
2598    }
2599
2600    #[test]
2601    fn test_row_id_mask_default() {
2602        let mask = RowIdMask::default();
2603        // Default should be BlockList with empty set (all rows allowed)
2604        assert_row_id_mask_selects(&mask, &[0, 1, 100, 1000], &[]);
2605        assert_eq!(mask.max_len(), None);
2606    }
2607
2608    #[test]
2609    fn test_row_id_mask_ops() {
2610        let mask = RowIdMask::default();
2611        assert_row_id_mask_selects(&mask, &[1, 5, 100], &[]);
2612
2613        let block_list = mask.also_block(row_ids(&[0, 5, 15]));
2614        assert_row_id_mask_selects(&block_list, &[1, 100], &[5]);
2615
2616        let allow_list = RowIdMask::from_allowed(row_ids(&[0, 2, 5]));
2617        assert_row_id_mask_selects(&allow_list, &[5], &[1, 100]);
2618    }
2619
2620    #[test]
2621    fn test_row_id_mask_combined_ops() {
2622        // Test combining allow and block operations
2623        let mask = RowIdMask::from_allowed(row_ids(&[10, 20, 30, 40, 50]));
2624        let mask = mask.also_block(row_ids(&[20, 40]));
2625        assert_row_id_mask_selects(&mask, &[10, 30, 50], &[20, 40]);
2626
2627        let mask = mask.also_allow(row_ids(&[20, 60]));
2628        assert_row_id_mask_selects(&mask, &[10, 20, 30, 50, 60], &[40]);
2629    }
2630
2631    #[test]
2632    fn test_row_id_mask_with_large_values() {
2633        let large_ids = [u64::MAX - 10, u64::MAX - 5, u64::MAX - 1];
2634
2635        // Allow list with large values
2636        let mask = RowIdMask::from_allowed(row_ids(&large_ids));
2637        for &id in &large_ids {
2638            assert!(mask.selected(id));
2639        }
2640        assert!(!mask.selected(u64::MAX));
2641        assert!(!mask.selected(0));
2642
2643        // Block list with large values
2644        let mask = RowIdMask::from_block(row_ids(&large_ids));
2645        for &id in &large_ids {
2646            assert!(!mask.selected(id));
2647        }
2648        assert!(mask.selected(u64::MAX));
2649        assert!(mask.selected(0));
2650    }
2651
2652    proptest::proptest! {
2653        #[test]
2654        fn test_row_id_set_from_sorted_iter_proptest(
2655            mut row_ids in proptest::collection::vec(0..u64::MAX, 0..1000)
2656        ) {
2657            row_ids.sort();
2658            row_ids.dedup();
2659            let num_rows = row_ids.len();
2660            let set = RowIdSet::from_sorted_iter(row_ids.clone()).unwrap();
2661            prop_assert_eq!(set.len(), Some(num_rows as u64));
2662            for id in row_ids {
2663                prop_assert!(set.contains(id));
2664            }
2665        }
2666
2667        #[test]
2668        fn test_row_id_set_union_proptest(
2669            ids1 in proptest::collection::vec(0..u64::MAX, 0..500),
2670            ids2 in proptest::collection::vec(0..u64::MAX, 0..500),
2671        ) {
2672            let set1 = row_ids(&ids1);
2673            let set2 = row_ids(&ids2);
2674
2675            let result = set1.union(&set2);
2676
2677            // All ids from both sets should be in result
2678            for id in ids1.iter().chain(ids2.iter()) {
2679                prop_assert!(result.contains(*id));
2680            }
2681
2682            // Result size should be union size
2683            let expected_size = ids1.iter().chain(ids2.iter()).collect::<std::collections::HashSet<_>>().len();
2684            prop_assert_eq!(result.len(), Some(expected_size as u64));
2685        }
2686
2687        #[test]
2688        fn test_row_id_set_difference_proptest(
2689            ids1 in proptest::collection::vec(0..u64::MAX, 0..500),
2690            ids2 in proptest::collection::vec(0..u64::MAX, 0..500),
2691        ) {
2692            let set1 = row_ids(&ids1);
2693            let set2 = row_ids(&ids2);
2694
2695            let result = set1.difference(&set2);
2696
2697            // Items in ids1 but not in ids2 should be in result
2698            for id in &ids1 {
2699                if !ids2.contains(id) {
2700                    prop_assert!(result.contains(*id));
2701                } else {
2702                    prop_assert!(!result.contains(*id));
2703                }
2704            }
2705        }
2706
2707        #[test]
2708        fn test_row_id_mask_allow_block_proptest(
2709            allow_ids in proptest::collection::vec(0..10000u64, 0..100),
2710            block_ids in proptest::collection::vec(0..10000u64, 0..100),
2711            test_ids in proptest::collection::vec(0..10000u64, 0..50),
2712        ) {
2713            let mask = RowIdMask::from_allowed(row_ids(&allow_ids))
2714                .also_block(row_ids(&block_ids));
2715
2716            for id in test_ids {
2717                let expected = allow_ids.contains(&id) && !block_ids.contains(&id);
2718                prop_assert_eq!(mask.selected(id), expected);
2719            }
2720        }
2721    }
2722}