Skip to main content

lance_encoding/encodings/logical/primitive/
all_null.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3
4use std::any::Any;
5use std::collections::VecDeque;
6use std::fmt::Debug;
7use std::ops::Range;
8use std::sync::Arc;
9use std::vec;
10
11use arrow_buffer::ScalarBuffer;
12use bytes::Bytes;
13use futures::FutureExt;
14use futures::future::BoxFuture;
15use lance_core::Result;
16use lance_core::cache::{Context, DeepSizeOf};
17use lance_core::error::Error;
18
19use crate::EncodingsIo;
20use crate::buffer::LanceBuffer;
21use crate::compression::{BlockDecompressor, DecompressionStrategy, create_rle_decompressor};
22use crate::data::{AllNullDataBlock, DataBlock};
23use crate::decoder::{DecodePageTask, DecodedPage, StructuralPageDecoder};
24use crate::encodings::physical::rle::{RleDecompressor, RleRuns};
25use crate::format::metadata::CompressiveEncoding;
26use crate::format::metadata::compressive_encoding::Compression;
27use crate::repdef::{DefinitionInterpretation, RepDefUnraveler, max_visible_level};
28
29use super::{
30    CachedPageData, NoCachedPageData, PageInitialization, PageInitializationBuffers, PageLoadTask,
31    StructuralPageScheduler,
32};
33
34/// How a complex-all-null page's rep/def level buffer is compressed on disk.
35/// Captured at scheduler construction so `initialize` can keep RLE levels in run
36/// form instead of expanding them.
37#[derive(Debug, Clone)]
38pub enum LevelCodec {
39    /// Raw little-endian u16 levels (no block compression).
40    Uncompressed,
41    /// RLE-compressed levels; the validated physical runs select their cached representation.
42    Rle(Arc<RleDecompressor>),
43    /// Any other block compression; decoded eagerly into [`LazyLevels::Dense`]
44    /// (these encodings don't expand, so laziness buys nothing).
45    Block(Arc<dyn BlockDecompressor>),
46}
47
48impl LevelCodec {
49    pub(super) fn try_new(
50        encoding: Option<&CompressiveEncoding>,
51        decompression_strategy: &dyn DecompressionStrategy,
52    ) -> Result<Self> {
53        match encoding {
54            None => Ok(Self::Uncompressed),
55            Some(encoding) => match encoding.compression.as_ref() {
56                Some(Compression::Rle(rle)) => Ok(Self::Rle(Arc::new(create_rle_decompressor(
57                    rle,
58                    decompression_strategy,
59                )?))),
60                _ => Ok(Self::Block(Arc::from(
61                    decompression_strategy.create_block_decompressor(encoding)?,
62                ))),
63            },
64        }
65    }
66}
67
68#[derive(Debug)]
69enum RunEnds {
70    U16(Box<[u16]>),
71    U32(Box<[u32]>),
72    U64(Box<[u64]>),
73}
74
75impl RunEnds {
76    fn width_for(num_values: usize) -> usize {
77        if u16::try_from(num_values).is_ok() {
78            std::mem::size_of::<u16>()
79        } else if u32::try_from(num_values).is_ok() {
80            std::mem::size_of::<u32>()
81        } else {
82            std::mem::size_of::<u64>()
83        }
84    }
85
86    fn len(&self) -> usize {
87        match self {
88            Self::U16(ends) => ends.len(),
89            Self::U32(ends) => ends.len(),
90            Self::U64(ends) => ends.len(),
91        }
92    }
93
94    fn get(&self, run: usize) -> usize {
95        match self {
96            Self::U16(ends) => ends[run] as usize,
97            Self::U32(ends) => ends[run] as usize,
98            Self::U64(ends) => ends[run] as usize,
99        }
100    }
101
102    fn partition_point(&self, logical_index: usize) -> usize {
103        match self {
104            Self::U16(ends) => ends.partition_point(|&end| end as usize <= logical_index),
105            Self::U32(ends) => ends.partition_point(|&end| end as usize <= logical_index),
106            Self::U64(ends) => ends.partition_point(|&end| end as usize <= logical_index),
107        }
108    }
109
110    fn deep_size(&self) -> usize {
111        match self {
112            Self::U16(ends) => std::mem::size_of_val(ends.as_ref()),
113            Self::U32(ends) => std::mem::size_of_val(ends.as_ref()),
114            Self::U64(ends) => std::mem::size_of_val(ends.as_ref()),
115        }
116    }
117}
118
119enum RunEndsBuilder {
120    U16(Vec<u16>),
121    U32(Vec<u32>),
122    U64(Vec<u64>),
123}
124
125impl RunEndsBuilder {
126    fn with_capacity(num_values: usize, capacity: usize) -> Self {
127        if u16::try_from(num_values).is_ok() {
128            Self::U16(Vec::with_capacity(capacity))
129        } else if u32::try_from(num_values).is_ok() {
130            Self::U32(Vec::with_capacity(capacity))
131        } else {
132            Self::U64(Vec::with_capacity(capacity))
133        }
134    }
135
136    fn push(&mut self, end: usize) -> Result<()> {
137        match self {
138            Self::U16(ends) => ends.push(
139                u16::try_from(end)
140                    .map_err(|_| Error::internal(format!("Run end {end} does not fit in u16")))?,
141            ),
142            Self::U32(ends) => ends.push(
143                u32::try_from(end)
144                    .map_err(|_| Error::internal(format!("Run end {end} does not fit in u32")))?,
145            ),
146            Self::U64(ends) => ends.push(end as u64),
147        }
148        Ok(())
149    }
150
151    fn set_last(&mut self, end: usize) -> Result<()> {
152        match self {
153            Self::U16(ends) => {
154                let last = ends.last_mut().ok_or_else(|| {
155                    Error::internal("Cannot extend an empty coalesced run buffer")
156                })?;
157                *last = u16::try_from(end)
158                    .map_err(|_| Error::internal(format!("Run end {end} does not fit in u16")))?;
159            }
160            Self::U32(ends) => {
161                let last = ends.last_mut().ok_or_else(|| {
162                    Error::internal("Cannot extend an empty coalesced run buffer")
163                })?;
164                *last = u32::try_from(end)
165                    .map_err(|_| Error::internal(format!("Run end {end} does not fit in u32")))?;
166            }
167            Self::U64(ends) => {
168                let last = ends.last_mut().ok_or_else(|| {
169                    Error::internal("Cannot extend an empty coalesced run buffer")
170                })?;
171                *last = end as u64;
172            }
173        }
174        Ok(())
175    }
176
177    fn finish(self) -> RunEnds {
178        match self {
179            Self::U16(ends) => RunEnds::U16(ends.into_boxed_slice()),
180            Self::U32(ends) => RunEnds::U32(ends.into_boxed_slice()),
181            Self::U64(ends) => RunEnds::U64(ends.into_boxed_slice()),
182        }
183    }
184}
185
186#[derive(Debug)]
187enum RunStorage {
188    Physical(RleRuns),
189    Coalesced { values: Box<[u16]>, ends: RunEnds },
190}
191
192impl RunStorage {
193    fn len(&self) -> usize {
194        match self {
195            Self::Physical(runs) => runs.num_values(),
196            Self::Coalesced { ends, .. } => ends.get(ends.len() - 1),
197        }
198    }
199
200    fn num_runs(&self) -> usize {
201        match self {
202            Self::Physical(runs) => runs.num_runs(),
203            Self::Coalesced { values, .. } => values.len(),
204        }
205    }
206
207    fn value(&self, run: usize) -> u16 {
208        match self {
209            Self::Physical(runs) => runs.value(run),
210            Self::Coalesced { values, .. } => values[run],
211        }
212    }
213
214    fn first_value_above(&self, max: u16) -> Option<(usize, u16)> {
215        (0..self.num_runs()).find_map(|run| {
216            let value = self.value(run);
217            (value > max).then_some((run, value))
218        })
219    }
220
221    fn seek(&self, position: &mut RunPosition, logical_index: usize) {
222        if logical_index >= self.len() {
223            *position = RunPosition {
224                run: self.num_runs(),
225                start: self.len(),
226                end: self.len(),
227            };
228            return;
229        }
230
231        match self {
232            Self::Physical(runs) => {
233                if position.run >= runs.num_runs()
234                    || position.end == 0
235                    || logical_index < position.start
236                {
237                    *position = RunPosition {
238                        run: 0,
239                        start: 0,
240                        end: runs.length(0),
241                    };
242                }
243                while position.end <= logical_index {
244                    self.advance(position);
245                }
246            }
247            Self::Coalesced { ends, .. } => {
248                if logical_index < position.start || logical_index >= position.end {
249                    let run = ends.partition_point(logical_index);
250                    *position = RunPosition {
251                        run,
252                        start: if run == 0 { 0 } else { ends.get(run - 1) },
253                        end: ends.get(run),
254                    };
255                }
256            }
257        }
258    }
259
260    fn advance(&self, position: &mut RunPosition) {
261        let next_run = position.run + 1;
262        if next_run >= self.num_runs() {
263            *position = RunPosition {
264                run: self.num_runs(),
265                start: self.len(),
266                end: self.len(),
267            };
268            return;
269        }
270
271        let start = position.end;
272        position.run = next_run;
273        position.start = start;
274        position.end = match self {
275            Self::Physical(runs) => start + runs.length(next_run),
276            Self::Coalesced { ends, .. } => ends.get(next_run),
277        };
278    }
279
280    fn deep_size(&self) -> usize {
281        match self {
282            Self::Physical(runs) => runs.deep_size(),
283            Self::Coalesced { values, ends } => {
284                std::mem::size_of_val(values.as_ref()) + ends.deep_size()
285            }
286        }
287    }
288}
289
290/// Rep/def levels for a complex-all-null page.
291///
292/// RLE pages retain the smallest of their validated physical runs, coalesced
293/// runs, and dense values. The decoder materializes only the per-drain slices
294/// it touches.
295#[derive(Debug, Clone)]
296enum LazyLevels {
297    Dense(ScalarBuffer<u16>),
298    Runs(Arc<RunStorage>),
299}
300
301#[derive(Debug, Clone, Copy, PartialEq, Eq)]
302enum LevelPlan {
303    Physical,
304    Coalesced,
305    Dense,
306}
307
308#[derive(Debug, Default, Clone, Copy)]
309struct RunPosition {
310    run: usize,
311    start: usize,
312    end: usize,
313}
314
315/// Monotonic forward cursor into a [`LazyLevels`] sequence.
316///
317/// Drains seek to strictly increasing rows, so each [`LazyLevels::seek_row_start`]
318/// resumes from the last position instead of rescanning — every run is visited at
319/// most once per page while locating and counting level ranges.
320#[derive(Debug, Default, Clone, Copy)]
321struct LevelCursor {
322    /// Logical level index where the current row begins.
323    level: usize,
324    /// Row index at `level` (the number of `max_rep` occurrences before it).
325    row: u64,
326    /// Run containing `level`. Unused for [`LazyLevels::Dense`].
327    run: RunPosition,
328}
329
330impl LazyLevels {
331    fn from_rle_runs(runs: RleRuns) -> Result<Self> {
332        let plan = Self::select_plan(&runs);
333        match plan {
334            LevelPlan::Physical => Ok(Self::Runs(Arc::new(RunStorage::Physical(
335                runs.into_owned(),
336            )))),
337            LevelPlan::Coalesced => Self::build_coalesced(runs),
338            LevelPlan::Dense => Self::build_dense(runs),
339        }
340    }
341
342    /// Minimize retained payload bytes first, then expected traversal work.
343    /// If both are equal, keep the physical runs and avoid another allocation.
344    fn select_plan(runs: &RleRuns) -> LevelPlan {
345        if runs.num_values() == 0 {
346            return LevelPlan::Dense;
347        }
348
349        let run_storage_size = std::mem::size_of::<RunStorage>() as u128;
350        let physical_size = run_storage_size + runs.owned_size() as u128;
351        let coalesced_size = run_storage_size
352            + (runs.coalesced_runs() as u128)
353                * (std::mem::size_of::<u16>() + RunEnds::width_for(runs.num_values())) as u128;
354        let dense_size = (runs.num_values() as u128) * std::mem::size_of::<u16>() as u128;
355        [
356            (physical_size, runs.num_runs(), 0usize, LevelPlan::Physical),
357            (
358                coalesced_size,
359                runs.coalesced_runs(),
360                1usize,
361                LevelPlan::Coalesced,
362            ),
363            (dense_size, runs.num_values(), 2usize, LevelPlan::Dense),
364        ]
365        .into_iter()
366        .min_by_key(|(size, traversal, priority, _)| (*size, *traversal, *priority))
367        .map(|(_, _, _, plan)| plan)
368        .unwrap_or(LevelPlan::Dense)
369    }
370
371    fn build_coalesced(runs: RleRuns) -> Result<Self> {
372        let mut values = Vec::with_capacity(runs.coalesced_runs());
373        let mut ends = RunEndsBuilder::with_capacity(runs.num_values(), runs.coalesced_runs());
374        let mut logical_end = 0usize;
375        for (value, length) in runs.iter() {
376            logical_end = logical_end
377                .checked_add(length)
378                .ok_or_else(|| Error::internal("Validated RLE run length sum overflowed usize"))?;
379            if values.last().copied() == Some(value) {
380                ends.set_last(logical_end)?;
381            } else {
382                values.push(value);
383                ends.push(logical_end)?;
384            }
385        }
386        Ok(Self::Runs(Arc::new(RunStorage::Coalesced {
387            values: values.into_boxed_slice(),
388            ends: ends.finish(),
389        })))
390    }
391
392    fn build_dense(runs: RleRuns) -> Result<Self> {
393        let mut values = Vec::new();
394        values.try_reserve_exact(runs.num_values()).map_err(|_| {
395            Error::internal(format!(
396                "Cannot allocate {} dense repetition/definition levels",
397                runs.num_values()
398            ))
399        })?;
400        for (value, length) in runs.iter() {
401            values.resize(values.len() + length, value);
402        }
403        Ok(Self::Dense(ScalarBuffer::from(values)))
404    }
405
406    fn len(&self) -> usize {
407        match self {
408            Self::Dense(buf) => buf.len(),
409            Self::Runs(runs) => runs.len(),
410        }
411    }
412
413    fn validate_max(&self, level_type: &str, max: u16) -> Result<()> {
414        let invalid = match self {
415            Self::Dense(levels) => levels
416                .iter()
417                .enumerate()
418                .find_map(|(index, &value)| (value > max).then_some(("index", index, value))),
419            Self::Runs(runs) => runs
420                .first_value_above(max)
421                .map(|(run, value)| ("run", run, value)),
422        };
423        if let Some((position_type, position, value)) = invalid {
424            return Err(Error::invalid_input_source(
425                format!(
426                    "Invalid {level_type} level {value} at {position_type} {position}: maximum is {max}"
427                )
428                .into(),
429            ));
430        }
431        Ok(())
432    }
433
434    /// Advance `cursor` to the start of row `target_row`, returning that row's
435    /// starting level index.
436    ///
437    /// Rows begin at `max_rep` positions, so this finds the `target_row`-th one.
438    /// `target_row` must be `>= cursor.row`: the cursor only moves forward, which
439    /// is what keeps a full page decode O(runs) rather than O(rows).
440    fn seek_row_start(
441        &self,
442        cursor: &mut LevelCursor,
443        target_row: u64,
444        max_rep: u16,
445    ) -> Result<usize> {
446        let mut need = target_row.checked_sub(cursor.row).ok_or_else(|| {
447            Error::internal(format!(
448                "Complex all-null row ranges are not sorted: target row {target_row} follows {}",
449                cursor.row
450            ))
451        })?;
452        if need == 0 {
453            return Ok(cursor.level);
454        }
455        match self {
456            Self::Dense(buf) => {
457                let mut level = cursor.level;
458                while need > 0 {
459                    if level >= buf.len() {
460                        return Err(Error::internal(
461                            "Invalid complex all-null layout: repetition buffer too short",
462                        ));
463                    }
464                    if buf[level] != max_rep {
465                        return Err(Error::internal(
466                            "Invalid complex all-null layout: row did not start at max repetition level",
467                        ));
468                    }
469                    level += 1;
470                    while level < buf.len() && buf[level] != max_rep {
471                        level += 1;
472                    }
473                    need -= 1;
474                }
475                cursor.level = level;
476                cursor.row = target_row;
477                Ok(level)
478            }
479            Self::Runs(runs) => {
480                let mut level = cursor.level;
481                let mut run = cursor.run;
482                runs.seek(&mut run, level);
483                while need > 0 {
484                    if run.run >= runs.num_runs() {
485                        return Err(Error::internal(
486                            "Invalid complex all-null layout: repetition buffer too short",
487                        ));
488                    }
489                    if runs.value(run.run) != max_rep {
490                        return Err(Error::internal(
491                            "Invalid complex all-null layout: row did not start at max repetition level",
492                        ));
493                    }
494                    let avail = (run.end - level) as u64;
495                    if need < avail {
496                        // Target lands inside this max-rep run.
497                        level += need as usize;
498                        need = 0;
499                    } else {
500                        // Consume every row start in this run, then skip the
501                        // trailing non-max-rep runs to reach the next row start.
502                        need -= avail;
503                        runs.advance(&mut run);
504                        while run.run < runs.num_runs() && runs.value(run.run) != max_rep {
505                            runs.advance(&mut run);
506                        }
507                        level = if run.run < runs.num_runs() {
508                            run.start
509                        } else {
510                            self.len()
511                        };
512                    }
513                }
514                cursor.level = level;
515                cursor.row = target_row;
516                cursor.run = run;
517                Ok(level)
518            }
519        }
520    }
521
522    /// Count of levels in `range` that are `<= max`, resuming from `*run_cursor`
523    /// and leaving it on the last run that overlaps `range`.
524    ///
525    /// Successive calls must pass ascending, non-overlapping ranges (`range.start
526    /// >=` the previous `range.end`) so runs are swept at most once per page.
527    fn count_le_cursor(
528        &self,
529        run_cursor: &mut RunPosition,
530        range: Range<usize>,
531        max: u16,
532    ) -> (u64, RunPosition) {
533        if range.is_empty() {
534            return (0, *run_cursor);
535        }
536        match self {
537            Self::Dense(buf) => (
538                buf[range].iter().filter(|&&d| d <= max).count() as u64,
539                RunPosition::default(),
540            ),
541            Self::Runs(runs) => {
542                // Advance to the first run overlapping the range.
543                runs.seek(run_cursor, range.start);
544                let start = *run_cursor;
545                let mut count = 0u64;
546                let mut current = *run_cursor;
547                while current.run < runs.num_runs() && current.start < range.end {
548                    if runs.value(current.run) <= max {
549                        let lo = current.start.max(range.start);
550                        let hi = current.end.min(range.end);
551                        count += (hi - lo) as u64;
552                    }
553                    if current.end >= range.end {
554                        break;
555                    }
556                    runs.advance(&mut current);
557                }
558                // Resume the next (ascending) range from the last overlapping run;
559                // `current` remains valid because `range` is non-empty.
560                *run_cursor = current;
561                (count, start)
562            }
563        }
564    }
565
566    fn extend_into(&self, range: Range<usize>, run: RunPosition, out: &mut Vec<u16>) {
567        if range.is_empty() {
568            return;
569        }
570        match self {
571            Self::Dense(buf) => out.extend_from_slice(&buf[range]),
572            Self::Runs(runs) => {
573                let mut current = run;
574                runs.seek(&mut current, range.start);
575                while current.run < runs.num_runs() && current.start < range.end {
576                    let lo = current.start.max(range.start);
577                    let hi = current.end.min(range.end);
578                    if hi > lo {
579                        out.resize(out.len() + (hi - lo), runs.value(current.run));
580                    }
581                    runs.advance(&mut current);
582                }
583            }
584        }
585    }
586
587    #[cfg(test)]
588    fn deep_size(&self) -> usize {
589        self.deep_size_of_children(&mut Context::new())
590    }
591}
592
593impl DeepSizeOf for LazyLevels {
594    fn deep_size_of_children(&self, ctx: &mut Context) -> usize {
595        match self {
596            Self::Dense(buf) => buf.deep_size_of_children(ctx),
597            Self::Runs(runs) => {
598                let pointer = Arc::as_ptr(runs) as *const () as usize;
599                if ctx.mark_seen(pointer) {
600                    std::mem::size_of_val(runs.as_ref()) + runs.deep_size()
601                } else {
602                    0
603                }
604            }
605        }
606    }
607}
608
609fn validate_complex_all_null_levels(
610    rep: &Option<LazyLevels>,
611    def: &Option<LazyLevels>,
612    max_rep: u16,
613    max_def: u16,
614) -> Result<()> {
615    if let Some(rep) = rep {
616        rep.validate_max("repetition", max_rep)?;
617    }
618    if let Some(def) = def {
619        def.validate_max("definition", max_def)?;
620    }
621    if let (Some(rep), Some(def)) = (rep, def)
622        && rep.len() != def.len()
623    {
624        return Err(Error::invalid_input_source(
625            format!(
626                "Mismatched complex all-null level counts: repetition has {}, definition has {}",
627                rep.len(),
628                def.len()
629            )
630            .into(),
631        ));
632    }
633    Ok(())
634}
635
636fn expected_level_bytes(num_values: u64, level_type: &str) -> Result<usize> {
637    usize::try_from(num_values)
638        .ok()
639        .and_then(|num_values| num_values.checked_mul(std::mem::size_of::<u16>()))
640        .ok_or_else(|| {
641            Error::invalid_input_source(
642                format!("{level_type} level count {num_values} does not fit in memory").into(),
643            )
644        })
645}
646
647fn dense_levels_from_block(
648    decompressed: DataBlock,
649    num_values: u64,
650    level_type: &str,
651) -> Result<LazyLevels> {
652    let DataBlock::FixedWidth(block) = decompressed else {
653        return Err(Error::invalid_input_source(
654            format!("Expected fixed-width data block for {level_type} levels").into(),
655        ));
656    };
657    if block.num_values != num_values {
658        return Err(Error::invalid_input_source(
659            format!(
660                "Unexpected {level_type} level count after decompression: expected {num_values}, got {}",
661                block.num_values
662            )
663            .into(),
664        ));
665    }
666    if block.bits_per_value != 16 {
667        return Err(Error::invalid_input_source(
668            format!(
669                "Unexpected {level_type} level bit width after decompression: expected 16, got {}",
670                block.bits_per_value
671            )
672            .into(),
673        ));
674    }
675    let expected_bytes = expected_level_bytes(num_values, level_type)?;
676    if block.data.len() != expected_bytes {
677        return Err(Error::invalid_input_source(
678            format!(
679                "Unexpected decompressed {level_type} level size: expected {expected_bytes} bytes for {num_values} values, got {}",
680                block.data.len()
681            )
682            .into(),
683        ));
684    }
685    Ok(LazyLevels::Dense(block.data.borrow_to_typed_slice::<u16>()))
686}
687
688#[derive(Debug)]
689struct CachedComplexAllNullState {
690    rep: Option<LazyLevels>,
691    def: Option<LazyLevels>,
692}
693
694impl DeepSizeOf for CachedComplexAllNullState {
695    fn deep_size_of_children(&self, ctx: &mut Context) -> usize {
696        self.rep.deep_size_of_children(ctx) + self.def.deep_size_of_children(ctx)
697    }
698}
699
700impl CachedPageData for CachedComplexAllNullState {
701    fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync + 'static> {
702        self
703    }
704}
705
706/// A scheduler for all-null data that has repetition and definition levels
707///
708/// We still need to do some I/O in this case because we need to figure out what kind of null we
709/// are dealing with (null list, null struct, what level null struct, etc.)
710///
711/// TODO: Right now we just load the entire rep/def at initialization time and cache it.  This is a touch
712/// RAM aggressive and maybe we want something more lazy in the future.  On the other hand, it's simple
713/// and fast so...maybe not :)
714#[derive(Debug)]
715pub struct ComplexAllNullScheduler {
716    // Set from protobuf
717    buffer_offsets_and_sizes: Arc<[(u64, u64)]>,
718    def_meaning: Arc<[DefinitionInterpretation]>,
719    repdef: Option<Arc<CachedComplexAllNullState>>,
720    max_rep: u16,
721    max_def: u16,
722    max_visible_level: u16,
723    rep_codec: LevelCodec,
724    def_codec: LevelCodec,
725    num_rep_values: u64,
726    num_def_values: u64,
727}
728
729impl ComplexAllNullScheduler {
730    pub(crate) fn new(
731        buffer_offsets_and_sizes: Arc<[(u64, u64)]>,
732        def_meaning: Arc<[DefinitionInterpretation]>,
733        rep_codec: LevelCodec,
734        def_codec: LevelCodec,
735        num_rep_values: u64,
736        num_def_values: u64,
737    ) -> Self {
738        let max_rep = def_meaning.iter().filter(|l| l.is_list()).count() as u16;
739        let max_def = def_meaning
740            .iter()
741            .map(|meaning| meaning.num_def_levels())
742            .sum::<u16>();
743        let max_visible_level = max_visible_level(&def_meaning);
744        Self {
745            buffer_offsets_and_sizes,
746            def_meaning,
747            repdef: None,
748            max_rep,
749            max_def,
750            max_visible_level,
751            rep_codec,
752            def_codec,
753            num_rep_values,
754            num_def_values,
755        }
756    }
757}
758
759impl StructuralPageScheduler for ComplexAllNullScheduler {
760    fn init_layout(&self) -> Result<PageInitialization> {
761        // Fully load the rep & def buffers, as needed
762        let (rep_pos, rep_size) = self.buffer_offsets_and_sizes[0];
763        let (def_pos, def_size) = self.buffer_offsets_and_sizes[1];
764
765        Ok(PageInitialization::new([
766            (rep_size > 0).then_some(rep_pos..rep_pos + rep_size),
767            (def_size > 0).then_some(def_pos..def_pos + def_size),
768        ]))
769    }
770
771    fn init_from_buffers<'a>(
772        &'a mut self,
773        buffers: PageInitializationBuffers,
774        _io: &Arc<dyn EncodingsIo>,
775    ) -> BoxFuture<'a, Result<Arc<dyn CachedPageData>>> {
776        let rep_codec = self.rep_codec.clone();
777        let def_codec = self.def_codec.clone();
778        let num_rep_values = self.num_rep_values;
779        let num_def_values = self.num_def_values;
780        let max_rep = self.max_rep;
781        let max_def = self.max_def;
782
783        async move {
784            let [rep_bytes, def_bytes] = buffers.try_into_array("complex all-null")?;
785
786            // RLE levels select the smallest validated cache representation;
787            // everything else expands eagerly to `LazyLevels::Dense`.
788            let build_levels = |compressed_bytes: Bytes,
789                                codec: &LevelCodec,
790                                num_values: u64,
791                                level_type: &str|
792             -> Result<LazyLevels> {
793                match codec {
794                    LevelCodec::Uncompressed => {
795                        if num_values == 0 {
796                            if !compressed_bytes
797                                .len()
798                                .is_multiple_of(std::mem::size_of::<u16>())
799                            {
800                                return Err(Error::invalid_input_source(
801                                    format!(
802                                        "Unexpected uncompressed {level_type} level size: {} bytes is not divisible by {}",
803                                        compressed_bytes.len(),
804                                        std::mem::size_of::<u16>()
805                                    )
806                                    .into(),
807                                ));
808                            }
809                        } else {
810                            let expected_bytes = expected_level_bytes(num_values, level_type)?;
811                            if compressed_bytes.len() != expected_bytes {
812                                return Err(Error::invalid_input_source(
813                                    format!(
814                                        "Unexpected uncompressed {level_type} level size: expected {expected_bytes} bytes for {num_values} values, got {}",
815                                        compressed_bytes.len()
816                                    )
817                                    .into(),
818                                ));
819                            }
820                        }
821                        let buffer = LanceBuffer::from_bytes(compressed_bytes, 2);
822                        Ok(LazyLevels::Dense(buffer.borrow_to_typed_slice::<u16>()))
823                    }
824                    LevelCodec::Rle(decompressor) => {
825                        let frame = LanceBuffer::from_bytes(compressed_bytes, 1);
826                        let runs = decompressor.decode_u16_runs(frame, num_values)?;
827                        LazyLevels::from_rle_runs(runs)
828                    }
829                    LevelCodec::Block(decompressor) => {
830                        let frame = LanceBuffer::from_bytes(compressed_bytes, 1);
831                        let decompressed = decompressor.decompress(Some(frame), num_values)?;
832                        dense_levels_from_block(decompressed, num_values, level_type)
833                    }
834                }
835            };
836
837            let rep = if let Some(rep) = rep_bytes {
838                Some(build_levels(rep, &rep_codec, num_rep_values, "repetition")?)
839            } else {
840                None
841            };
842
843            let def = if let Some(def) = def_bytes {
844                Some(build_levels(def, &def_codec, num_def_values, "definition")?)
845            } else {
846                None
847            };
848
849            validate_complex_all_null_levels(&rep, &def, max_rep, max_def)?;
850            let repdef = Arc::new(CachedComplexAllNullState { rep, def });
851
852            Ok(repdef as Arc<dyn CachedPageData>)
853        }
854        .boxed()
855    }
856
857    fn try_load(&mut self, data: &Arc<dyn CachedPageData>) -> Result<()> {
858        self.repdef = Some(data.clone().as_arc_any().downcast().map_err(|_| {
859            Error::invalid_input_source(
860                "Cached complex all-null page data has an unexpected type".into(),
861            )
862        })?);
863        Ok(())
864    }
865
866    fn schedule_ranges(
867        &self,
868        ranges: &[Range<u64>],
869        _io: &Arc<dyn EncodingsIo>,
870    ) -> Result<Vec<PageLoadTask>> {
871        let ranges = VecDeque::from_iter(ranges.iter().cloned());
872        let num_rows = ranges.iter().map(|r| r.end - r.start).sum::<u64>();
873        let decoder = Box::new(ComplexAllNullPageDecoder {
874            ranges,
875            rep: self.repdef.as_ref().unwrap().rep.clone(),
876            def: self.repdef.as_ref().unwrap().def.clone(),
877            num_rows,
878            def_meaning: self.def_meaning.clone(),
879            max_rep: self.max_rep,
880            max_visible_level: self.max_visible_level,
881            rep_cursor: LevelCursor::default(),
882            def_run_cursor: RunPosition::default(),
883        }) as Box<dyn StructuralPageDecoder>;
884        let page_load_task = PageLoadTask {
885            decoder_fut: std::future::ready(Ok(decoder)).boxed(),
886            num_rows,
887        };
888        Ok(vec![page_load_task])
889    }
890}
891
892#[derive(Debug)]
893pub struct ComplexAllNullPageDecoder {
894    ranges: VecDeque<Range<u64>>,
895    rep: Option<LazyLevels>,
896    def: Option<LazyLevels>,
897    num_rows: u64,
898    def_meaning: Arc<[DefinitionInterpretation]>,
899    max_rep: u16,
900    max_visible_level: u16,
901    /// Monotonic cursor into `rep` tracking the current row's level start.
902    rep_cursor: LevelCursor,
903    /// Monotonic run cursor into `def` for `count_le_cursor`.
904    def_run_cursor: RunPosition,
905}
906
907impl ComplexAllNullPageDecoder {
908    fn drain_ranges(&mut self, num_rows: u64) -> Vec<Range<u64>> {
909        let mut rows_desired = num_rows;
910        let mut ranges = Vec::with_capacity(self.ranges.len());
911        while rows_desired > 0 {
912            let front = self.ranges.front_mut().unwrap();
913            let avail = front.end - front.start;
914            if avail > rows_desired {
915                ranges.push(front.start..front.start + rows_desired);
916                front.start += rows_desired;
917                rows_desired = 0;
918            } else {
919                ranges.push(self.ranges.pop_front().unwrap());
920                rows_desired -= avail;
921            }
922        }
923        ranges
924    }
925
926    /// Level index at which row `target_row` starts, advancing the monotonic
927    /// repetition cursor. Callers must request non-decreasing `target_row`.
928    fn seek_row_start(&mut self, target_row: u64) -> Result<usize> {
929        match &self.rep {
930            Some(rep) => rep.seek_row_start(&mut self.rep_cursor, target_row, self.max_rep),
931            None => {
932                // Without repetition every level is its own row.
933                self.rep_cursor.row = target_row;
934                self.rep_cursor.level = target_row as usize;
935                Ok(target_row as usize)
936            }
937        }
938    }
939
940    /// Number of visible items in the level range `levels` (definition levels
941    /// `<= max_visible_level`), advancing the monotonic definition cursor.
942    fn count_visible(&mut self, levels: Range<usize>) -> Result<(u64, RunPosition)> {
943        match &self.def {
944            Some(def) => {
945                if levels.end > def.len() {
946                    return Err(Error::internal(
947                        "Invalid complex all-null layout: definition buffer too short",
948                    ));
949                }
950                Ok(def.count_le_cursor(&mut self.def_run_cursor, levels, self.max_visible_level))
951            }
952            None => Ok(((levels.end - levels.start) as u64, RunPosition::default())),
953        }
954    }
955}
956
957impl StructuralPageDecoder for ComplexAllNullPageDecoder {
958    fn drain(&mut self, num_rows: u64) -> Result<Box<dyn DecodePageTask>> {
959        let drained_ranges = self.drain_ranges(num_rows);
960        let mut level_slices: Vec<LevelSlice> = Vec::with_capacity(drained_ranges.len());
961        let mut visible_items_total = 0;
962
963        // Each row range is one contiguous level slice `[start_row_level,
964        // end_row_level)`, so we seek both boundaries and count its visibility at
965        // once rather than per row. The cursors only move forward, so locating and
966        // counting all requested ranges visits each intervening run at most once.
967        for range in drained_ranges {
968            let level_start = self.seek_row_start(range.start)?;
969            let rep_run = self.rep_cursor.run;
970            let level_end = self.seek_row_start(range.end)?;
971            let (visible_items, def_run) = self.count_visible(level_start..level_end)?;
972            visible_items_total += visible_items;
973            if let Some(last) = level_slices.last_mut()
974                && last.range.end == level_start
975            {
976                last.range.end = level_end;
977            } else {
978                level_slices.push(LevelSlice {
979                    range: level_start..level_end,
980                    rep_run,
981                    def_run,
982                });
983            }
984        }
985
986        Ok(Box::new(DecodeComplexAllNullTask {
987            level_slices,
988            visible_items_total,
989            rep: self.rep.clone(),
990            def: self.def.clone(),
991            def_meaning: self.def_meaning.clone(),
992            max_visible_level: self.max_visible_level,
993        }))
994    }
995
996    fn num_rows(&self) -> u64 {
997        self.num_rows
998    }
999}
1000
1001/// We use `level_slices` to slice into `rep` and `def` and create rep/def buffers
1002/// for the null data.
1003#[derive(Debug, Clone)]
1004struct LevelSlice {
1005    range: Range<usize>,
1006    rep_run: RunPosition,
1007    def_run: RunPosition,
1008}
1009
1010#[derive(Clone, Copy)]
1011enum LevelKind {
1012    Repetition,
1013    Definition,
1014}
1015
1016impl LevelSlice {
1017    fn run(&self, kind: LevelKind) -> RunPosition {
1018        match kind {
1019            LevelKind::Repetition => self.rep_run,
1020            LevelKind::Definition => self.def_run,
1021        }
1022    }
1023}
1024
1025#[derive(Debug)]
1026pub struct DecodeComplexAllNullTask {
1027    level_slices: Vec<LevelSlice>,
1028    visible_items_total: u64,
1029    rep: Option<LazyLevels>,
1030    def: Option<LazyLevels>,
1031    def_meaning: Arc<[DefinitionInterpretation]>,
1032    max_visible_level: u16,
1033}
1034
1035impl DecodeComplexAllNullTask {
1036    fn decode_level(&self, levels: &Option<LazyLevels>, kind: LevelKind) -> Option<Vec<u16>> {
1037        levels.as_ref().map(|levels| {
1038            let num_levels = self
1039                .level_slices
1040                .iter()
1041                .map(|slice| slice.range.end - slice.range.start)
1042                .sum();
1043            let mut referenced_levels = Vec::with_capacity(num_levels);
1044            for slice in &self.level_slices {
1045                levels.extend_into(slice.range.clone(), slice.run(kind), &mut referenced_levels);
1046            }
1047            referenced_levels
1048        })
1049    }
1050}
1051
1052impl DecodePageTask for DecodeComplexAllNullTask {
1053    fn decode(self: Box<Self>) -> Result<DecodedPage> {
1054        let rep = self.decode_level(&self.rep, LevelKind::Repetition);
1055        let def = self.decode_level(&self.def, LevelKind::Definition);
1056
1057        // If there are definition levels there may be empty / null lists which are not visible
1058        // in the items array.  We need to account for that here to figure out how many values
1059        // should be in the items array.
1060        let num_values = if let Some(def) = &def {
1061            def.iter().filter(|&d| *d <= self.max_visible_level).count() as u64
1062        } else {
1063            self.visible_items_total
1064        };
1065
1066        let data = DataBlock::AllNull(AllNullDataBlock { num_values });
1067        let unraveler = RepDefUnraveler::new(rep, def, self.def_meaning, num_values);
1068        Ok(DecodedPage {
1069            data,
1070            repdef: unraveler,
1071        })
1072    }
1073}
1074
1075/// A scheduler for simple all-null data
1076///
1077/// "simple" all-null data is data that is all null and only has a single level of definition and
1078/// no repetition.  We don't need to read any data at all in this case.
1079#[derive(Debug, Default)]
1080pub struct SimpleAllNullScheduler {}
1081
1082impl StructuralPageScheduler for SimpleAllNullScheduler {
1083    fn needs_initialization(&self) -> bool {
1084        false
1085    }
1086
1087    fn init_layout(&self) -> Result<PageInitialization> {
1088        Ok(PageInitialization::new([]))
1089    }
1090
1091    fn init_from_buffers<'a>(
1092        &'a mut self,
1093        _buffers: PageInitializationBuffers,
1094        _io: &Arc<dyn EncodingsIo>,
1095    ) -> BoxFuture<'a, Result<Arc<dyn CachedPageData>>> {
1096        std::future::ready(Ok(Arc::new(NoCachedPageData) as Arc<dyn CachedPageData>)).boxed()
1097    }
1098
1099    fn try_load(&mut self, _cache: &Arc<dyn CachedPageData>) -> Result<()> {
1100        Ok(())
1101    }
1102
1103    fn schedule_ranges(
1104        &self,
1105        ranges: &[Range<u64>],
1106        _io: &Arc<dyn EncodingsIo>,
1107    ) -> Result<Vec<PageLoadTask>> {
1108        let num_rows = ranges.iter().map(|r| r.end - r.start).sum::<u64>();
1109        let decoder =
1110            Box::new(SimpleAllNullPageDecoder { num_rows }) as Box<dyn StructuralPageDecoder>;
1111        let page_load_task = PageLoadTask {
1112            decoder_fut: std::future::ready(Ok(decoder)).boxed(),
1113            num_rows,
1114        };
1115        Ok(vec![page_load_task])
1116    }
1117}
1118
1119/// A page decode task for all-null data without any
1120/// repetition and only a single level of definition
1121#[derive(Debug)]
1122struct SimpleAllNullDecodePageTask {
1123    num_values: u64,
1124}
1125impl DecodePageTask for SimpleAllNullDecodePageTask {
1126    fn decode(self: Box<Self>) -> Result<DecodedPage> {
1127        let unraveler = RepDefUnraveler::new(
1128            None,
1129            Some(vec![1; self.num_values as usize]),
1130            Arc::new([DefinitionInterpretation::NullableItem]),
1131            self.num_values,
1132        );
1133        Ok(DecodedPage {
1134            data: DataBlock::AllNull(AllNullDataBlock {
1135                num_values: self.num_values,
1136            }),
1137            repdef: unraveler,
1138        })
1139    }
1140}
1141
1142#[derive(Debug)]
1143pub struct SimpleAllNullPageDecoder {
1144    num_rows: u64,
1145}
1146
1147impl StructuralPageDecoder for SimpleAllNullPageDecoder {
1148    fn drain(&mut self, num_rows: u64) -> Result<Box<dyn DecodePageTask>> {
1149        Ok(Box::new(SimpleAllNullDecodePageTask {
1150            num_values: num_rows,
1151        }))
1152    }
1153
1154    fn num_rows(&self) -> u64 {
1155        self.num_rows
1156    }
1157}
1158
1159#[cfg(test)]
1160#[allow(clippy::single_range_in_vec_init)]
1161mod tests {
1162    use std::collections::HashMap;
1163    use std::sync::Arc;
1164
1165    use arrow_buffer::ScalarBuffer;
1166
1167    use crate::buffer::LanceBuffer;
1168    use crate::compression::DefaultDecompressionStrategy;
1169    use crate::data::{BlockInfo, DataBlock, FixedWidthDataBlock};
1170    use crate::encodings::logical::primitive::tests::encoded_u16_frame;
1171    use crate::encodings::physical::rle::{RleDecompressor, RleRuns, RunLengthWidth};
1172    use crate::format::metadata::compressive_encoding::Compression;
1173    use crate::format::{EncodingUtils, metadata};
1174    use crate::testing::{TestCases, check_round_trip_encoding_of_data};
1175
1176    use super::{
1177        LazyLevels, LevelCodec, LevelCursor, LevelPlan, RunEndsBuilder, RunPosition, RunStorage,
1178        dense_levels_from_block, validate_complex_all_null_levels,
1179    };
1180
1181    fn encoded_u16_runs(levels: &[u16], run_length_width: RunLengthWidth) -> RleRuns {
1182        let frame = encoded_u16_frame(levels, run_length_width);
1183        RleDecompressor::with_run_length_width(16, run_length_width)
1184            .decode_u16_runs(frame, levels.len() as u64)
1185            .unwrap()
1186    }
1187
1188    fn physical_levels(levels: &[u16]) -> LazyLevels {
1189        LazyLevels::Runs(Arc::new(RunStorage::Physical(
1190            encoded_u16_runs(levels, RunLengthWidth::U8).into_owned(),
1191        )))
1192    }
1193
1194    fn coalesced_levels(levels: &[u16]) -> LazyLevels {
1195        let mut values = Vec::new();
1196        let mut ends = RunEndsBuilder::with_capacity(levels.len(), levels.len());
1197        for (index, &value) in levels.iter().enumerate() {
1198            if values.last() == Some(&value) {
1199                ends.set_last(index + 1).unwrap();
1200            } else {
1201                values.push(value);
1202                ends.push(index + 1).unwrap();
1203            }
1204        }
1205        LazyLevels::Runs(Arc::new(RunStorage::Coalesced {
1206            values: values.into_boxed_slice(),
1207            ends: ends.finish(),
1208        }))
1209    }
1210
1211    #[test]
1212    fn lazy_levels_runs_match_dense() {
1213        // Runs: 3x2, 1x1, 3x3, 0x2  =>  [3,3,1,3,3,3,0,0]
1214        let expanded: Vec<u16> = vec![3, 3, 1, 3, 3, 3, 0, 0];
1215        let coalesced = coalesced_levels(&expanded);
1216        let physical = physical_levels(&expanded);
1217        let dense = LazyLevels::Dense(ScalarBuffer::<u16>::from(expanded.clone()));
1218        let n = expanded.len();
1219
1220        assert_eq!(coalesced.len(), n);
1221        assert_eq!(physical.len(), n);
1222        assert_eq!(dense.len(), n);
1223
1224        // Rows begin at each `max_rep` (3) position; row `num_rows` maps to `len`.
1225        let max_rep = 3u16;
1226        let row_starts: Vec<usize> = (0..n).filter(|&i| expanded[i] == max_rep).collect();
1227        for target in 0..=row_starts.len() as u64 {
1228            let want = row_starts.get(target as usize).copied().unwrap_or(n);
1229            for runs in [&coalesced, &physical] {
1230                let mut cursor = LevelCursor::default();
1231                assert_eq!(
1232                    runs.seek_row_start(&mut cursor, target, max_rep).unwrap(),
1233                    want,
1234                    "seek_row_start({target})"
1235                );
1236            }
1237            let mut c_dense = LevelCursor::default();
1238            assert_eq!(
1239                dense.seek_row_start(&mut c_dense, target, max_rep).unwrap(),
1240                want
1241            );
1242        }
1243
1244        // `count_le_cursor` (fresh cursor per range) and `extend_into` agree with
1245        // the dense reference on every sub-range.
1246        for start in 0..=n {
1247            for end in start..=n {
1248                for max in [0u16, 1, 2, 3] {
1249                    let want = expanded[start..end].iter().filter(|&&d| d <= max).count() as u64;
1250                    for runs in [&coalesced, &physical] {
1251                        let mut cursor = RunPosition::default();
1252                        assert_eq!(
1253                            runs.count_le_cursor(&mut cursor, start..end, max).0,
1254                            want,
1255                            "count_le_cursor({start}..{end}, {max})"
1256                        );
1257                    }
1258                    let mut d_cur = RunPosition::default();
1259                    assert_eq!(dense.count_le_cursor(&mut d_cur, start..end, max).0, want);
1260                }
1261                for runs in [&coalesced, &physical] {
1262                    let mut got = Vec::new();
1263                    runs.extend_into(start..end, RunPosition::default(), &mut got);
1264                    assert_eq!(
1265                        got,
1266                        expanded[start..end].to_vec(),
1267                        "extend_into({start}..{end})"
1268                    );
1269                }
1270                let mut got_dense = Vec::new();
1271                dense.extend_into(start..end, RunPosition::default(), &mut got_dense);
1272                assert_eq!(got_dense, expanded[start..end].to_vec());
1273            }
1274        }
1275    }
1276
1277    #[test]
1278    fn physical_run_hints_support_deferred_materialization() {
1279        let expanded: Vec<u16> = vec![3, 3, 1, 1, 2, 2, 0, 0];
1280        let physical = physical_levels(&expanded);
1281        let LazyLevels::Runs(runs) = &physical else {
1282            panic!("expected physical runs");
1283        };
1284        let mut first_hint = RunPosition::default();
1285        runs.seek(&mut first_hint, 2);
1286        let mut second_hint = RunPosition::default();
1287        runs.seek(&mut second_hint, 6);
1288
1289        let mut second = Vec::new();
1290        physical.extend_into(6..8, second_hint, &mut second);
1291        let mut first = Vec::new();
1292        physical.extend_into(2..4, first_hint, &mut first);
1293        assert_eq!(second, expanded[6..8]);
1294        assert_eq!(first, expanded[2..4]);
1295    }
1296
1297    /// Fuzz parity for the run-oriented complex-all-null drain: the cursor walk
1298    /// over `LazyLevels` must yield the exact level slices and visible
1299    /// count that a brute-force reference over the fully expanded levels does, for
1300    /// dense, physical-run, and coalesced-run forms and arbitrarily shaped range requests.
1301    mod complex_all_null_drain_parity {
1302        use std::ops::Range;
1303
1304        use arrow_buffer::ScalarBuffer;
1305        use proptest::prelude::*;
1306
1307        use super::super::{LazyLevels, LevelCursor, RunPosition};
1308        use super::{coalesced_levels, physical_levels};
1309        use crate::Result;
1310
1311        #[derive(Debug, Clone)]
1312        struct DrainInput {
1313            max_rep: u16,
1314            max_visible: u16,
1315            rep: Option<Vec<u16>>,
1316            def: Option<Vec<u16>>,
1317            ranges: Vec<Range<u64>>,
1318        }
1319
1320        fn dense_levels(levels: &[u16]) -> LazyLevels {
1321            LazyLevels::Dense(ScalarBuffer::from(levels.to_vec()))
1322        }
1323
1324        fn rle_levels(levels: &[u16]) -> LazyLevels {
1325            coalesced_levels(levels)
1326        }
1327
1328        fn seek(
1329            rep: Option<&LazyLevels>,
1330            cursor: &mut LevelCursor,
1331            row: u64,
1332            max_rep: u16,
1333        ) -> Result<usize> {
1334            match rep {
1335                Some(rep) => rep.seek_row_start(cursor, row, max_rep),
1336                None => {
1337                    cursor.row = row;
1338                    cursor.level = row as usize;
1339                    Ok(row as usize)
1340                }
1341            }
1342        }
1343
1344        /// Mirror of `ComplexAllNullPageDecoder::drain`, driving the real
1345        /// `seek_row_start` / `count_le_cursor` with monotonic cursors.
1346        fn simulate_drain(
1347            rep: Option<&LazyLevels>,
1348            def: Option<&LazyLevels>,
1349            max_rep: u16,
1350            max_visible: u16,
1351            ranges: &[Range<u64>],
1352        ) -> Result<(Vec<Range<usize>>, u64)> {
1353            let mut rep_cursor = LevelCursor::default();
1354            let mut def_run_cursor = RunPosition::default();
1355            let mut slices: Vec<Range<usize>> = Vec::new();
1356            let mut visible = 0u64;
1357            for range in ranges {
1358                let level_start = seek(rep, &mut rep_cursor, range.start, max_rep)?;
1359                let level_end = seek(rep, &mut rep_cursor, range.end, max_rep)?;
1360                visible += match def {
1361                    Some(def) => {
1362                        def.count_le_cursor(
1363                            &mut def_run_cursor,
1364                            level_start..level_end,
1365                            max_visible,
1366                        )
1367                        .0
1368                    }
1369                    None => (level_end - level_start) as u64,
1370                };
1371                match slices.last_mut() {
1372                    Some(last) if last.end == level_start => last.end = level_end,
1373                    _ => slices.push(level_start..level_end),
1374                }
1375            }
1376            Ok((slices, visible))
1377        }
1378
1379        /// Independent brute-force reference over fully expanded levels.
1380        fn reference_drain(
1381            rep: Option<&[u16]>,
1382            def: Option<&[u16]>,
1383            max_rep: u16,
1384            max_visible: u16,
1385            ranges: &[Range<u64>],
1386        ) -> (Vec<Range<usize>>, u64) {
1387            let total_levels = rep
1388                .map(|r| r.len())
1389                .or_else(|| def.map(|d| d.len()))
1390                .unwrap_or(0);
1391            // Level index where each row starts (or `total_levels` for the end row).
1392            let row_starts: Vec<usize> = match rep {
1393                Some(rep) => (0..rep.len()).filter(|&i| rep[i] == max_rep).collect(),
1394                None => (0..total_levels).collect(),
1395            };
1396            let level_of_row = |row: u64| {
1397                row_starts
1398                    .get(row as usize)
1399                    .copied()
1400                    .unwrap_or(total_levels)
1401            };
1402
1403            let mut slices: Vec<Range<usize>> = Vec::new();
1404            let mut visible = 0u64;
1405            for range in ranges {
1406                let ls = level_of_row(range.start);
1407                let le = level_of_row(range.end);
1408                visible += match def {
1409                    Some(def) => def[ls..le].iter().filter(|&&d| d <= max_visible).count() as u64,
1410                    None => (le - ls) as u64,
1411                };
1412                match slices.last_mut() {
1413                    Some(last) if last.end == ls => last.end = le,
1414                    _ => slices.push(ls..le),
1415                }
1416            }
1417            (slices, visible)
1418        }
1419
1420        fn ranges_strategy(num_rows: u64) -> BoxedStrategy<Vec<Range<u64>>> {
1421            if num_rows == 0 {
1422                return Just(Vec::new()).boxed();
1423            }
1424            // (gap, len) pairs; a zero gap yields ranges adjacent in row space,
1425            // which exercises the level-slice coalescing path.
1426            proptest::collection::vec((0u64..=3, 1u64..=4), 0..=8)
1427                .prop_map(move |pairs| {
1428                    let mut ranges = Vec::new();
1429                    let mut pos = 0u64;
1430                    for (gap, len) in pairs {
1431                        pos = pos.saturating_add(gap);
1432                        if pos >= num_rows {
1433                            break;
1434                        }
1435                        let end = (pos + len).min(num_rows);
1436                        ranges.push(pos..end);
1437                        pos = end;
1438                    }
1439                    ranges
1440                })
1441                .boxed()
1442        }
1443
1444        fn drain_input() -> impl Strategy<Value = DrainInput> {
1445            (
1446                1u16..=3,
1447                0u16..=3,
1448                any::<bool>(),
1449                any::<bool>(),
1450                1usize..=48,
1451            )
1452                .prop_flat_map(|(max_rep, max_visible, has_rep, has_def, len)| {
1453                    // Complex-all-null always has definition levels when there is
1454                    // no repetition, so force `def` present in that case.
1455                    let has_def = has_def || !has_rep;
1456                    let rep = if has_rep {
1457                        proptest::collection::vec(0u16..=max_rep, len)
1458                            .prop_map(move |mut v| {
1459                                // Row 0 must start at a max-rep boundary.
1460                                v[0] = max_rep;
1461                                Some(v)
1462                            })
1463                            .boxed()
1464                    } else {
1465                        Just(None).boxed()
1466                    };
1467                    let def = if has_def {
1468                        proptest::collection::vec(0u16..=(max_visible + 2), len)
1469                            .prop_map(Some)
1470                            .boxed()
1471                    } else {
1472                        Just(None).boxed()
1473                    };
1474                    (Just(max_rep), Just(max_visible), rep, def)
1475                })
1476                .prop_flat_map(|(max_rep, max_visible, rep, def)| {
1477                    let num_rows = match &rep {
1478                        Some(rep) => rep.iter().filter(|&&v| v == max_rep).count() as u64,
1479                        None => def.as_ref().map(|d| d.len() as u64).unwrap_or(0),
1480                    };
1481                    ranges_strategy(num_rows).prop_map(move |ranges| DrainInput {
1482                        max_rep,
1483                        max_visible,
1484                        rep: rep.clone(),
1485                        def: def.clone(),
1486                        ranges,
1487                    })
1488                })
1489        }
1490
1491        proptest! {
1492            #![proptest_config(ProptestConfig::with_cases(512))]
1493
1494            #[test]
1495            fn drain_matches_reference(input in drain_input()) {
1496                let DrainInput { max_rep, max_visible, rep, def, ranges } = input;
1497
1498                let reference =
1499                    reference_drain(rep.as_deref(), def.as_deref(), max_rep, max_visible, &ranges);
1500
1501                let rep_dense = rep.as_deref().map(dense_levels);
1502                let def_dense = def.as_deref().map(dense_levels);
1503                let got_dense =
1504                    simulate_drain(rep_dense.as_ref(), def_dense.as_ref(), max_rep, max_visible, &ranges)
1505                        .unwrap();
1506                prop_assert_eq!(&got_dense, &reference, "dense form diverged from reference");
1507
1508                let rep_rle = rep.as_deref().map(rle_levels);
1509                let def_rle = def.as_deref().map(rle_levels);
1510                let got_rle =
1511                    simulate_drain(rep_rle.as_ref(), def_rle.as_ref(), max_rep, max_visible, &ranges)
1512                        .unwrap();
1513                prop_assert_eq!(&got_rle, &reference, "rle form diverged from reference");
1514
1515                let rep_physical = rep.as_deref().map(physical_levels);
1516                let def_physical = def.as_deref().map(physical_levels);
1517                let got_physical =
1518                    simulate_drain(rep_physical.as_ref(), def_physical.as_ref(), max_rep, max_visible, &ranges)
1519                        .unwrap();
1520                prop_assert_eq!(&got_physical, &reference, "physical form diverged from reference");
1521            }
1522        }
1523    }
1524
1525    #[test]
1526    fn lazy_levels_runs_are_compact() {
1527        let single_run = |n: usize| {
1528            let mut ends = RunEndsBuilder::with_capacity(n, 1);
1529            ends.push(n).unwrap();
1530            LazyLevels::Runs(Arc::new(RunStorage::Coalesced {
1531                values: vec![1u16].into_boxed_slice(),
1532                ends: ends.finish(),
1533            }))
1534        };
1535        // Run-form footprint is independent of the logical length within an end width...
1536        assert_eq!(single_run(100).deep_size(), single_run(10_000).deep_size());
1537        assert!(single_run(10_000_000).deep_size() < 100);
1538        assert_eq!(single_run(10_000_000).len(), 10_000_000);
1539        // ...while Dense pays 2 bytes per value.
1540        assert_eq!(
1541            LazyLevels::Dense(ScalarBuffer::<u16>::from(vec![1u16; 1000])).deep_size(),
1542            2000
1543        );
1544    }
1545
1546    #[test]
1547    fn lazy_levels_selects_smallest_representation() {
1548        let runs = encoded_u16_runs(&[7u16; 10], RunLengthWidth::U8);
1549        assert_eq!(LazyLevels::select_plan(&runs), LevelPlan::Dense);
1550
1551        let equal_size: Vec<u16> = std::iter::repeat_n(0, 256)
1552            .chain(std::iter::repeat_n(1, 100))
1553            .chain(std::iter::repeat_n(2, 100))
1554            .collect();
1555        let runs = encoded_u16_runs(&equal_size, RunLengthWidth::U8);
1556        assert_eq!(LazyLevels::select_plan(&runs), LevelPlan::Coalesced);
1557
1558        let moderate_runs: Vec<u16> = (0..250)
1559            .flat_map(|run| std::iter::repeat_n((run % 2) as u16, 4))
1560            .collect();
1561        let runs = encoded_u16_runs(&moderate_runs, RunLengthWidth::U8);
1562        assert_eq!(LazyLevels::select_plan(&runs), LevelPlan::Physical);
1563
1564        let split_constant = vec![7u16; 5000];
1565        let runs = encoded_u16_runs(&split_constant, RunLengthWidth::U8);
1566        assert_eq!(LazyLevels::select_plan(&runs), LevelPlan::Coalesced);
1567
1568        let high_density: Vec<u16> = (0..70_000).map(|index| (index % 2) as u16).collect();
1569        let runs = encoded_u16_runs(&high_density, RunLengthWidth::U32);
1570        assert_eq!(LazyLevels::select_plan(&runs), LevelPlan::Dense);
1571    }
1572
1573    #[test]
1574    fn physical_runs_detach_from_large_encoded_frame() {
1575        let levels: Vec<u16> = (0..250)
1576            .flat_map(|run| std::iter::repeat_n((run % 2) as u16, 4))
1577            .collect();
1578        let frame = encoded_u16_frame(&levels, RunLengthWidth::U8);
1579        let frame_offset = 4096;
1580        let mut allocation = vec![0; frame_offset + frame.len() + 1_000_000];
1581        allocation[frame_offset..frame_offset + frame.len()].copy_from_slice(frame.as_ref());
1582        let frame = LanceBuffer::from(allocation).slice_with_length(frame_offset, frame.len());
1583        let runs = RleDecompressor::with_run_length_width(16, RunLengthWidth::U8)
1584            .decode_u16_runs(frame, levels.len() as u64)
1585            .unwrap();
1586
1587        assert_eq!(LazyLevels::select_plan(&runs), LevelPlan::Physical);
1588        let cached = LazyLevels::from_rle_runs(runs).unwrap();
1589        assert!(
1590            matches!(cached, LazyLevels::Runs(ref runs) if matches!(runs.as_ref(), RunStorage::Physical(_)))
1591        );
1592        assert_eq!(cached.len(), levels.len());
1593        assert!(cached.deep_size() < 4096);
1594    }
1595
1596    #[test]
1597    fn complex_all_null_levels_reject_invalid_values_and_lengths() {
1598        let invalid_levels = vec![0u16, 3];
1599        for levels in [
1600            LazyLevels::Dense(ScalarBuffer::from(invalid_levels.clone())),
1601            physical_levels(&invalid_levels),
1602            coalesced_levels(&invalid_levels),
1603        ] {
1604            let error = validate_complex_all_null_levels(&None, &Some(levels), 0, 2).unwrap_err();
1605            assert!(matches!(error, lance_core::Error::InvalidInput { .. }));
1606            assert!(error.to_string().contains("Invalid definition level 3"));
1607        }
1608
1609        let rep = Some(LazyLevels::Dense(ScalarBuffer::from(vec![0u16; 2])));
1610        let def = Some(LazyLevels::Dense(ScalarBuffer::from(vec![0u16])));
1611        let error = validate_complex_all_null_levels(&rep, &def, 0, 0).unwrap_err();
1612        assert!(matches!(error, lance_core::Error::InvalidInput { .. }));
1613        assert!(
1614            error
1615                .to_string()
1616                .contains("repetition has 2, definition has 1")
1617        );
1618    }
1619
1620    #[test]
1621    fn block_levels_reject_malformed_payload_size() {
1622        let block = DataBlock::FixedWidth(FixedWidthDataBlock {
1623            data: LanceBuffer::from(vec![0]),
1624            bits_per_value: 16,
1625            num_values: 1,
1626            block_info: BlockInfo::new(),
1627        });
1628        let error = dense_levels_from_block(block, 1, "definition").unwrap_err();
1629        assert!(matches!(error, lance_core::Error::InvalidInput { .. }));
1630        assert!(
1631            error
1632                .to_string()
1633                .contains("expected 2 bytes for 1 values, got 1")
1634        );
1635    }
1636
1637    #[test]
1638    fn complex_all_null_level_codec_validates_rle_metadata() {
1639        let encoding = metadata::CompressiveEncoding {
1640            compression: Some(Compression::Rle(Box::new(metadata::Rle {
1641                values: None,
1642                run_lengths: Some(Box::new(EncodingUtils::flat(8, None))),
1643            }))),
1644        };
1645
1646        let error = LevelCodec::try_new(Some(&encoding), &DefaultDecompressionStrategy::default())
1647            .unwrap_err();
1648        assert!(matches!(error, lance_core::Error::InvalidInput { .. }));
1649        assert!(
1650            error
1651                .to_string()
1652                .contains("RLE compression missing values encoding")
1653        );
1654    }
1655
1656    // https://github.com/lance-format/lance/issues/6681
1657    #[tokio::test]
1658    async fn test_sparse_boolean_list_roundtrip() {
1659        use arrow_array::builder::{BooleanBuilder, ListBuilder};
1660
1661        let mut list_builder = ListBuilder::new(BooleanBuilder::new());
1662        for i in 0..1000i32 {
1663            if i % 64 == 0 {
1664                // Alternate true/false so the array is not constant (constant path avoids the bug).
1665                list_builder.values().append_value(i % 128 == 0);
1666                list_builder.append(true);
1667            } else {
1668                list_builder.append(false);
1669            }
1670        }
1671        let list_array = Arc::new(list_builder.finish());
1672
1673        let test_cases = TestCases::default().with_structural_encodings();
1674        check_round_trip_encoding_of_data(vec![list_array], &test_cases, HashMap::new()).await;
1675    }
1676}