1use arrow_array::Array;
2use arrow_array::new_null_array;
3use arrow_schema::DataType;
4use std::sync::Arc;
5
6use arrow_array::builder::{BooleanBuilder, Float64Builder, StringBuilder, UInt8Builder};
7use arrow_array::{ArrayRef, BooleanArray, Float64Array, StringArray, UInt8Array, UInt32Array};
8use once_cell::sync::OnceCell;
9
10use crate::format::FormatId;
11use formualizer_common::{ExcelError, ExcelErrorKind, LiteralValue};
12use rustc_hash::FxHashMap;
13use std::collections::{BTreeMap, HashMap};
14
15#[repr(u8)]
17#[derive(Copy, Clone, Debug, Eq, PartialEq)]
18pub enum TypeTag {
19 Empty = 0,
20 Number = 1,
21 Boolean = 2,
22 Text = 3,
23 Error = 4,
24 DateTime = 5, Duration = 6, Pending = 7,
27}
28
29impl TypeTag {
30 fn from_value(v: &LiteralValue) -> Self {
31 match v {
32 LiteralValue::Empty => TypeTag::Empty,
33 LiteralValue::Int(_) | LiteralValue::Number(_) => TypeTag::Number,
34 LiteralValue::Boolean(_) => TypeTag::Boolean,
35 LiteralValue::Text(_) => TypeTag::Text,
36 LiteralValue::Error(_) => TypeTag::Error,
37 LiteralValue::Date(_) | LiteralValue::DateTime(_) | LiteralValue::Time(_) => {
38 TypeTag::DateTime
39 }
40 LiteralValue::Duration(_) => TypeTag::Duration,
41 LiteralValue::Pending => TypeTag::Pending,
42 LiteralValue::Array(_) => TypeTag::Error, }
44 }
45}
46
47impl TypeTag {
48 #[inline]
49 pub fn from_u8(b: u8) -> Self {
50 match b {
51 x if x == TypeTag::Empty as u8 => TypeTag::Empty,
52 x if x == TypeTag::Number as u8 => TypeTag::Number,
53 x if x == TypeTag::Boolean as u8 => TypeTag::Boolean,
54 x if x == TypeTag::Text as u8 => TypeTag::Text,
55 x if x == TypeTag::Error as u8 => TypeTag::Error,
56 x if x == TypeTag::DateTime as u8 => TypeTag::DateTime,
57 x if x == TypeTag::Duration as u8 => TypeTag::Duration,
58 x if x == TypeTag::Pending as u8 => TypeTag::Pending,
59 _ => TypeTag::Empty,
60 }
61 }
62}
63
64#[derive(Debug, Clone, Copy, Default)]
65pub struct ColumnChunkMeta {
66 pub len: usize,
67 pub non_null_num: usize,
68 pub non_null_bool: usize,
69 pub non_null_text: usize,
70 pub non_null_err: usize,
71}
72
73#[derive(Debug, Clone, PartialEq, Eq)]
75pub struct FormatRuns {
76 run_ends: Vec<u32>,
77 format_ids: Vec<u16>,
78}
79
80impl FormatRuns {
81 pub fn from_ids(ids: &[u16]) -> Option<Self> {
82 if ids.iter().all(|id| *id == FormatId::GENERAL.0) {
83 return None;
84 }
85 let mut run_ends = Vec::new();
86 let mut format_ids = Vec::new();
87 for (idx, id) in ids.iter().copied().enumerate() {
88 if format_ids.last().copied() != Some(id) {
89 format_ids.push(id);
90 if idx > 0 {
91 run_ends.push(idx as u32);
92 }
93 }
94 }
95 run_ends.push(ids.len() as u32);
96 Some(Self {
97 run_ends,
98 format_ids,
99 })
100 }
101
102 #[inline]
103 pub fn get(&self, offset: usize) -> FormatId {
104 let run = self
105 .run_ends
106 .partition_point(|end| (*end as usize) <= offset);
107 self.format_ids
108 .get(run)
109 .copied()
110 .map(FormatId)
111 .unwrap_or_default()
112 }
113
114 pub fn to_ids(&self, len: usize) -> Vec<u16> {
115 (0..len).map(|offset| self.get(offset).0).collect()
116 }
117
118 pub fn slice(&self, offset: usize, len: usize) -> Option<Self> {
119 let ids: Vec<_> = (offset..offset.saturating_add(len))
120 .map(|i| self.get(i).0)
121 .collect();
122 Self::from_ids(&ids)
123 }
124}
125
126#[derive(Debug, Clone)]
127pub struct ColumnChunk {
128 pub numbers: Option<Arc<Float64Array>>,
129 pub booleans: Option<Arc<BooleanArray>>,
130 pub text: Option<ArrayRef>, pub errors: Option<Arc<UInt8Array>>, pub type_tag: Arc<UInt8Array>,
133 pub formula_id: Option<Arc<UInt32Array>>, pub format: Option<FormatRuns>,
136 pub meta: ColumnChunkMeta,
137 lazy_null_numbers: OnceCell<Arc<Float64Array>>,
139 lazy_null_booleans: OnceCell<Arc<BooleanArray>>,
140 lazy_null_text: OnceCell<ArrayRef>,
141 lazy_null_errors: OnceCell<Arc<UInt8Array>>,
142 lowered_text: OnceCell<ArrayRef>,
144 pub overlay: Overlay,
146 pub computed_overlay: Overlay,
148}
149
150impl ColumnChunk {
151 #[inline]
152 pub fn len(&self) -> usize {
153 self.type_tag.len()
154 }
155 #[inline]
156 pub fn is_empty(&self) -> bool {
157 self.len() == 0
158 }
159 #[inline]
160 pub fn numbers_or_null(&self) -> Arc<Float64Array> {
161 #[cfg(test)]
162 crate::engine::range_view::range_work::record(|w| w.provider_requests[0] += 1);
163 if let Some(a) = &self.numbers {
164 return a.clone();
165 }
166 self.lazy_null_numbers
167 .get_or_init(|| {
168 #[cfg(test)]
169 crate::engine::range_view::range_work::record(|w| {
170 w.provider_builds[0] += 1;
171 w.provider_slots[0] += self.len();
172 });
173 let arr = new_null_array(&DataType::Float64, self.len());
174 Arc::new(arr.as_any().downcast_ref::<Float64Array>().unwrap().clone())
175 })
176 .clone()
177 }
178 #[inline]
179 pub fn booleans_or_null(&self) -> Arc<BooleanArray> {
180 #[cfg(test)]
181 crate::engine::range_view::range_work::record(|w| w.provider_requests[1] += 1);
182 if let Some(a) = &self.booleans {
183 return a.clone();
184 }
185 self.lazy_null_booleans
186 .get_or_init(|| {
187 #[cfg(test)]
188 crate::engine::range_view::range_work::record(|w| {
189 w.provider_builds[1] += 1;
190 w.provider_slots[1] += self.len();
191 });
192 let arr = new_null_array(&DataType::Boolean, self.len());
193 Arc::new(arr.as_any().downcast_ref::<BooleanArray>().unwrap().clone())
194 })
195 .clone()
196 }
197 #[inline]
198 pub fn errors_or_null(&self) -> Arc<UInt8Array> {
199 #[cfg(test)]
200 crate::engine::range_view::range_work::record(|w| w.provider_requests[2] += 1);
201 if let Some(a) = &self.errors {
202 return a.clone();
203 }
204 self.lazy_null_errors
205 .get_or_init(|| {
206 #[cfg(test)]
207 crate::engine::range_view::range_work::record(|w| {
208 w.provider_builds[2] += 1;
209 w.provider_slots[2] += self.len();
210 });
211 let arr = new_null_array(&DataType::UInt8, self.len());
212 Arc::new(arr.as_any().downcast_ref::<UInt8Array>().unwrap().clone())
213 })
214 .clone()
215 }
216 #[inline]
217 pub fn text_or_null(&self) -> ArrayRef {
218 #[cfg(test)]
219 crate::engine::range_view::range_work::record(|w| w.provider_requests[3] += 1);
220 if let Some(a) = &self.text {
221 return a.clone();
222 }
223 self.lazy_null_text
224 .get_or_init(|| {
225 #[cfg(test)]
226 crate::engine::range_view::range_work::record(|w| {
227 w.provider_builds[3] += 1;
228 w.provider_slots[3] += self.len();
229 });
230 new_null_array(&DataType::Utf8, self.len())
231 })
232 .clone()
233 }
234
235 pub fn text_lower_or_null(&self) -> ArrayRef {
237 if let Some(a) = self.lowered_text.get() {
238 return a.clone();
239 }
240 let out: ArrayRef = if let Some(txt) = &self.text {
242 let sa = txt.as_any().downcast_ref::<StringArray>().unwrap();
243 let mut b = arrow_array::builder::StringBuilder::with_capacity(sa.len(), sa.len() * 8);
244 for i in 0..sa.len() {
245 if sa.is_null(i) {
246 b.append_null();
247 } else {
248 b.append_value(sa.value(i).to_lowercase());
249 }
250 }
251 let lowered = b.finish();
252 Arc::new(lowered)
253 } else {
254 new_null_array(&DataType::Utf8, self.len())
255 };
256 self.lowered_text.get_or_init(|| out.clone());
257 out
258 }
259
260 pub fn grow_len_to(&mut self, new_len: usize) {
265 let old_len = self.len();
266 if new_len <= old_len {
267 return;
268 }
269
270 let mut tags: Vec<u8> = self.type_tag.values().to_vec();
272 tags.resize(new_len, TypeTag::Empty as u8);
273 self.type_tag = Arc::new(UInt8Array::from(tags));
274
275 if let Some(a) = &self.numbers {
277 use arrow_array::builder::Float64Builder;
278 let mut b = Float64Builder::with_capacity(new_len);
279 for i in 0..old_len {
280 if a.is_null(i) {
281 b.append_null();
282 } else {
283 b.append_value(a.value(i));
284 }
285 }
286 for _ in old_len..new_len {
287 b.append_null();
288 }
289 self.numbers = Some(Arc::new(b.finish()));
290 }
291 if let Some(a) = &self.booleans {
292 use arrow_array::builder::BooleanBuilder;
293 let mut b = BooleanBuilder::with_capacity(new_len);
294 for i in 0..old_len {
295 if a.is_null(i) {
296 b.append_null();
297 } else {
298 b.append_value(a.value(i));
299 }
300 }
301 for _ in old_len..new_len {
302 b.append_null();
303 }
304 self.booleans = Some(Arc::new(b.finish()));
305 }
306 if let Some(a) = &self.errors {
307 use arrow_array::builder::UInt8Builder;
308 let mut b = UInt8Builder::with_capacity(new_len);
309 for i in 0..old_len {
310 if a.is_null(i) {
311 b.append_null();
312 } else {
313 b.append_value(a.value(i));
314 }
315 }
316 for _ in old_len..new_len {
317 b.append_null();
318 }
319 self.errors = Some(Arc::new(b.finish()));
320 }
321 if let Some(a) = &self.text {
322 use arrow_array::builder::StringBuilder;
323 let sa = a.as_any().downcast_ref::<StringArray>().unwrap();
324 let mut b = StringBuilder::with_capacity(new_len, 0);
325 for i in 0..old_len {
326 if sa.is_null(i) {
327 b.append_null();
328 } else {
329 b.append_value(sa.value(i));
330 }
331 }
332 for _ in old_len..new_len {
333 b.append_null();
334 }
335 self.text = Some(Arc::new(b.finish()) as ArrayRef);
336 }
337
338 if let Some(format) = &self.format {
339 let mut ids = format.to_ids(old_len);
340 ids.resize(new_len, FormatId::GENERAL.0);
341 self.format = FormatRuns::from_ids(&ids);
342 }
343
344 self.lazy_null_numbers = OnceCell::new();
346 self.lazy_null_booleans = OnceCell::new();
347 self.lazy_null_text = OnceCell::new();
348 self.lazy_null_errors = OnceCell::new();
349 self.lowered_text = OnceCell::new();
350
351 self.meta.len = new_len;
352 }
353}
354
355#[derive(Debug, Clone)]
356pub struct ArrowColumn {
357 pub chunks: Vec<ColumnChunk>,
358 pub sparse_chunks: FxHashMap<usize, ColumnChunk>,
359 pub index: u32,
360}
361
362impl ArrowColumn {
363 #[inline]
364 pub fn chunk(&self, idx: usize) -> Option<&ColumnChunk> {
365 if idx < self.chunks.len() {
366 Some(&self.chunks[idx])
367 } else {
368 self.sparse_chunks.get(&idx)
369 }
370 }
371
372 #[inline]
373 pub fn chunk_mut(&mut self, idx: usize) -> Option<&mut ColumnChunk> {
374 if idx < self.chunks.len() {
375 Some(&mut self.chunks[idx])
376 } else {
377 self.sparse_chunks.get_mut(&idx)
378 }
379 }
380
381 #[inline]
382 pub fn has_sparse_chunks(&self) -> bool {
383 !self.sparse_chunks.is_empty()
384 }
385
386 #[inline]
387 pub fn total_chunk_count(&self) -> usize {
388 self.chunks.len() + self.sparse_chunks.len()
389 }
390}
391
392#[derive(Debug, Clone)]
393pub struct ArrowSheet {
394 pub name: Arc<str>,
395 pub date_system: crate::engine::DateSystem,
400 pub columns: Vec<ArrowColumn>,
401 pub nrows: u32,
402 pub chunk_starts: Vec<usize>,
403 pub chunk_rows: usize,
408}
409
410#[derive(Debug, Default, Clone)]
411pub struct SheetStore {
412 pub sheets: Vec<ArrowSheet>,
413}
414
415impl SheetStore {
416 pub fn sheet(&self, name: &str) -> Option<&ArrowSheet> {
417 self.sheets.iter().find(|s| s.name.as_ref() == name)
418 }
419 pub fn sheet_mut(&mut self, name: &str) -> Option<&mut ArrowSheet> {
420 self.sheets.iter_mut().find(|s| s.name.as_ref() == name)
421 }
422}
423
424pub struct IngestBuilder {
426 name: Arc<str>,
427 ncols: usize,
428 chunk_rows: usize,
429 date_system: crate::engine::DateSystem,
430
431 num_builders: Vec<Float64Builder>,
433 bool_builders: Vec<BooleanBuilder>,
434 text_builders: Vec<StringBuilder>,
435 err_builders: Vec<UInt8Builder>,
436 tag_builders: Vec<UInt8Builder>,
437 format_builders: Vec<Vec<u16>>,
438
439 lane_counts: Vec<LaneCounts>,
441
442 chunks: Vec<Vec<ColumnChunk>>, row_in_chunk: usize,
445 total_rows: u32,
446}
447
448#[derive(Debug, Clone, Copy, Default)]
449struct LaneCounts {
450 n_num: usize,
451 n_bool: usize,
452 n_text: usize,
453 n_err: usize,
454}
455
456impl IngestBuilder {
457 pub fn new(
458 sheet_name: &str,
459 ncols: usize,
460 chunk_rows: usize,
461 date_system: crate::engine::DateSystem,
462 ) -> Self {
463 let mut chunks = Vec::with_capacity(ncols);
464 chunks.resize_with(ncols, Vec::new);
465 Self {
466 name: Arc::from(sheet_name.to_string()),
467 ncols,
468 chunk_rows: chunk_rows.max(1),
469 date_system,
470 num_builders: (0..ncols)
471 .map(|_| Float64Builder::with_capacity(chunk_rows))
472 .collect(),
473 bool_builders: (0..ncols)
474 .map(|_| BooleanBuilder::with_capacity(chunk_rows))
475 .collect(),
476 text_builders: (0..ncols)
477 .map(|_| StringBuilder::with_capacity(chunk_rows, chunk_rows * 12))
478 .collect(),
479 err_builders: (0..ncols)
480 .map(|_| UInt8Builder::with_capacity(chunk_rows))
481 .collect(),
482 tag_builders: (0..ncols)
483 .map(|_| UInt8Builder::with_capacity(chunk_rows))
484 .collect(),
485 format_builders: (0..ncols).map(|_| Vec::with_capacity(chunk_rows)).collect(),
486 lane_counts: vec![LaneCounts::default(); ncols],
487 chunks,
488 row_in_chunk: 0,
489 total_rows: 0,
490 }
491 }
492
493 pub fn append_row_cells<'a>(&mut self, row: &[CellIngest<'a>]) -> Result<(), ExcelError> {
496 assert_eq!(row.len(), self.ncols, "row width mismatch");
497 for (c, cell) in row.iter().enumerate() {
498 self.format_builders[c].push(match cell {
499 CellIngest::DateSerial(serial) if serial.fract().abs() > f64::EPSILON => {
500 FormatId::DATETIME.0
501 }
502 CellIngest::DateSerial(_) => FormatId::DATE.0,
503 CellIngest::FormattedNumber(_, id) => id.0,
504 CellIngest::DurationSerial(_) => FormatId::DURATION.0,
505 _ => FormatId::GENERAL.0,
506 });
507 match cell {
508 CellIngest::Empty => {
509 self.tag_builders[c].append_value(TypeTag::Empty as u8);
510 self.num_builders[c].append_null();
511 self.bool_builders[c].append_null();
512 self.text_builders[c].append_null();
513 self.err_builders[c].append_null();
514 }
515 CellIngest::Number(n) => {
516 self.tag_builders[c].append_value(TypeTag::Number as u8);
517 self.num_builders[c].append_value(*n);
518 self.lane_counts[c].n_num += 1;
519 self.bool_builders[c].append_null();
520 self.text_builders[c].append_null();
521 self.err_builders[c].append_null();
522 }
523 CellIngest::Boolean(b) => {
524 self.tag_builders[c].append_value(TypeTag::Boolean as u8);
525 self.num_builders[c].append_null();
526 self.bool_builders[c].append_value(*b);
527 self.lane_counts[c].n_bool += 1;
528 self.text_builders[c].append_null();
529 self.err_builders[c].append_null();
530 }
531 CellIngest::Text(s) => {
532 self.tag_builders[c].append_value(TypeTag::Text as u8);
533 self.num_builders[c].append_null();
534 self.bool_builders[c].append_null();
535 self.text_builders[c].append_value(s);
536 self.lane_counts[c].n_text += 1;
537 self.err_builders[c].append_null();
538 }
539 CellIngest::ErrorCode(code) => {
540 self.tag_builders[c].append_value(TypeTag::Error as u8);
541 self.num_builders[c].append_null();
542 self.bool_builders[c].append_null();
543 self.text_builders[c].append_null();
544 self.err_builders[c].append_value(*code);
545 self.lane_counts[c].n_err += 1;
546 }
547 CellIngest::DateSerial(serial) | CellIngest::FormattedNumber(serial, _) => {
548 self.tag_builders[c].append_value(TypeTag::Number as u8);
549 self.num_builders[c].append_value(*serial);
550 self.lane_counts[c].n_num += 1;
551 self.bool_builders[c].append_null();
552 self.text_builders[c].append_null();
553 self.err_builders[c].append_null();
554 }
555 CellIngest::DurationSerial(serial) => {
556 self.tag_builders[c].append_value(TypeTag::Number as u8);
557 self.num_builders[c].append_value(*serial);
558 self.lane_counts[c].n_num += 1;
559 self.bool_builders[c].append_null();
560 self.text_builders[c].append_null();
561 self.err_builders[c].append_null();
562 }
563 CellIngest::Pending => {
564 self.tag_builders[c].append_value(TypeTag::Pending as u8);
565 self.num_builders[c].append_null();
566 self.bool_builders[c].append_null();
567 self.text_builders[c].append_null();
568 self.err_builders[c].append_null();
569 }
570 }
571 }
572 self.row_in_chunk += 1;
573 self.total_rows += 1;
574 if self.row_in_chunk >= self.chunk_rows {
575 self.finish_chunk();
576 }
577 Ok(())
578 }
579
580 pub fn append_row_cells_iter<'a, I>(&mut self, iter: I) -> Result<(), ExcelError>
583 where
584 I: ExactSizeIterator<Item = CellIngest<'a>>,
585 {
586 assert_eq!(iter.len(), self.ncols, "row width mismatch");
587 for (c, cell) in iter.enumerate() {
588 self.format_builders[c].push(match cell {
589 CellIngest::DateSerial(serial) if serial.fract().abs() > f64::EPSILON => {
590 FormatId::DATETIME.0
591 }
592 CellIngest::DateSerial(_) => FormatId::DATE.0,
593 CellIngest::FormattedNumber(_, id) => id.0,
594 CellIngest::DurationSerial(_) => FormatId::DURATION.0,
595 _ => FormatId::GENERAL.0,
596 });
597 match cell {
598 CellIngest::Empty => {
599 self.tag_builders[c].append_value(TypeTag::Empty as u8);
600 self.num_builders[c].append_null();
601 self.bool_builders[c].append_null();
602 self.text_builders[c].append_null();
603 self.err_builders[c].append_null();
604 }
605 CellIngest::Number(n) => {
606 self.tag_builders[c].append_value(TypeTag::Number as u8);
607 self.num_builders[c].append_value(n);
608 self.lane_counts[c].n_num += 1;
609 self.bool_builders[c].append_null();
610 self.text_builders[c].append_null();
611 self.err_builders[c].append_null();
612 }
613 CellIngest::Boolean(b) => {
614 self.tag_builders[c].append_value(TypeTag::Boolean as u8);
615 self.num_builders[c].append_null();
616 self.bool_builders[c].append_value(b);
617 self.lane_counts[c].n_bool += 1;
618 self.text_builders[c].append_null();
619 self.err_builders[c].append_null();
620 }
621 CellIngest::Text(s) => {
622 self.tag_builders[c].append_value(TypeTag::Text as u8);
623 self.num_builders[c].append_null();
624 self.bool_builders[c].append_null();
625 self.text_builders[c].append_value(s);
626 self.lane_counts[c].n_text += 1;
627 self.err_builders[c].append_null();
628 }
629 CellIngest::ErrorCode(code) => {
630 self.tag_builders[c].append_value(TypeTag::Error as u8);
631 self.num_builders[c].append_null();
632 self.bool_builders[c].append_null();
633 self.text_builders[c].append_null();
634 self.err_builders[c].append_value(code);
635 self.lane_counts[c].n_err += 1;
636 }
637 CellIngest::DateSerial(serial) | CellIngest::FormattedNumber(serial, _) => {
638 self.tag_builders[c].append_value(TypeTag::Number as u8);
639 self.num_builders[c].append_value(serial);
640 self.lane_counts[c].n_num += 1;
641 self.bool_builders[c].append_null();
642 self.text_builders[c].append_null();
643 self.err_builders[c].append_null();
644 }
645 CellIngest::DurationSerial(serial) => {
646 self.tag_builders[c].append_value(TypeTag::Number as u8);
647 self.num_builders[c].append_value(serial);
648 self.lane_counts[c].n_num += 1;
649 self.bool_builders[c].append_null();
650 self.text_builders[c].append_null();
651 self.err_builders[c].append_null();
652 }
653 CellIngest::Pending => {
654 self.tag_builders[c].append_value(TypeTag::Pending as u8);
655 self.num_builders[c].append_null();
656 self.bool_builders[c].append_null();
657 self.text_builders[c].append_null();
658 self.err_builders[c].append_null();
659 }
660 }
661 }
662 self.row_in_chunk += 1;
663 self.total_rows += 1;
664 if self.row_in_chunk >= self.chunk_rows {
665 self.finish_chunk();
666 }
667 Ok(())
668 }
669
670 pub fn append_row(&mut self, row: &[LiteralValue]) -> Result<(), ExcelError> {
672 assert_eq!(row.len(), self.ncols, "row width mismatch");
673
674 for (c, v) in row.iter().enumerate() {
675 self.format_builders[c].push(match v {
676 LiteralValue::Date(_) => FormatId::DATE.0,
677 LiteralValue::DateTime(_) => FormatId::DATETIME.0,
678 LiteralValue::Time(_) => FormatId::TIME.0,
679 LiteralValue::Duration(_) => FormatId::DURATION.0,
680 _ => FormatId::GENERAL.0,
681 });
682 let tag = match v {
683 LiteralValue::Date(_)
684 | LiteralValue::DateTime(_)
685 | LiteralValue::Time(_)
686 | LiteralValue::Duration(_) => TypeTag::Number,
687 _ => TypeTag::from_value(v),
688 } as u8;
689 self.tag_builders[c].append_value(tag);
690
691 match v {
692 LiteralValue::Empty => {
693 self.num_builders[c].append_null();
694 self.bool_builders[c].append_null();
695 self.text_builders[c].append_null();
696 self.err_builders[c].append_null();
697 }
698 LiteralValue::Int(i) => {
699 self.num_builders[c].append_value(*i as f64);
700 self.lane_counts[c].n_num += 1;
701 self.bool_builders[c].append_null();
702 self.text_builders[c].append_null();
703 self.err_builders[c].append_null();
704 }
705 LiteralValue::Number(n) => {
706 self.num_builders[c].append_value(*n);
707 self.lane_counts[c].n_num += 1;
708 self.bool_builders[c].append_null();
709 self.text_builders[c].append_null();
710 self.err_builders[c].append_null();
711 }
712 LiteralValue::Boolean(b) => {
713 self.num_builders[c].append_null();
714 self.bool_builders[c].append_value(*b);
715 self.lane_counts[c].n_bool += 1;
716 self.text_builders[c].append_null();
717 self.err_builders[c].append_null();
718 }
719 LiteralValue::Text(s) => {
720 self.num_builders[c].append_null();
721 self.bool_builders[c].append_null();
722 self.text_builders[c].append_value(s);
723 self.lane_counts[c].n_text += 1;
724 self.err_builders[c].append_null();
725 }
726 LiteralValue::Error(e) => {
727 self.num_builders[c].append_null();
728 self.bool_builders[c].append_null();
729 self.text_builders[c].append_null();
730 self.err_builders[c].append_value(map_error_code(e.kind));
731 self.lane_counts[c].n_err += 1;
732 }
733 LiteralValue::Date(d) => {
735 let dt = d.and_hms_opt(0, 0, 0).unwrap();
736 let serial = formualizer_common::datetime_to_serial_for(self.date_system, &dt);
737 self.num_builders[c].append_value(serial);
738 self.lane_counts[c].n_num += 1;
739 self.bool_builders[c].append_null();
740 self.text_builders[c].append_null();
741 self.err_builders[c].append_null();
742 }
743 LiteralValue::DateTime(dt) => {
744 let serial = formualizer_common::datetime_to_serial_for(self.date_system, dt);
745 self.num_builders[c].append_value(serial);
746 self.lane_counts[c].n_num += 1;
747 self.bool_builders[c].append_null();
748 self.text_builders[c].append_null();
749 self.err_builders[c].append_null();
750 }
751 LiteralValue::Time(t) => {
752 let serial = formualizer_common::time_to_fraction(t);
753 self.num_builders[c].append_value(serial);
754 self.lane_counts[c].n_num += 1;
755 self.bool_builders[c].append_null();
756 self.text_builders[c].append_null();
757 self.err_builders[c].append_null();
758 }
759 LiteralValue::Duration(dur) => {
760 let serial = dur.num_seconds() as f64 / 86_400.0;
761 self.num_builders[c].append_value(serial);
762 self.lane_counts[c].n_num += 1;
763 self.bool_builders[c].append_null();
764 self.text_builders[c].append_null();
765 self.err_builders[c].append_null();
766 }
767 LiteralValue::Array(_) => {
768 self.num_builders[c].append_null();
770 self.bool_builders[c].append_null();
771 self.text_builders[c].append_null();
772 self.err_builders[c].append_value(map_error_code(ExcelErrorKind::Value));
773 self.lane_counts[c].n_err += 1;
774 }
775 LiteralValue::Pending => {
776 self.num_builders[c].append_null();
778 self.bool_builders[c].append_null();
779 self.text_builders[c].append_null();
780 self.err_builders[c].append_null();
781 }
782 }
783 }
784
785 self.row_in_chunk += 1;
786 self.total_rows += 1;
787
788 if self.row_in_chunk >= self.chunk_rows {
789 self.finish_chunk();
790 }
791
792 Ok(())
793 }
794
795 fn finish_chunk(&mut self) {
796 if self.row_in_chunk == 0 {
797 return;
798 }
799 for c in 0..self.ncols {
800 let len = self.row_in_chunk;
801 let numbers_arc: Option<Arc<Float64Array>> = if self.lane_counts[c].n_num == 0 {
802 None
803 } else {
804 Some(Arc::new(self.num_builders[c].finish()))
805 };
806 let booleans_arc: Option<Arc<BooleanArray>> = if self.lane_counts[c].n_bool == 0 {
807 None
808 } else {
809 Some(Arc::new(self.bool_builders[c].finish()))
810 };
811 let text_ref: Option<ArrayRef> = if self.lane_counts[c].n_text == 0 {
812 None
813 } else {
814 Some(Arc::new(self.text_builders[c].finish()))
815 };
816 let errors_arc: Option<Arc<UInt8Array>> = if self.lane_counts[c].n_err == 0 {
817 None
818 } else {
819 Some(Arc::new(self.err_builders[c].finish()))
820 };
821 let tags: UInt8Array = self.tag_builders[c].finish();
822
823 let chunk = ColumnChunk {
824 numbers: numbers_arc,
825 booleans: booleans_arc,
826 text: text_ref,
827 errors: errors_arc,
828 type_tag: Arc::new(tags),
829 formula_id: None,
830 format: FormatRuns::from_ids(&self.format_builders[c]),
831 meta: ColumnChunkMeta {
832 len,
833 non_null_num: self.lane_counts[c].n_num,
834 non_null_bool: self.lane_counts[c].n_bool,
835 non_null_text: self.lane_counts[c].n_text,
836 non_null_err: self.lane_counts[c].n_err,
837 },
838 lazy_null_numbers: OnceCell::new(),
839 lazy_null_booleans: OnceCell::new(),
840 lazy_null_text: OnceCell::new(),
841 lazy_null_errors: OnceCell::new(),
842 lowered_text: OnceCell::new(),
843 overlay: Overlay::new(),
844 computed_overlay: Overlay::new(),
845 };
846 self.chunks[c].push(chunk);
847
848 self.num_builders[c] = Float64Builder::with_capacity(self.chunk_rows);
850 self.bool_builders[c] = BooleanBuilder::with_capacity(self.chunk_rows);
851 self.text_builders[c] =
852 StringBuilder::with_capacity(self.chunk_rows, self.chunk_rows * 12);
853 self.err_builders[c] = UInt8Builder::with_capacity(self.chunk_rows);
854 self.tag_builders[c] = UInt8Builder::with_capacity(self.chunk_rows);
855 self.format_builders[c] = Vec::with_capacity(self.chunk_rows);
856 self.lane_counts[c] = LaneCounts::default();
857 }
858 self.row_in_chunk = 0;
859 }
860
861 pub fn finish(mut self) -> ArrowSheet {
862 if self.row_in_chunk > 0 {
864 self.finish_chunk();
865 }
866
867 let mut columns = Vec::with_capacity(self.ncols);
868 for (idx, chunks) in self.chunks.into_iter().enumerate() {
869 columns.push(ArrowColumn {
870 chunks,
871 sparse_chunks: FxHashMap::default(),
872 index: idx as u32,
873 });
874 }
875 let mut chunk_starts: Vec<usize> = Vec::new();
877 if let Some(col0) = columns.first() {
878 let chunks_len0 = col0.chunks.len();
879 for (ci, col) in columns.iter().enumerate() {
880 if col.chunks.len() != chunks_len0 {
881 panic!(
882 "ArrowSheet chunk misalignment: column {} chunks={} != {}",
883 ci,
884 col.chunks.len(),
885 chunks_len0
886 );
887 }
888 }
889 let mut cur = 0usize;
890 for i in 0..chunks_len0 {
891 let len_i = col0.chunks[i].type_tag.len();
892 for (ci, col) in columns.iter().enumerate() {
893 let got = col.chunks[i].type_tag.len();
894 if got != len_i {
895 panic!(
896 "ArrowSheet chunk row-length misalignment at chunk {i}: col {ci} len={got} != {len_i}"
897 );
898 }
899 }
900 chunk_starts.push(cur);
901 cur += len_i;
902 }
903 }
904 ArrowSheet {
905 name: self.name,
906 date_system: self.date_system,
907 columns,
908 nrows: self.total_rows,
909 chunk_starts,
910 chunk_rows: self.chunk_rows,
911 }
912 }
913}
914
915pub fn map_error_code(kind: ExcelErrorKind) -> u8 {
916 match kind {
917 ExcelErrorKind::Null => 1,
918 ExcelErrorKind::Ref => 2,
919 ExcelErrorKind::Name => 3,
920 ExcelErrorKind::Value => 4,
921 ExcelErrorKind::Div => 5,
922 ExcelErrorKind::Na => 6,
923 ExcelErrorKind::Num => 7,
924 ExcelErrorKind::Error => 8,
925 ExcelErrorKind::NImpl => 9,
926 ExcelErrorKind::Spill => 10,
927 ExcelErrorKind::Calc => 11,
928 ExcelErrorKind::Circ => 12,
929 ExcelErrorKind::Cancelled => 13,
930 _ => 8,
931 }
932}
933
934pub fn unmap_error_code(code: u8) -> ExcelErrorKind {
935 match code {
936 1 => ExcelErrorKind::Null,
937 2 => ExcelErrorKind::Ref,
938 3 => ExcelErrorKind::Name,
939 4 => ExcelErrorKind::Value,
940 5 => ExcelErrorKind::Div,
941 6 => ExcelErrorKind::Na,
942 7 => ExcelErrorKind::Num,
943 8 => ExcelErrorKind::Error,
944 9 => ExcelErrorKind::NImpl,
945 10 => ExcelErrorKind::Spill,
946 11 => ExcelErrorKind::Calc,
947 12 => ExcelErrorKind::Circ,
948 13 => ExcelErrorKind::Cancelled,
949 _ => ExcelErrorKind::Error,
950 }
951}
952
953pub enum CellIngest<'a> {
957 Empty,
958 Number(f64),
959 Boolean(bool),
960 Text(&'a str),
961 ErrorCode(u8),
962 DateSerial(f64),
963 DurationSerial(f64),
964 FormattedNumber(f64, FormatId),
965 Pending,
966}
967
968#[derive(Debug, Clone, PartialEq)]
969pub enum OverlayValue {
970 Empty,
971 Number(f64),
972 DateTime(f64),
974 Duration(f64),
976 Boolean(bool),
977 Text(Arc<str>),
978 Error(u8),
979 Pending,
980}
981
982impl OverlayValue {
983 pub fn from_literal_value(
984 value: &LiteralValue,
985 date_system: crate::engine::DateSystem,
986 ) -> Self {
987 match value {
988 LiteralValue::Empty => OverlayValue::Empty,
989 LiteralValue::Int(i) => OverlayValue::Number(*i as f64),
990 LiteralValue::Number(n) => OverlayValue::Number(*n),
991 LiteralValue::Boolean(b) => OverlayValue::Boolean(*b),
992 LiteralValue::Text(s) => OverlayValue::Text(Arc::from(s.clone())),
993 LiteralValue::Error(e) => OverlayValue::Error(map_error_code(e.kind)),
994 LiteralValue::Date(d) => {
995 let dt = d.and_hms_opt(0, 0, 0).unwrap();
996 OverlayValue::DateTime(formualizer_common::datetime_to_serial_for(date_system, &dt))
997 }
998 LiteralValue::DateTime(dt) => {
999 OverlayValue::DateTime(formualizer_common::datetime_to_serial_for(date_system, dt))
1000 }
1001 LiteralValue::Time(t) => {
1002 OverlayValue::DateTime(formualizer_common::time_to_fraction(t))
1003 }
1004 LiteralValue::Duration(d) => OverlayValue::Duration(d.num_seconds() as f64 / 86_400.0),
1005 LiteralValue::Pending => OverlayValue::Pending,
1006 LiteralValue::Array(_) => OverlayValue::Error(map_error_code(ExcelErrorKind::Value)),
1007 }
1008 }
1009
1010 #[inline]
1011 pub(crate) fn estimated_payload_bytes(&self) -> usize {
1012 match self {
1013 OverlayValue::Empty | OverlayValue::Pending => 0,
1014 OverlayValue::Number(_) | OverlayValue::DateTime(_) | OverlayValue::Duration(_) => {
1015 core::mem::size_of::<f64>()
1016 }
1017 OverlayValue::Boolean(_) => core::mem::size_of::<bool>(),
1018 OverlayValue::Error(_) => core::mem::size_of::<u8>(),
1019 OverlayValue::Text(s) => s.len(),
1021 }
1022 }
1023
1024 #[inline]
1025 pub(crate) fn type_tag(&self) -> TypeTag {
1026 match self {
1027 OverlayValue::Empty => TypeTag::Empty,
1028 OverlayValue::Number(_) => TypeTag::Number,
1029 OverlayValue::DateTime(_) => TypeTag::DateTime,
1030 OverlayValue::Duration(_) => TypeTag::Duration,
1031 OverlayValue::Boolean(_) => TypeTag::Boolean,
1032 OverlayValue::Text(_) => TypeTag::Text,
1033 OverlayValue::Error(_) => TypeTag::Error,
1034 OverlayValue::Pending => TypeTag::Pending,
1035 }
1036 }
1037
1038 #[inline]
1039 pub(crate) fn numeric_lane_value(&self) -> Option<f64> {
1040 match self {
1041 OverlayValue::Number(n) | OverlayValue::DateTime(n) | OverlayValue::Duration(n) => {
1042 Some(*n)
1043 }
1044 _ => None,
1045 }
1046 }
1047
1048 #[inline]
1049 pub(crate) fn boolean_lane_value(&self) -> Option<bool> {
1050 match self {
1051 OverlayValue::Boolean(b) => Some(*b),
1052 _ => None,
1053 }
1054 }
1055
1056 #[inline]
1057 pub(crate) fn text_lane_value(&self) -> Option<&str> {
1058 match self {
1059 OverlayValue::Text(s) => Some(s.as_ref()),
1060 _ => None,
1061 }
1062 }
1063
1064 #[inline]
1065 pub(crate) fn error_lane_value(&self) -> Option<u8> {
1066 match self {
1067 OverlayValue::Error(code) => Some(*code),
1068 _ => None,
1069 }
1070 }
1071
1072 pub(crate) fn lowered_text_value(&self) -> Option<String> {
1073 match self {
1074 OverlayValue::Text(s) => Some(s.to_lowercase()),
1075 OverlayValue::Number(n) | OverlayValue::DateTime(n) | OverlayValue::Duration(n) => {
1076 Some(n.to_string())
1077 }
1078 OverlayValue::Boolean(b) => Some(if *b { "true" } else { "false" }.to_string()),
1079 OverlayValue::Empty | OverlayValue::Error(_) | OverlayValue::Pending => None,
1080 }
1081 }
1082
1083 pub(crate) fn to_literal_for(&self, date_system: crate::engine::DateSystem) -> LiteralValue {
1084 match self {
1085 OverlayValue::Empty => LiteralValue::Empty,
1086 OverlayValue::Number(n) => LiteralValue::Number(*n),
1087 OverlayValue::DateTime(serial) | OverlayValue::Duration(serial) => {
1088 let _ = date_system;
1089 LiteralValue::Number(*serial)
1090 }
1091 OverlayValue::Boolean(b) => LiteralValue::Boolean(*b),
1092 OverlayValue::Text(s) => LiteralValue::Text((**s).to_string()),
1093 OverlayValue::Error(code) => {
1094 LiteralValue::Error(ExcelError::new(unmap_error_code(*code)))
1095 }
1096 OverlayValue::Pending => LiteralValue::Pending,
1097 }
1098 }
1099
1100 #[cfg(test)]
1101 pub(crate) fn to_literal(&self) -> LiteralValue {
1102 self.to_literal_for(crate::engine::DateSystem::Excel1900)
1103 }
1104}
1105
1106#[derive(Debug, Clone)]
1107pub(crate) enum OverlayScalar<'a> {
1108 Borrowed(&'a OverlayValue),
1109 Owned(OverlayValue),
1110}
1111
1112impl<'a> OverlayScalar<'a> {
1113 #[inline]
1114 fn as_value(&self) -> &OverlayValue {
1115 match self {
1116 OverlayScalar::Borrowed(value) => value,
1117 OverlayScalar::Owned(value) => value,
1118 }
1119 }
1120
1121 #[inline]
1122 pub(crate) fn to_overlay_value(&self) -> OverlayValue {
1123 self.as_value().clone()
1124 }
1125
1126 #[inline]
1127 pub(crate) fn type_tag(&self) -> TypeTag {
1128 self.as_value().type_tag()
1129 }
1130
1131 #[inline]
1132 pub(crate) fn numeric_lane_value(&self) -> Option<f64> {
1133 self.as_value().numeric_lane_value()
1134 }
1135
1136 #[inline]
1137 pub(crate) fn boolean_lane_value(&self) -> Option<bool> {
1138 self.as_value().boolean_lane_value()
1139 }
1140
1141 #[inline]
1142 pub(crate) fn text_lane_value(&self) -> Option<&str> {
1143 self.as_value().text_lane_value()
1144 }
1145
1146 #[inline]
1147 pub(crate) fn error_lane_value(&self) -> Option<u8> {
1148 self.as_value().error_lane_value()
1149 }
1150
1151 pub(crate) fn lowered_text_value(&self) -> Option<String> {
1152 self.as_value().lowered_text_value()
1153 }
1154
1155 pub(crate) fn to_literal_for(&self, date_system: crate::engine::DateSystem) -> LiteralValue {
1156 self.as_value().to_literal_for(date_system)
1157 }
1158
1159 #[cfg(test)]
1160 pub(crate) fn to_literal(&self) -> LiteralValue {
1161 self.to_literal_for(crate::engine::DateSystem::Excel1900)
1162 }
1163}
1164
1165const OVERLAY_ENTRY_BASE_BYTES: usize = 32;
1166const OVERLAY_FRAGMENT_BASE_BYTES: usize = 48;
1167
1168#[allow(dead_code)]
1169#[derive(Debug, Clone)]
1170pub(crate) struct OverlayFragmentPayload {
1171 type_tags: Arc<UInt8Array>,
1172 numbers: Option<Arc<Float64Array>>,
1173 booleans: Option<Arc<BooleanArray>>,
1174 text: Option<ArrayRef>,
1175 errors: Option<Arc<UInt8Array>>,
1176 estimated_bytes: usize,
1177}
1178
1179impl OverlayFragmentPayload {
1180 fn from_values(values: Vec<OverlayValue>) -> Self {
1181 let len = values.len();
1182 let mut tag_b = UInt8Builder::with_capacity(len);
1183 let mut nb = Float64Builder::with_capacity(len);
1184 let mut bb = BooleanBuilder::with_capacity(len);
1185 let mut sb = StringBuilder::with_capacity(len, len.saturating_mul(8));
1186 let mut eb = UInt8Builder::with_capacity(len);
1187 let mut non_num = 0usize;
1188 let mut non_bool = 0usize;
1189 let mut non_text = 0usize;
1190 let mut non_err = 0usize;
1191
1192 for value in &values {
1193 append_overlay_value_to_lane_builders(
1194 value,
1195 &mut tag_b,
1196 &mut nb,
1197 &mut bb,
1198 &mut sb,
1199 &mut eb,
1200 &mut non_num,
1201 &mut non_bool,
1202 &mut non_text,
1203 &mut non_err,
1204 );
1205 }
1206
1207 let type_tags = Arc::new(tag_b.finish());
1208 let numbers = {
1209 let a = nb.finish();
1210 (non_num > 0).then(|| Arc::new(a))
1211 };
1212 let booleans = {
1213 let a = bb.finish();
1214 (non_bool > 0).then(|| Arc::new(a))
1215 };
1216 let text = {
1217 let a = sb.finish();
1218 (non_text > 0).then(|| Arc::new(a) as ArrayRef)
1219 };
1220 let errors = {
1221 let a = eb.finish();
1222 (non_err > 0).then(|| Arc::new(a))
1223 };
1224
1225 let estimated_bytes = type_tags
1226 .get_array_memory_size()
1227 .saturating_add(
1228 numbers
1229 .as_ref()
1230 .map(|a| a.get_array_memory_size())
1231 .unwrap_or(0),
1232 )
1233 .saturating_add(
1234 booleans
1235 .as_ref()
1236 .map(|a| a.get_array_memory_size())
1237 .unwrap_or(0),
1238 )
1239 .saturating_add(
1240 text.as_ref()
1241 .map(|a| a.get_array_memory_size())
1242 .unwrap_or(0),
1243 )
1244 .saturating_add(
1245 errors
1246 .as_ref()
1247 .map(|a| a.get_array_memory_size())
1248 .unwrap_or(0),
1249 );
1250
1251 Self {
1252 type_tags,
1253 numbers,
1254 booleans,
1255 text,
1256 errors,
1257 estimated_bytes,
1258 }
1259 }
1260
1261 fn overlay_value(&self, idx: usize) -> Option<OverlayValue> {
1262 if idx >= self.type_tags.len() || self.type_tags.is_null(idx) {
1263 return None;
1264 }
1265 match TypeTag::from_u8(self.type_tags.value(idx)) {
1266 TypeTag::Empty => Some(OverlayValue::Empty),
1267 TypeTag::Number => Some(OverlayValue::Number(self.number_at(idx)?)),
1268 TypeTag::DateTime => Some(OverlayValue::DateTime(self.number_at(idx)?)),
1269 TypeTag::Duration => Some(OverlayValue::Duration(self.number_at(idx)?)),
1270 TypeTag::Boolean => Some(OverlayValue::Boolean(self.boolean_at(idx)?)),
1271 TypeTag::Text => Some(OverlayValue::Text(Arc::from(self.text_at(idx)?))),
1272 TypeTag::Error => Some(OverlayValue::Error(self.error_at(idx)?)),
1273 TypeTag::Pending => Some(OverlayValue::Pending),
1274 }
1275 }
1276
1277 #[inline]
1278 fn get_scalar(&self, idx: usize) -> Option<OverlayScalar<'_>> {
1279 self.overlay_value(idx).map(OverlayScalar::Owned)
1280 }
1281
1282 #[inline]
1283 fn number_at(&self, idx: usize) -> Option<f64> {
1284 let arr = self.numbers.as_ref()?;
1285 (!arr.is_null(idx)).then(|| arr.value(idx))
1286 }
1287
1288 #[inline]
1289 fn boolean_at(&self, idx: usize) -> Option<bool> {
1290 let arr = self.booleans.as_ref()?;
1291 (!arr.is_null(idx)).then(|| arr.value(idx))
1292 }
1293
1294 #[inline]
1295 fn text_at(&self, idx: usize) -> Option<&str> {
1296 let arr = self.text.as_ref()?;
1297 let arr = arr.as_any().downcast_ref::<StringArray>()?;
1298 (!arr.is_null(idx)).then(|| arr.value(idx))
1299 }
1300
1301 #[inline]
1302 fn error_at(&self, idx: usize) -> Option<u8> {
1303 let arr = self.errors.as_ref()?;
1304 (!arr.is_null(idx)).then(|| arr.value(idx))
1305 }
1306
1307 #[inline]
1308 fn values_slice(&self, start: usize, len: usize) -> Vec<OverlayValue> {
1309 (start..start.saturating_add(len))
1310 .filter_map(|idx| self.overlay_value(idx))
1311 .collect()
1312 }
1313
1314 #[inline]
1315 fn estimated_bytes(&self) -> usize {
1316 self.estimated_bytes
1317 }
1318}
1319#[derive(Debug, Clone)]
1320pub(crate) enum OverlayFragment {
1321 SparseOffsets {
1322 offsets: Vec<u32>,
1323 payload: OverlayFragmentPayload,
1324 },
1325 DenseRange {
1326 start: u32,
1327 len: u32,
1328 payload: OverlayFragmentPayload,
1329 },
1330 RunRange {
1331 start: u32,
1332 len: u32,
1333 run_ends: Vec<u32>,
1334 payload: OverlayFragmentPayload,
1335 },
1336}
1337
1338impl OverlayFragment {
1339 const MAX_SPLIT_SEGMENTS_BEFORE_SPARSE_FALLBACK: usize = 128;
1340
1341 pub(crate) fn sparse_offsets(items: Vec<(usize, OverlayValue)>) -> Option<Self> {
1342 let mut by_offset: BTreeMap<usize, OverlayValue> = BTreeMap::new();
1343 for (offset, value) in items {
1344 by_offset.insert(offset, value);
1345 }
1346 if by_offset.is_empty() {
1347 return None;
1348 }
1349
1350 let mut offsets = Vec::with_capacity(by_offset.len());
1351 let mut values = Vec::with_capacity(by_offset.len());
1352 for (offset, value) in by_offset {
1353 offsets.push(u32::try_from(offset).expect("overlay offset fits in u32"));
1354 values.push(value);
1355 }
1356
1357 Some(Self::SparseOffsets {
1358 offsets,
1359 payload: OverlayFragmentPayload::from_values(values),
1360 })
1361 }
1362
1363 pub(crate) fn sparse_offsets_if_estimated_smaller_than_points(
1364 items: Vec<(usize, OverlayValue)>,
1365 point_estimate: usize,
1366 ) -> Option<Result<Self, Vec<(usize, OverlayValue)>>> {
1367 let fragment = Self::sparse_offsets(items)?;
1368 if fragment.estimated_bytes() < point_estimate {
1369 Some(Ok(fragment))
1370 } else {
1371 Some(Err(fragment.cells()))
1372 }
1373 }
1374
1375 pub(crate) fn dense_range(start: usize, values: Vec<OverlayValue>) -> Option<Self> {
1376 let len = values.len();
1377 if len == 0 {
1378 return None;
1379 }
1380 Some(Self::DenseRange {
1381 start: u32::try_from(start).expect("overlay start fits in u32"),
1382 len: u32::try_from(len).expect("overlay length fits in u32"),
1383 payload: OverlayFragmentPayload::from_values(values),
1384 })
1385 }
1386
1387 pub(crate) fn run_range(start: usize, values: Vec<OverlayValue>) -> Option<Self> {
1388 if values.is_empty() {
1389 return None;
1390 }
1391
1392 let mut run_ends = Vec::new();
1393 let mut run_values = Vec::new();
1394 let mut current = values[0].clone();
1395 for (idx, value) in values.iter().enumerate().skip(1) {
1396 if *value != current {
1397 run_ends.push(idx);
1398 run_values.push(current);
1399 current = value.clone();
1400 }
1401 }
1402 run_ends.push(values.len());
1403 run_values.push(current);
1404
1405 Self::run_range_from_parts(start, values.len(), run_ends, run_values)
1406 }
1407
1408 fn run_range_from_parts(
1409 start: usize,
1410 len: usize,
1411 run_ends: Vec<usize>,
1412 values: Vec<OverlayValue>,
1413 ) -> Option<Self> {
1414 if len == 0 || run_ends.is_empty() || run_ends.len() != values.len() {
1415 return None;
1416 }
1417
1418 let mut merged_ends: Vec<u32> = Vec::with_capacity(run_ends.len());
1419 let mut merged_values: Vec<OverlayValue> = Vec::with_capacity(values.len());
1420 let mut prev_end = 0usize;
1421 for (end, value) in run_ends.into_iter().zip(values.into_iter()) {
1422 if end <= prev_end || end > len {
1423 return None;
1424 }
1425 if merged_values.last().is_some_and(|last| *last == value) {
1426 if let Some(last_end) = merged_ends.last_mut() {
1427 *last_end = u32::try_from(end).expect("run end fits in u32");
1428 }
1429 } else {
1430 merged_ends.push(u32::try_from(end).expect("run end fits in u32"));
1431 merged_values.push(value);
1432 }
1433 prev_end = end;
1434 }
1435
1436 if prev_end != len || merged_ends.last().copied() != Some(len as u32) {
1437 return None;
1438 }
1439
1440 Some(Self::RunRange {
1441 start: u32::try_from(start).expect("overlay start fits in u32"),
1442 len: u32::try_from(len).expect("overlay length fits in u32"),
1443 run_ends: merged_ends,
1444 payload: OverlayFragmentPayload::from_values(merged_values),
1445 })
1446 }
1447
1448 #[inline]
1449 fn estimated_bytes(&self) -> usize {
1450 match self {
1451 OverlayFragment::SparseOffsets { offsets, payload } => OVERLAY_FRAGMENT_BASE_BYTES
1452 .saturating_add(offsets.len().saturating_mul(core::mem::size_of::<u32>()))
1453 .saturating_add(payload.estimated_bytes()),
1454 OverlayFragment::DenseRange { payload, .. } => {
1455 OVERLAY_FRAGMENT_BASE_BYTES.saturating_add(payload.estimated_bytes())
1456 }
1457 OverlayFragment::RunRange {
1458 run_ends, payload, ..
1459 } => OVERLAY_FRAGMENT_BASE_BYTES
1460 .saturating_add(run_ends.len().saturating_mul(core::mem::size_of::<u32>()))
1461 .saturating_add(payload.estimated_bytes()),
1462 }
1463 }
1464
1465 #[inline]
1466 fn coverage_len(&self) -> usize {
1467 match self {
1468 OverlayFragment::SparseOffsets { offsets, .. } => offsets.len(),
1469 OverlayFragment::DenseRange { len, .. } | OverlayFragment::RunRange { len, .. } => {
1470 *len as usize
1471 }
1472 }
1473 }
1474
1475 pub(crate) fn max_covered_offset(&self) -> usize {
1476 match self {
1477 OverlayFragment::SparseOffsets { offsets, .. } => {
1478 offsets.iter().copied().max().unwrap_or(0) as usize
1479 }
1480 OverlayFragment::DenseRange { start, len, .. }
1481 | OverlayFragment::RunRange { start, len, .. } => (*start as usize)
1482 .saturating_add(*len as usize)
1483 .saturating_sub(1),
1484 }
1485 }
1486
1487 fn interval_coverage(&self) -> Option<core::ops::Range<usize>> {
1488 match self {
1489 OverlayFragment::DenseRange { start, len, .. }
1490 | OverlayFragment::RunRange { start, len, .. } => {
1491 let start = *start as usize;
1492 Some(start..start.saturating_add(*len as usize))
1493 }
1494 OverlayFragment::SparseOffsets { .. } => None,
1495 }
1496 }
1497
1498 fn sparse_offsets_slice(&self) -> Option<&[u32]> {
1499 match self {
1500 OverlayFragment::SparseOffsets { offsets, .. } => Some(offsets.as_slice()),
1501 _ => None,
1502 }
1503 }
1504
1505 fn has_any_in_range(&self, range: core::ops::Range<usize>) -> bool {
1506 if range.is_empty() {
1507 return false;
1508 }
1509 match self {
1510 OverlayFragment::SparseOffsets { offsets, .. } => {
1511 let start = u32::try_from(range.start).unwrap_or(u32::MAX);
1512 let idx = offsets.partition_point(|off| *off < start);
1513 offsets
1514 .get(idx)
1515 .is_some_and(|off| (*off as usize) < range.end)
1516 }
1517 OverlayFragment::DenseRange { .. } | OverlayFragment::RunRange { .. } => self
1518 .interval_coverage()
1519 .is_some_and(|r| r.start < range.end && range.start < r.end),
1520 }
1521 }
1522
1523 fn intersects_fragment_exact(&self, replacement: &OverlayFragment) -> bool {
1524 if let Some(offsets) = replacement.sparse_offsets_slice() {
1525 self.intersects_sparse_offsets(offsets)
1526 } else if let Some(range) = replacement.interval_coverage() {
1527 self.intersects_interval(range)
1528 } else {
1529 false
1530 }
1531 }
1532
1533 fn intersects_interval(&self, range: core::ops::Range<usize>) -> bool {
1534 if range.is_empty() {
1535 return false;
1536 }
1537 match self {
1538 OverlayFragment::SparseOffsets { offsets, .. } => {
1539 let start = u32::try_from(range.start).unwrap_or(u32::MAX);
1540 let idx = offsets.partition_point(|off| *off < start);
1541 offsets
1542 .get(idx)
1543 .is_some_and(|off| (*off as usize) < range.end)
1544 }
1545 OverlayFragment::DenseRange { .. } | OverlayFragment::RunRange { .. } => self
1546 .interval_coverage()
1547 .is_some_and(|own| own.start < range.end && range.start < own.end),
1548 }
1549 }
1550
1551 fn intersects_sparse_offsets(&self, replacement_offsets: &[u32]) -> bool {
1552 if replacement_offsets.is_empty() {
1553 return false;
1554 }
1555 match self {
1556 OverlayFragment::SparseOffsets { offsets, .. } => {
1557 Self::sorted_offsets_intersect(offsets, replacement_offsets)
1558 }
1559 OverlayFragment::DenseRange { .. } | OverlayFragment::RunRange { .. } => {
1560 self.interval_coverage().is_some_and(|range| {
1561 let start = u32::try_from(range.start).unwrap_or(u32::MAX);
1562 let idx = replacement_offsets.partition_point(|off| *off < start);
1563 replacement_offsets
1564 .get(idx)
1565 .is_some_and(|off| (*off as usize) < range.end)
1566 })
1567 }
1568 }
1569 }
1570
1571 fn sorted_offsets_intersect(a: &[u32], b: &[u32]) -> bool {
1572 let mut ai = 0usize;
1573 let mut bi = 0usize;
1574 while ai < a.len() && bi < b.len() {
1575 match a[ai].cmp(&b[bi]) {
1576 core::cmp::Ordering::Equal => return true,
1577 core::cmp::Ordering::Less => ai += 1,
1578 core::cmp::Ordering::Greater => bi += 1,
1579 }
1580 }
1581 false
1582 }
1583
1584 fn covers_offset(&self, off: usize) -> bool {
1585 self.get_scalar(off).is_some()
1586 }
1587
1588 fn get_scalar(&self, off: usize) -> Option<OverlayScalar<'_>> {
1589 match self {
1590 OverlayFragment::SparseOffsets { offsets, payload } => {
1591 let off = u32::try_from(off).ok()?;
1592 let idx = offsets.binary_search(&off).ok()?;
1593 payload.get_scalar(idx)
1594 }
1595 OverlayFragment::DenseRange {
1596 start,
1597 len,
1598 payload,
1599 } => {
1600 let start = *start as usize;
1601 let rel = off.checked_sub(start)?;
1602 if rel >= *len as usize {
1603 return None;
1604 }
1605 payload.get_scalar(rel)
1606 }
1607 OverlayFragment::RunRange {
1608 start,
1609 len,
1610 run_ends,
1611 payload,
1612 } => {
1613 let start = *start as usize;
1614 let rel = off.checked_sub(start)?;
1615 if rel >= *len as usize {
1616 return None;
1617 }
1618 let rel_u32 = u32::try_from(rel).ok()?;
1619 let run_idx = run_ends.partition_point(|end| *end <= rel_u32);
1620 payload.get_scalar(run_idx)
1621 }
1622 }
1623 }
1624
1625 fn subtract_fragment(&self, replacement: &OverlayFragment) -> Vec<OverlayFragment> {
1626 if let Some(offsets) = replacement.sparse_offsets_slice() {
1627 self.subtract_sparse_offsets(offsets)
1628 } else if let Some(range) = replacement.interval_coverage() {
1629 self.subtract_interval(range)
1630 } else {
1631 vec![self.clone()]
1632 }
1633 }
1634
1635 fn subtract_offset(&self, off: usize) -> Vec<OverlayFragment> {
1636 match self {
1637 OverlayFragment::SparseOffsets { .. } => {
1638 let Ok(off) = u32::try_from(off) else {
1639 return vec![self.clone()];
1640 };
1641 self.subtract_sparse_offsets(core::slice::from_ref(&off))
1642 }
1643 OverlayFragment::DenseRange { .. } | OverlayFragment::RunRange { .. } => {
1644 self.subtract_interval(off..off.saturating_add(1))
1645 }
1646 }
1647 }
1648
1649 fn subtract_interval(&self, replacement: core::ops::Range<usize>) -> Vec<OverlayFragment> {
1650 if replacement.is_empty() {
1651 return vec![self.clone()];
1652 }
1653
1654 match self {
1655 OverlayFragment::SparseOffsets { offsets, payload } => {
1656 let cells: Vec<_> = offsets
1657 .iter()
1658 .enumerate()
1659 .filter_map(|(idx, off)| {
1660 let off_usize = *off as usize;
1661 (!replacement.contains(&off_usize))
1662 .then(|| payload.overlay_value(idx).map(|value| (off_usize, value)))?
1663 })
1664 .collect();
1665 OverlayFragment::sparse_offsets(cells).into_iter().collect()
1666 }
1667 OverlayFragment::DenseRange { .. } => {
1668 let Some(own) = self.interval_coverage() else {
1669 return vec![self.clone()];
1670 };
1671 if own.end <= replacement.start || replacement.end <= own.start {
1672 return vec![self.clone()];
1673 }
1674 let cut_start = replacement.start.max(own.start);
1675 let cut_end = replacement.end.min(own.end);
1676 let mut out = Vec::with_capacity(2);
1677 if own.start < cut_start
1678 && let Some(left) =
1679 self.dense_segment_with_start(own.start, own.start, cut_start)
1680 {
1681 out.push(left);
1682 }
1683 if cut_end < own.end
1684 && let Some(right) = self.dense_segment_with_start(cut_end, cut_end, own.end)
1685 {
1686 out.push(right);
1687 }
1688 out
1689 }
1690 OverlayFragment::RunRange { .. } => {
1691 let Some(own) = self.interval_coverage() else {
1692 return vec![self.clone()];
1693 };
1694 if own.end <= replacement.start || replacement.end <= own.start {
1695 return vec![self.clone()];
1696 }
1697 let cut_start = replacement.start.max(own.start);
1698 let cut_end = replacement.end.min(own.end);
1699 let mut out = Vec::with_capacity(2);
1700 if own.start < cut_start
1701 && let Some(left) = self.run_segment_with_start(own.start, own.start, cut_start)
1702 {
1703 out.push(left);
1704 }
1705 if cut_end < own.end
1706 && let Some(right) = self.run_segment_with_start(cut_end, cut_end, own.end)
1707 {
1708 out.push(right);
1709 }
1710 out
1711 }
1712 }
1713 }
1714
1715 fn subtract_sparse_offsets(&self, replacement_offsets: &[u32]) -> Vec<OverlayFragment> {
1716 if replacement_offsets.is_empty() {
1717 return vec![self.clone()];
1718 }
1719
1720 match self {
1721 OverlayFragment::SparseOffsets { offsets, payload } => {
1722 let cells: Vec<_> = offsets
1723 .iter()
1724 .enumerate()
1725 .filter_map(|(idx, off)| {
1726 replacement_offsets.binary_search(off).is_err().then(|| {
1727 payload
1728 .overlay_value(idx)
1729 .map(|value| (*off as usize, value))
1730 })?
1731 })
1732 .collect();
1733 OverlayFragment::sparse_offsets(cells).into_iter().collect()
1734 }
1735 OverlayFragment::DenseRange { .. } => {
1736 self.subtract_sparse_offsets_from_dense(replacement_offsets)
1737 }
1738 OverlayFragment::RunRange { .. } => {
1739 self.subtract_sparse_offsets_from_run(replacement_offsets)
1740 }
1741 }
1742 }
1743
1744 fn sparse_holes_in_interval(offsets: &[u32], range: core::ops::Range<usize>) -> Vec<usize> {
1745 if range.is_empty() {
1746 return Vec::new();
1747 }
1748 let start = u32::try_from(range.start).unwrap_or(u32::MAX);
1749 let mut idx = offsets.partition_point(|off| *off < start);
1750 let mut holes = Vec::new();
1751 let mut last = None;
1752 while let Some(off) = offsets.get(idx).copied() {
1753 let off_usize = off as usize;
1754 if off_usize >= range.end {
1755 break;
1756 }
1757 if last != Some(off_usize) {
1758 holes.push(off_usize);
1759 last = Some(off_usize);
1760 }
1761 idx += 1;
1762 }
1763 holes
1764 }
1765
1766 fn subtract_sparse_offsets_from_dense(
1767 &self,
1768 replacement_offsets: &[u32],
1769 ) -> Vec<OverlayFragment> {
1770 let Some(own) = self.interval_coverage() else {
1771 return vec![self.clone()];
1772 };
1773 let holes = Self::sparse_holes_in_interval(replacement_offsets, own.clone());
1774 if holes.is_empty() {
1775 return vec![self.clone()];
1776 }
1777 if holes.len().saturating_add(1) > Self::MAX_SPLIT_SEGMENTS_BEFORE_SPARSE_FALLBACK {
1778 return self.sparse_remainder_excluding_offsets(&holes);
1779 }
1780
1781 let mut out = Vec::with_capacity(holes.len().saturating_add(1));
1782 let mut seg_start = own.start;
1783 for hole in holes {
1784 if seg_start < hole
1785 && let Some(segment) = self.dense_segment_with_start(seg_start, seg_start, hole)
1786 {
1787 out.push(segment);
1788 }
1789 seg_start = hole.saturating_add(1);
1790 }
1791 if seg_start < own.end
1792 && let Some(segment) = self.dense_segment_with_start(seg_start, seg_start, own.end)
1793 {
1794 out.push(segment);
1795 }
1796 out
1797 }
1798
1799 fn subtract_sparse_offsets_from_run(
1800 &self,
1801 replacement_offsets: &[u32],
1802 ) -> Vec<OverlayFragment> {
1803 let Some(own) = self.interval_coverage() else {
1804 return vec![self.clone()];
1805 };
1806 let holes = Self::sparse_holes_in_interval(replacement_offsets, own.clone());
1807 if holes.is_empty() {
1808 return vec![self.clone()];
1809 }
1810 if holes.len().saturating_add(1) > Self::MAX_SPLIT_SEGMENTS_BEFORE_SPARSE_FALLBACK {
1811 return self.sparse_remainder_excluding_offsets(&holes);
1812 }
1813
1814 let mut out = Vec::with_capacity(holes.len().saturating_add(1));
1815 let mut seg_start = own.start;
1816 for hole in holes {
1817 if seg_start < hole
1818 && let Some(segment) = self.run_segment_with_start(seg_start, seg_start, hole)
1819 {
1820 out.push(segment);
1821 }
1822 seg_start = hole.saturating_add(1);
1823 }
1824 if seg_start < own.end
1825 && let Some(segment) = self.run_segment_with_start(seg_start, seg_start, own.end)
1826 {
1827 out.push(segment);
1828 }
1829 out
1830 }
1831
1832 fn sparse_remainder_excluding_offsets(&self, sorted_holes: &[usize]) -> Vec<OverlayFragment> {
1833 let cells: Vec<_> = self
1834 .cells()
1835 .into_iter()
1836 .filter(|(off, _)| sorted_holes.binary_search(off).is_err())
1837 .collect();
1838 OverlayFragment::sparse_offsets(cells).into_iter().collect()
1839 }
1840
1841 fn dense_segment_with_start(
1842 &self,
1843 new_start: usize,
1844 abs_start: usize,
1845 abs_end: usize,
1846 ) -> Option<OverlayFragment> {
1847 match self {
1848 OverlayFragment::DenseRange { start, payload, .. } => {
1849 if abs_start >= abs_end {
1850 return None;
1851 }
1852 let base = *start as usize;
1853 let rel_start = abs_start.checked_sub(base)?;
1854 let len = abs_end.saturating_sub(abs_start);
1855 OverlayFragment::dense_range(new_start, payload.values_slice(rel_start, len))
1856 }
1857 _ => None,
1858 }
1859 }
1860
1861 fn run_segment_with_start(
1862 &self,
1863 new_start: usize,
1864 abs_start: usize,
1865 abs_end: usize,
1866 ) -> Option<OverlayFragment> {
1867 let OverlayFragment::RunRange {
1868 start,
1869 len,
1870 run_ends,
1871 payload,
1872 } = self
1873 else {
1874 return None;
1875 };
1876 if abs_start >= abs_end {
1877 return None;
1878 }
1879 let base = *start as usize;
1880 let frag_end = base.saturating_add(*len as usize);
1881 if abs_start < base || abs_end > frag_end {
1882 return None;
1883 }
1884
1885 let rel_start = abs_start - base;
1886 let rel_end = abs_end - base;
1887 let mut new_run_ends = Vec::new();
1888 let mut new_values = Vec::new();
1889 let mut prev_end = 0usize;
1890
1891 for (run_idx, end) in run_ends.iter().enumerate() {
1892 let run_start = prev_end;
1893 let run_end = *end as usize;
1894 let inter_start = run_start.max(rel_start);
1895 let inter_end = run_end.min(rel_end);
1896 if inter_start < inter_end {
1897 new_run_ends.push(inter_end - rel_start);
1898 if let Some(value) = payload.overlay_value(run_idx) {
1899 new_values.push(value);
1900 }
1901 }
1902 prev_end = run_end;
1903 if prev_end >= rel_end {
1904 break;
1905 }
1906 }
1907
1908 OverlayFragment::run_range_from_parts(
1909 new_start,
1910 abs_end.saturating_sub(abs_start),
1911 new_run_ends,
1912 new_values,
1913 )
1914 }
1915
1916 fn cells(&self) -> Vec<(usize, OverlayValue)> {
1917 match self {
1918 OverlayFragment::SparseOffsets { offsets, payload } => offsets
1919 .iter()
1920 .enumerate()
1921 .filter_map(|(idx, off)| {
1922 payload
1923 .overlay_value(idx)
1924 .map(|value| (*off as usize, value))
1925 })
1926 .collect(),
1927 OverlayFragment::DenseRange {
1928 start,
1929 len,
1930 payload,
1931 } => {
1932 let start = *start as usize;
1933 (0..*len as usize)
1934 .filter_map(|idx| {
1935 payload
1936 .overlay_value(idx)
1937 .map(|value| (start.saturating_add(idx), value))
1938 })
1939 .collect()
1940 }
1941 OverlayFragment::RunRange { start, len, .. } => {
1942 let start = *start as usize;
1943 (0..*len as usize)
1944 .filter_map(|idx| {
1945 self.get_scalar(start.saturating_add(idx))
1946 .map(|value| (start.saturating_add(idx), value.to_overlay_value()))
1947 })
1948 .collect()
1949 }
1950 }
1951 }
1952
1953 fn slice(&self, off: usize, len: usize) -> Option<OverlayFragment> {
1954 let end = off.saturating_add(len);
1955 if len == 0 {
1956 return None;
1957 }
1958
1959 match self {
1960 OverlayFragment::SparseOffsets { offsets, payload } => {
1961 let start = u32::try_from(off).unwrap_or(u32::MAX);
1962 let lo = offsets.partition_point(|candidate| *candidate < start);
1963 let hi = offsets.partition_point(|candidate| (*candidate as usize) < end);
1964 let cells: Vec<_> = (lo..hi)
1965 .filter_map(|idx| {
1966 let rebased = (offsets[idx] as usize).saturating_sub(off);
1967 payload.overlay_value(idx).map(|value| (rebased, value))
1968 })
1969 .collect();
1970 OverlayFragment::sparse_offsets(cells)
1971 }
1972 OverlayFragment::DenseRange { .. } => {
1973 let own = self.interval_coverage()?;
1974 let seg_start = own.start.max(off);
1975 let seg_end = own.end.min(end);
1976 if seg_start >= seg_end {
1977 return None;
1978 }
1979 self.dense_segment_with_start(seg_start - off, seg_start, seg_end)
1980 }
1981 OverlayFragment::RunRange { .. } => {
1982 let own = self.interval_coverage()?;
1983 let seg_start = own.start.max(off);
1984 let seg_end = own.end.min(end);
1985 if seg_start >= seg_end {
1986 return None;
1987 }
1988 self.run_segment_with_start(seg_start - off, seg_start, seg_end)
1989 }
1990 }
1991 }
1992}
1993#[derive(Debug, Default, Clone)]
1994pub struct Overlay {
1995 points: HashMap<usize, OverlayValue>,
1996 format_points: HashMap<usize, FormatId>,
1997 fragments: Vec<OverlayFragment>,
1998 estimated_bytes: usize,
2002}
2003
2004impl Overlay {
2005 const ENTRY_BASE_BYTES: usize = OVERLAY_ENTRY_BASE_BYTES;
2008
2009 pub fn new() -> Self {
2010 Self {
2011 points: HashMap::new(),
2012 format_points: HashMap::new(),
2013 fragments: Vec::new(),
2014 estimated_bytes: 0,
2015 }
2016 }
2017
2018 #[inline]
2019 fn point_estimate(v: &OverlayValue) -> usize {
2020 Self::ENTRY_BASE_BYTES + v.estimated_payload_bytes()
2021 }
2022
2023 #[inline]
2024 fn adjust_estimated_bytes(&mut self, delta: isize) {
2025 if delta >= 0 {
2026 self.estimated_bytes = self.estimated_bytes.saturating_add(delta as usize);
2027 } else {
2028 self.estimated_bytes = self.estimated_bytes.saturating_sub((-delta) as usize);
2029 }
2030 }
2031
2032 #[inline]
2033 pub(crate) fn get_scalar(&self, off: usize) -> Option<OverlayScalar<'_>> {
2034 self.points
2035 .get(&off)
2036 .map(OverlayScalar::Borrowed)
2037 .or_else(|| self.fragments.iter().rev().find_map(|f| f.get_scalar(off)))
2038 }
2039
2040 #[inline]
2041 pub fn get(&self, off: usize) -> Option<OverlayValue> {
2042 self.get_scalar(off).map(|value| value.to_overlay_value())
2043 }
2044
2045 #[inline]
2046 pub fn get_format(&self, off: usize) -> Option<FormatId> {
2047 self.format_points.get(&off).copied()
2048 }
2049
2050 #[inline]
2051 pub(crate) fn has_formats(&self) -> bool {
2052 !self.format_points.is_empty()
2053 }
2054
2055 #[inline]
2056 pub fn set_format(&mut self, off: usize, format: Option<FormatId>) {
2057 match format.filter(|id| *id != FormatId::GENERAL) {
2058 Some(id) => {
2059 self.format_points.insert(off, id);
2060 }
2061 None => {
2062 self.format_points.remove(&off);
2063 }
2064 }
2065 }
2066
2067 pub(crate) fn clear_format_range(&mut self, start: usize, end: usize) {
2070 if self.format_points.is_empty() || start >= end {
2071 return;
2072 }
2073 self.format_points
2074 .retain(|off, _| *off < start || *off >= end);
2075 }
2076
2077 pub(crate) fn clear_format_offsets(&mut self, offsets: &[usize]) {
2079 if self.format_points.is_empty() {
2080 return;
2081 }
2082 for off in offsets {
2083 self.format_points.remove(off);
2084 }
2085 }
2086
2087 #[inline]
2088 pub(crate) fn set_scalar(&mut self, off: usize, v: OverlayValue) -> isize {
2089 let removed = self.remove_scalar(off);
2090 let new_est = Self::point_estimate(&v);
2091 self.points.insert(off, v);
2092 self.adjust_estimated_bytes(new_est as isize);
2093 removed.saturating_add(new_est as isize)
2094 }
2095
2096 #[inline]
2097 pub fn set(&mut self, off: usize, v: OverlayValue) -> isize {
2098 self.set_scalar(off, v)
2099 }
2100
2101 pub(crate) fn apply_fragment(&mut self, fragment: OverlayFragment) -> isize {
2102 let mut delta = self.remove_points_covered_by_fragment(&fragment);
2103 delta = delta.saturating_add(self.remove_fragments_covered_by_fragment(&fragment));
2104
2105 let fragment_est = fragment.estimated_bytes();
2106 self.fragments.push(fragment);
2107 self.adjust_estimated_bytes(fragment_est as isize);
2108 delta.saturating_add(fragment_est as isize)
2109 }
2110
2111 fn remove_points_covered_by_fragment(&mut self, fragment: &OverlayFragment) -> isize {
2112 let mut removed = 0usize;
2113 match fragment {
2114 OverlayFragment::SparseOffsets { offsets, .. } => {
2115 for off in offsets.iter().copied() {
2116 if let Some(old) = self.points.remove(&(off as usize)) {
2117 removed = removed.saturating_add(Self::point_estimate(&old));
2118 }
2119 }
2120 }
2121 OverlayFragment::DenseRange { .. } | OverlayFragment::RunRange { .. } => {
2122 if let Some(range) = fragment.interval_coverage() {
2123 let keys: Vec<_> = self
2124 .points
2125 .keys()
2126 .copied()
2127 .filter(|off| range.contains(off))
2128 .collect();
2129 for off in keys {
2130 if let Some(old) = self.points.remove(&off) {
2131 removed = removed.saturating_add(Self::point_estimate(&old));
2132 }
2133 }
2134 }
2135 }
2136 }
2137 self.estimated_bytes = self.estimated_bytes.saturating_sub(removed);
2138 -(removed as isize)
2139 }
2140
2141 fn remove_fragments_covered_by_fragment(&mut self, replacement: &OverlayFragment) -> isize {
2142 if self.fragments.is_empty() {
2143 return 0;
2144 }
2145
2146 let mut delta: isize = 0;
2147 let mut fragments = Vec::with_capacity(self.fragments.len());
2148 for fragment in self.fragments.drain(..) {
2149 if !fragment.intersects_fragment_exact(replacement) {
2150 fragments.push(fragment);
2151 continue;
2152 }
2153
2154 let old_est = fragment.estimated_bytes();
2155 let replacements = fragment.subtract_fragment(replacement);
2156 let new_est = replacements
2157 .iter()
2158 .map(OverlayFragment::estimated_bytes)
2159 .fold(0usize, usize::saturating_add);
2160 fragments.extend(replacements);
2161 delta = delta.saturating_add(new_est as isize - old_est as isize);
2162 }
2163 self.fragments = fragments;
2164 self.adjust_estimated_bytes(delta);
2165 delta
2166 }
2167
2168 #[inline]
2169 pub(crate) fn remove_scalar(&mut self, off: usize) -> isize {
2170 let mut delta = 0isize;
2171 if let Some(old) = self.points.remove(&off) {
2172 let old_est = Self::point_estimate(&old);
2173 self.estimated_bytes = self.estimated_bytes.saturating_sub(old_est);
2174 delta = delta.saturating_sub(old_est as isize);
2175 }
2176
2177 if !self.fragments.is_empty() {
2178 let mut fragments = Vec::with_capacity(self.fragments.len());
2179 for fragment in self.fragments.drain(..) {
2180 if fragment.get_scalar(off).is_none() {
2181 fragments.push(fragment);
2182 continue;
2183 }
2184
2185 let old_est = fragment.estimated_bytes();
2186 let replacements = fragment.subtract_offset(off);
2187 let new_est = replacements
2188 .iter()
2189 .map(OverlayFragment::estimated_bytes)
2190 .fold(0usize, usize::saturating_add);
2191 fragments.extend(replacements);
2192 delta = delta.saturating_add(new_est as isize - old_est as isize);
2193 }
2194 self.fragments = fragments;
2195 self.adjust_estimated_bytes(delta);
2196 }
2197
2198 delta
2199 }
2200
2201 #[inline]
2202 pub fn remove(&mut self, off: usize) -> isize {
2203 self.remove_scalar(off)
2204 }
2205
2206 pub(crate) fn remove_range(&mut self, range: core::ops::Range<usize>) -> isize {
2207 if range.is_empty() {
2208 return 0;
2209 }
2210
2211 let mut delta = 0isize;
2212 let removed_points: Vec<_> = self
2213 .points
2214 .keys()
2215 .copied()
2216 .filter(|off| range.contains(off))
2217 .collect();
2218 for off in removed_points {
2219 if let Some(old) = self.points.remove(&off) {
2220 let old_est = Self::point_estimate(&old);
2221 self.estimated_bytes = self.estimated_bytes.saturating_sub(old_est);
2222 delta = delta.saturating_sub(old_est as isize);
2223 }
2224 }
2225
2226 if !self.fragments.is_empty() {
2227 let mut fragment_delta = 0isize;
2228 let mut fragments = Vec::with_capacity(self.fragments.len());
2229 for fragment in self.fragments.drain(..) {
2230 let old_est = fragment.estimated_bytes();
2231 let replacements = fragment.subtract_interval(range.clone());
2232 let new_est = replacements
2233 .iter()
2234 .map(OverlayFragment::estimated_bytes)
2235 .fold(0usize, usize::saturating_add);
2236 fragments.extend(replacements);
2237 fragment_delta = fragment_delta.saturating_add(new_est as isize - old_est as isize);
2238 }
2239 self.fragments = fragments;
2240 self.adjust_estimated_bytes(fragment_delta);
2241 delta = delta.saturating_add(fragment_delta);
2242 }
2243
2244 delta
2245 }
2246
2247 #[inline]
2248 pub(crate) fn clear_all(&mut self) -> usize {
2249 let freed = self.estimated_bytes;
2250 self.points.clear();
2251 self.fragments.clear();
2252 self.estimated_bytes = 0;
2253 freed
2254 }
2255
2256 #[inline]
2257 pub fn clear(&mut self) -> usize {
2258 self.clear_all()
2259 }
2260
2261 #[inline]
2262 pub fn len(&self) -> usize {
2263 self.points.len().saturating_add(
2264 self.fragments
2265 .iter()
2266 .map(OverlayFragment::coverage_len)
2267 .sum(),
2268 )
2269 }
2270
2271 #[inline]
2272 pub fn estimated_bytes(&self) -> usize {
2273 self.estimated_bytes
2274 }
2275
2276 #[inline]
2277 pub fn is_empty(&self) -> bool {
2278 self.points.is_empty() && self.fragments.is_empty()
2279 }
2280
2281 #[inline]
2282 pub(crate) fn has_any_in_range(&self, range: core::ops::Range<usize>) -> bool {
2283 self.points.keys().any(|k| range.contains(k))
2284 || self
2285 .fragments
2286 .iter()
2287 .any(|fragment| fragment.has_any_in_range(range.clone()))
2288 }
2289
2290 #[inline]
2291 pub fn any_in_range(&self, range: core::ops::Range<usize>) -> bool {
2292 self.has_any_in_range(range)
2293 }
2294
2295 pub(crate) fn slice(&self, off: usize, len: usize) -> Overlay {
2296 let mut out = Overlay::new();
2297 let end = off.saturating_add(len);
2298 for fragment in &self.fragments {
2299 if let Some(sliced) = fragment.slice(off, len) {
2300 let _ = out.apply_fragment(sliced);
2301 }
2302 }
2303 for (k, v) in self.points.iter() {
2304 if *k >= off && *k < end {
2305 let _ = out.set_scalar(*k - off, v.clone());
2306 }
2307 }
2308 for (k, format) in &self.format_points {
2309 if *k >= off && *k < end {
2310 out.set_format(*k - off, Some(*format));
2311 }
2312 }
2313 out
2314 }
2315
2316 pub fn iter(&self) -> impl Iterator<Item = (usize, OverlayValue)> {
2318 let mut cells = BTreeMap::new();
2319 for fragment in &self.fragments {
2320 for (off, value) in fragment.cells() {
2321 cells.insert(off, value);
2322 }
2323 }
2324 for (off, value) in &self.points {
2325 cells.insert(*off, value.clone());
2326 }
2327 cells.into_iter()
2328 }
2329
2330 pub(crate) fn iter_points(&self) -> impl Iterator<Item = (&usize, &OverlayValue)> {
2332 self.points.iter()
2333 }
2334}
2335
2336#[cfg(test)]
2337#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
2338pub(crate) struct OverlayDebugStats {
2339 pub(crate) points: usize,
2340 pub(crate) sparse_fragments: usize,
2341 pub(crate) dense_fragments: usize,
2342 pub(crate) run_fragments: usize,
2343 pub(crate) covered_len: usize,
2344}
2345
2346#[cfg(test)]
2347impl Overlay {
2348 pub(crate) fn debug_stats(&self) -> OverlayDebugStats {
2349 let mut stats = OverlayDebugStats {
2350 points: self.points.len(),
2351 covered_len: self.len(),
2352 ..OverlayDebugStats::default()
2353 };
2354 for fragment in &self.fragments {
2355 match fragment {
2356 OverlayFragment::SparseOffsets { .. } => stats.sparse_fragments += 1,
2357 OverlayFragment::DenseRange { .. } => stats.dense_fragments += 1,
2358 OverlayFragment::RunRange { .. } => stats.run_fragments += 1,
2359 }
2360 }
2361 stats
2362 }
2363
2364 pub(crate) fn debug_is_normalized(&self) -> bool {
2365 let mut covered = std::collections::HashSet::new();
2366 for off in self.points.keys().copied() {
2367 if !covered.insert(off) {
2368 return false;
2369 }
2370 }
2371 for fragment in &self.fragments {
2372 for (off, _) in fragment.cells() {
2373 if !covered.insert(off) {
2374 return false;
2375 }
2376 }
2377 }
2378 covered.len() == self.len()
2379 }
2380
2381 pub(crate) fn debug_recomputed_estimated_bytes(&self) -> usize {
2382 let point_bytes = self
2383 .points
2384 .values()
2385 .map(Self::point_estimate)
2386 .fold(0usize, usize::saturating_add);
2387 let fragment_bytes = self
2388 .fragments
2389 .iter()
2390 .map(OverlayFragment::estimated_bytes)
2391 .fold(0usize, usize::saturating_add);
2392 point_bytes.saturating_add(fragment_bytes)
2393 }
2394}
2395
2396#[derive(Debug, Clone, Copy, Default)]
2397#[cfg_attr(test, derive(serde::Serialize))]
2398pub(crate) struct OverlaySelectStats {
2399 pub(crate) zip_select_calls: usize,
2400 pub(crate) direct_dense_slices: usize,
2401 pub(crate) direct_run_materializations: usize,
2402 pub(crate) partial_sparse_intersections: usize,
2403 pub(crate) partial_dense_intersections: usize,
2404 pub(crate) partial_run_intersections: usize,
2405 pub(crate) partial_overlay_builds: usize,
2406 pub(crate) row_scalar_fallbacks: usize,
2407 pub(crate) point_entries_applied: usize,
2408 pub(crate) fragment_intersections: usize,
2409}
2410
2411#[cfg(test)]
2412thread_local! {
2413 static OVERLAY_SELECT_STATS: std::cell::RefCell<OverlaySelectStats> =
2414 std::cell::RefCell::new(OverlaySelectStats::default());
2415}
2416
2417#[cfg(test)]
2418pub(crate) fn reset_overlay_select_stats() {
2419 OVERLAY_SELECT_STATS.with(|stats| *stats.borrow_mut() = OverlaySelectStats::default());
2420}
2421
2422#[cfg(test)]
2423pub(crate) fn snapshot_overlay_select_stats() -> OverlaySelectStats {
2424 OVERLAY_SELECT_STATS.with(|stats| *stats.borrow())
2425}
2426
2427#[cfg(test)]
2428fn record_overlay_select_stats(f: impl FnOnce(&mut OverlaySelectStats)) {
2429 OVERLAY_SELECT_STATS.with(|stats| f(&mut stats.borrow_mut()));
2430}
2431
2432#[cfg(not(test))]
2433#[inline]
2434fn record_overlay_select_stats(_f: impl FnOnce(&mut OverlaySelectStats)) {}
2435
2436#[derive(Debug, Clone, Copy, Eq, PartialEq)]
2437enum OverlayFragmentShape {
2438 Sparse,
2439 Dense,
2440 Run,
2441}
2442
2443struct OverlaySlots<T> {
2444 present: Vec<bool>,
2445 values: Vec<Option<T>>,
2446 any_present: bool,
2447}
2448
2449impl<T> OverlaySlots<T> {
2450 fn new(len: usize) -> Self {
2451 Self {
2452 present: vec![false; len],
2453 values: (0..len).map(|_| None).collect(),
2454 any_present: false,
2455 }
2456 }
2457
2458 #[inline]
2459 fn set(&mut self, idx: usize, value: Option<T>) {
2460 if idx >= self.present.len() {
2461 return;
2462 }
2463 self.present[idx] = true;
2464 self.values[idx] = value;
2465 self.any_present = true;
2466 }
2467
2468 #[inline]
2469 fn any_present(&self) -> bool {
2470 self.any_present
2471 }
2472}
2473
2474pub(crate) struct OverlayCascade<'a> {
2475 user: &'a Overlay,
2476 computed: &'a Overlay,
2477}
2478
2479impl<'a> OverlayCascade<'a> {
2480 #[inline]
2481 pub(crate) fn new(user: &'a Overlay, computed: &'a Overlay) -> Self {
2482 Self { user, computed }
2483 }
2484
2485 #[inline]
2486 pub(crate) fn get_scalar(&self, off: usize) -> Option<OverlayScalar<'a>> {
2487 self.user
2488 .get_scalar(off)
2489 .or_else(|| self.computed.get_scalar(off))
2490 }
2491
2492 #[inline]
2493 pub(crate) fn get_format(&self, off: usize) -> Option<FormatId> {
2494 self.user
2495 .get_format(off)
2496 .or_else(|| self.computed.get_format(off))
2497 }
2498
2499 #[inline]
2500 pub(crate) fn has_any_in_range(&self, range: core::ops::Range<usize>) -> bool {
2501 self.user.has_any_in_range(range.clone()) || self.computed.has_any_in_range(range)
2502 }
2503
2504 pub(crate) fn select_numbers(
2505 &self,
2506 range: core::ops::Range<usize>,
2507 base: &Float64Array,
2508 ) -> Arc<Float64Array> {
2509 if let Some(fragment) = self.user.full_cover_dense_fragment(range.clone()) {
2510 record_overlay_select_stats(|stats| stats.direct_dense_slices += 1);
2511 return Self::dense_numbers(fragment, range);
2512 }
2513 if let Some(fragment) = self.user.full_cover_run_fragment(range.clone()) {
2514 record_overlay_select_stats(|stats| stats.direct_run_materializations += 1);
2515 return Self::run_numbers(fragment, range);
2516 }
2517 if !self.user.has_any_in_range(range.clone()) {
2518 if let Some(fragment) = self.computed.full_cover_dense_fragment(range.clone()) {
2519 record_overlay_select_stats(|stats| stats.direct_dense_slices += 1);
2520 return Self::dense_numbers(fragment, range);
2521 }
2522 if let Some(fragment) = self.computed.full_cover_run_fragment(range.clone()) {
2523 record_overlay_select_stats(|stats| stats.direct_run_materializations += 1);
2524 return Self::run_numbers(fragment, range);
2525 }
2526 }
2527
2528 if !self.has_any_in_range(range.clone()) {
2529 return Arc::new(base.clone());
2530 }
2531
2532 record_overlay_select_stats(|stats| stats.partial_overlay_builds += 1);
2533 let len = range.end.saturating_sub(range.start);
2534 let mut slots = OverlaySlots::<f64>::new(len);
2535 Self::apply_number_layer(self.computed, range.clone(), &mut slots);
2536 Self::apply_number_layer(self.user, range.clone(), &mut slots);
2537 if !slots.any_present() {
2538 return Arc::new(base.clone());
2539 }
2540
2541 let mut mask_b = BooleanBuilder::with_capacity(len);
2542 let mut values_b = Float64Builder::with_capacity(len);
2543 for idx in 0..len {
2544 mask_b.append_value(slots.present[idx]);
2545 match slots.values[idx] {
2546 Some(value) => values_b.append_value(value),
2547 None => values_b.append_null(),
2548 }
2549 }
2550 record_overlay_select_stats(|stats| stats.zip_select_calls += 1);
2551 let mask = mask_b.finish();
2552 let values = values_b.finish();
2553 let zipped =
2554 crate::compute_prelude::zip_select(&mask, &values, base).expect("zip numeric overlay");
2555 Arc::new(
2556 zipped
2557 .as_any()
2558 .downcast_ref::<Float64Array>()
2559 .expect("numeric overlay zip type")
2560 .clone(),
2561 )
2562 }
2563
2564 pub(crate) fn select_booleans(
2565 &self,
2566 range: core::ops::Range<usize>,
2567 base: &BooleanArray,
2568 ) -> Arc<BooleanArray> {
2569 if let Some(fragment) = self.user.full_cover_dense_fragment(range.clone()) {
2570 record_overlay_select_stats(|stats| stats.direct_dense_slices += 1);
2571 return Self::dense_booleans(fragment, range);
2572 }
2573 if let Some(fragment) = self.user.full_cover_run_fragment(range.clone()) {
2574 record_overlay_select_stats(|stats| stats.direct_run_materializations += 1);
2575 return Self::run_booleans(fragment, range);
2576 }
2577 if !self.user.has_any_in_range(range.clone()) {
2578 if let Some(fragment) = self.computed.full_cover_dense_fragment(range.clone()) {
2579 record_overlay_select_stats(|stats| stats.direct_dense_slices += 1);
2580 return Self::dense_booleans(fragment, range);
2581 }
2582 if let Some(fragment) = self.computed.full_cover_run_fragment(range.clone()) {
2583 record_overlay_select_stats(|stats| stats.direct_run_materializations += 1);
2584 return Self::run_booleans(fragment, range);
2585 }
2586 }
2587
2588 if !self.has_any_in_range(range.clone()) {
2589 return Arc::new(base.clone());
2590 }
2591
2592 record_overlay_select_stats(|stats| stats.partial_overlay_builds += 1);
2593 let len = range.end.saturating_sub(range.start);
2594 let mut slots = OverlaySlots::<bool>::new(len);
2595 Self::apply_boolean_layer(self.computed, range.clone(), &mut slots);
2596 Self::apply_boolean_layer(self.user, range.clone(), &mut slots);
2597 if !slots.any_present() {
2598 return Arc::new(base.clone());
2599 }
2600
2601 let mut mask_b = BooleanBuilder::with_capacity(len);
2602 let mut values_b = BooleanBuilder::with_capacity(len);
2603 for idx in 0..len {
2604 mask_b.append_value(slots.present[idx]);
2605 match slots.values[idx] {
2606 Some(value) => values_b.append_value(value),
2607 None => values_b.append_null(),
2608 }
2609 }
2610 record_overlay_select_stats(|stats| stats.zip_select_calls += 1);
2611 let mask = mask_b.finish();
2612 let values = values_b.finish();
2613 let zipped =
2614 crate::compute_prelude::zip_select(&mask, &values, base).expect("zip boolean overlay");
2615 Arc::new(
2616 zipped
2617 .as_any()
2618 .downcast_ref::<BooleanArray>()
2619 .expect("boolean overlay zip type")
2620 .clone(),
2621 )
2622 }
2623
2624 pub(crate) fn select_text(
2625 &self,
2626 range: core::ops::Range<usize>,
2627 base: &StringArray,
2628 ) -> ArrayRef {
2629 if let Some(fragment) = self.user.full_cover_dense_fragment(range.clone()) {
2630 record_overlay_select_stats(|stats| stats.direct_dense_slices += 1);
2631 return Self::dense_text(fragment, range);
2632 }
2633 if let Some(fragment) = self.user.full_cover_run_fragment(range.clone()) {
2634 record_overlay_select_stats(|stats| stats.direct_run_materializations += 1);
2635 return Self::run_text(fragment, range);
2636 }
2637 if !self.user.has_any_in_range(range.clone()) {
2638 if let Some(fragment) = self.computed.full_cover_dense_fragment(range.clone()) {
2639 record_overlay_select_stats(|stats| stats.direct_dense_slices += 1);
2640 return Self::dense_text(fragment, range);
2641 }
2642 if let Some(fragment) = self.computed.full_cover_run_fragment(range.clone()) {
2643 record_overlay_select_stats(|stats| stats.direct_run_materializations += 1);
2644 return Self::run_text(fragment, range);
2645 }
2646 }
2647
2648 if !self.has_any_in_range(range.clone()) {
2649 return Arc::new(base.clone()) as ArrayRef;
2650 }
2651
2652 record_overlay_select_stats(|stats| stats.partial_overlay_builds += 1);
2653 let len = range.end.saturating_sub(range.start);
2654 let mut slots = OverlaySlots::<String>::new(len);
2655 Self::apply_text_layer(self.computed, range.clone(), &mut slots);
2656 Self::apply_text_layer(self.user, range.clone(), &mut slots);
2657 if !slots.any_present() {
2658 return Arc::new(base.clone()) as ArrayRef;
2659 }
2660
2661 let mut mask_b = BooleanBuilder::with_capacity(len);
2662 let mut values_b = StringBuilder::with_capacity(len, len.saturating_mul(8));
2663 for idx in 0..len {
2664 mask_b.append_value(slots.present[idx]);
2665 match &slots.values[idx] {
2666 Some(value) => values_b.append_value(value),
2667 None => values_b.append_null(),
2668 }
2669 }
2670 record_overlay_select_stats(|stats| stats.zip_select_calls += 1);
2671 let mask = mask_b.finish();
2672 let values = values_b.finish();
2673 crate::compute_prelude::zip_select(&mask, &values, base).expect("zip text overlay")
2674 }
2675
2676 pub(crate) fn select_errors(
2677 &self,
2678 range: core::ops::Range<usize>,
2679 base: &UInt8Array,
2680 ) -> Arc<UInt8Array> {
2681 if let Some(fragment) = self.user.full_cover_dense_fragment(range.clone()) {
2682 record_overlay_select_stats(|stats| stats.direct_dense_slices += 1);
2683 return Self::dense_errors(fragment, range);
2684 }
2685 if let Some(fragment) = self.user.full_cover_run_fragment(range.clone()) {
2686 record_overlay_select_stats(|stats| stats.direct_run_materializations += 1);
2687 return Self::run_errors(fragment, range);
2688 }
2689 if !self.user.has_any_in_range(range.clone()) {
2690 if let Some(fragment) = self.computed.full_cover_dense_fragment(range.clone()) {
2691 record_overlay_select_stats(|stats| stats.direct_dense_slices += 1);
2692 return Self::dense_errors(fragment, range);
2693 }
2694 if let Some(fragment) = self.computed.full_cover_run_fragment(range.clone()) {
2695 record_overlay_select_stats(|stats| stats.direct_run_materializations += 1);
2696 return Self::run_errors(fragment, range);
2697 }
2698 }
2699
2700 if !self.has_any_in_range(range.clone()) {
2701 return Arc::new(base.clone());
2702 }
2703
2704 record_overlay_select_stats(|stats| stats.partial_overlay_builds += 1);
2705 let len = range.end.saturating_sub(range.start);
2706 let mut slots = OverlaySlots::<u8>::new(len);
2707 Self::apply_error_layer(self.computed, range.clone(), &mut slots);
2708 Self::apply_error_layer(self.user, range.clone(), &mut slots);
2709 if !slots.any_present() {
2710 return Arc::new(base.clone());
2711 }
2712
2713 let mut mask_b = BooleanBuilder::with_capacity(len);
2714 let mut values_b = UInt8Builder::with_capacity(len);
2715 for idx in 0..len {
2716 mask_b.append_value(slots.present[idx]);
2717 match slots.values[idx] {
2718 Some(value) => values_b.append_value(value),
2719 None => values_b.append_null(),
2720 }
2721 }
2722 record_overlay_select_stats(|stats| stats.zip_select_calls += 1);
2723 let mask = mask_b.finish();
2724 let values = values_b.finish();
2725 let zipped =
2726 crate::compute_prelude::zip_select(&mask, &values, base).expect("zip error overlay");
2727 Arc::new(
2728 zipped
2729 .as_any()
2730 .downcast_ref::<UInt8Array>()
2731 .expect("error overlay zip type")
2732 .clone(),
2733 )
2734 }
2735
2736 pub(crate) fn select_type_tags(
2737 &self,
2738 range: core::ops::Range<usize>,
2739 base: &UInt8Array,
2740 ) -> Arc<UInt8Array> {
2741 if let Some(fragment) = self.user.full_cover_dense_fragment(range.clone()) {
2742 record_overlay_select_stats(|stats| stats.direct_dense_slices += 1);
2743 return Self::dense_type_tags(fragment, range);
2744 }
2745 if let Some(fragment) = self.user.full_cover_run_fragment(range.clone()) {
2746 record_overlay_select_stats(|stats| stats.direct_run_materializations += 1);
2747 return Self::run_type_tags(fragment, range);
2748 }
2749 if !self.user.has_any_in_range(range.clone()) {
2750 if let Some(fragment) = self.computed.full_cover_dense_fragment(range.clone()) {
2751 record_overlay_select_stats(|stats| stats.direct_dense_slices += 1);
2752 return Self::dense_type_tags(fragment, range);
2753 }
2754 if let Some(fragment) = self.computed.full_cover_run_fragment(range.clone()) {
2755 record_overlay_select_stats(|stats| stats.direct_run_materializations += 1);
2756 return Self::run_type_tags(fragment, range);
2757 }
2758 }
2759
2760 if !self.has_any_in_range(range.clone()) {
2761 return Arc::new(base.clone());
2762 }
2763
2764 record_overlay_select_stats(|stats| stats.partial_overlay_builds += 1);
2765 let len = range.end.saturating_sub(range.start);
2766 let mut slots = OverlaySlots::<u8>::new(len);
2767 Self::apply_type_tag_layer(self.computed, range.clone(), &mut slots);
2768 Self::apply_type_tag_layer(self.user, range.clone(), &mut slots);
2769 if !slots.any_present() {
2770 return Arc::new(base.clone());
2771 }
2772
2773 let mut mask_b = BooleanBuilder::with_capacity(len);
2774 let mut values_b = UInt8Builder::with_capacity(len);
2775 for idx in 0..len {
2776 mask_b.append_value(slots.present[idx]);
2777 match slots.values[idx] {
2778 Some(value) => values_b.append_value(value),
2779 None => values_b.append_null(),
2780 }
2781 }
2782 record_overlay_select_stats(|stats| stats.zip_select_calls += 1);
2783 let mask = mask_b.finish();
2784 let values = values_b.finish();
2785 let zipped =
2786 crate::compute_prelude::zip_select(&mask, &values, base).expect("zip type-tag overlay");
2787 Arc::new(
2788 zipped
2789 .as_any()
2790 .downcast_ref::<UInt8Array>()
2791 .expect("type-tag overlay zip type")
2792 .clone(),
2793 )
2794 }
2795
2796 pub(crate) fn select_lowered_text(
2797 &self,
2798 range: core::ops::Range<usize>,
2799 base: &StringArray,
2800 ) -> Arc<StringArray> {
2801 if let Some(fragment) = self.user.full_cover_dense_fragment(range.clone()) {
2802 record_overlay_select_stats(|stats| stats.direct_dense_slices += 1);
2803 return Self::dense_lowered_text(fragment, range);
2804 }
2805 if let Some(fragment) = self.user.full_cover_run_fragment(range.clone()) {
2806 record_overlay_select_stats(|stats| stats.direct_run_materializations += 1);
2807 return Self::run_lowered_text(fragment, range);
2808 }
2809 if !self.user.has_any_in_range(range.clone()) {
2810 if let Some(fragment) = self.computed.full_cover_dense_fragment(range.clone()) {
2811 record_overlay_select_stats(|stats| stats.direct_dense_slices += 1);
2812 return Self::dense_lowered_text(fragment, range);
2813 }
2814 if let Some(fragment) = self.computed.full_cover_run_fragment(range.clone()) {
2815 record_overlay_select_stats(|stats| stats.direct_run_materializations += 1);
2816 return Self::run_lowered_text(fragment, range);
2817 }
2818 }
2819
2820 if !self.has_any_in_range(range.clone()) {
2821 return Arc::new(base.clone());
2822 }
2823 if self.user.fragments.is_empty() && self.computed.fragments.is_empty() {
2824 return self.select_lowered_text_point_scalar(range, base);
2825 }
2826
2827 record_overlay_select_stats(|stats| stats.partial_overlay_builds += 1);
2828 let len = range.end.saturating_sub(range.start);
2829 let mut slots = OverlaySlots::<String>::new(len);
2830 Self::apply_lowered_text_layer(self.computed, range.clone(), &mut slots);
2831 Self::apply_lowered_text_layer(self.user, range.clone(), &mut slots);
2832 if !slots.any_present() {
2833 return Arc::new(base.clone());
2834 }
2835
2836 let mut mask_b = BooleanBuilder::with_capacity(len);
2837 let mut values_b = StringBuilder::with_capacity(len, len.saturating_mul(8));
2838 for idx in 0..len {
2839 mask_b.append_value(slots.present[idx]);
2840 match &slots.values[idx] {
2841 Some(value) => values_b.append_value(value),
2842 None => values_b.append_null(),
2843 }
2844 }
2845 record_overlay_select_stats(|stats| stats.zip_select_calls += 1);
2846 let mask = mask_b.finish();
2847 let values = values_b.finish();
2848 let zipped = crate::compute_prelude::zip_select(&mask, &values, base)
2849 .expect("zip lowered text overlay");
2850 Arc::new(
2851 zipped
2852 .as_any()
2853 .downcast_ref::<StringArray>()
2854 .expect("lowered text overlay zip type")
2855 .clone(),
2856 )
2857 }
2858
2859 fn select_lowered_text_point_scalar(
2860 &self,
2861 range: core::ops::Range<usize>,
2862 base: &StringArray,
2863 ) -> Arc<StringArray> {
2864 let len = range.end.saturating_sub(range.start);
2865 let mut mask_b = BooleanBuilder::with_capacity(len);
2866 let mut values_b = StringBuilder::with_capacity(len, len.saturating_mul(8));
2867 record_overlay_select_stats(|stats| stats.row_scalar_fallbacks += len);
2868 for off in range {
2869 if let Some(value) = self.get_scalar(off) {
2870 mask_b.append_value(true);
2871 if let Some(s) = value.lowered_text_value() {
2872 values_b.append_value(&s);
2873 } else {
2874 values_b.append_null();
2875 }
2876 record_overlay_select_stats(|stats| stats.point_entries_applied += 1);
2877 } else {
2878 mask_b.append_value(false);
2879 values_b.append_null();
2880 }
2881 }
2882 record_overlay_select_stats(|stats| stats.zip_select_calls += 1);
2883 let mask = mask_b.finish();
2884 let values = values_b.finish();
2885 let zipped = crate::compute_prelude::zip_select(&mask, &values, base)
2886 .expect("zip lowered text overlay");
2887 Arc::new(
2888 zipped
2889 .as_any()
2890 .downcast_ref::<StringArray>()
2891 .expect("lowered text overlay zip type")
2892 .clone(),
2893 )
2894 }
2895
2896 fn dense_numbers(
2897 fragment: &OverlayFragment,
2898 range: core::ops::Range<usize>,
2899 ) -> Arc<Float64Array> {
2900 let (rel_start, len, payload) = Self::dense_payload_window(fragment, range);
2901 Self::payload_numbers_slice(payload, rel_start, len)
2902 }
2903
2904 fn dense_booleans(
2905 fragment: &OverlayFragment,
2906 range: core::ops::Range<usize>,
2907 ) -> Arc<BooleanArray> {
2908 let (rel_start, len, payload) = Self::dense_payload_window(fragment, range);
2909 Self::payload_booleans_slice(payload, rel_start, len)
2910 }
2911
2912 fn dense_text(fragment: &OverlayFragment, range: core::ops::Range<usize>) -> ArrayRef {
2913 let (rel_start, len, payload) = Self::dense_payload_window(fragment, range);
2914 Self::payload_text_slice(payload, rel_start, len)
2915 }
2916
2917 fn dense_errors(fragment: &OverlayFragment, range: core::ops::Range<usize>) -> Arc<UInt8Array> {
2918 let (rel_start, len, payload) = Self::dense_payload_window(fragment, range);
2919 Self::payload_errors_slice(payload, rel_start, len)
2920 }
2921
2922 fn dense_type_tags(
2923 fragment: &OverlayFragment,
2924 range: core::ops::Range<usize>,
2925 ) -> Arc<UInt8Array> {
2926 let (rel_start, len, payload) = Self::dense_payload_window(fragment, range);
2927 Self::payload_type_tags_slice(payload, rel_start, len)
2928 }
2929
2930 fn dense_lowered_text(
2931 fragment: &OverlayFragment,
2932 range: core::ops::Range<usize>,
2933 ) -> Arc<StringArray> {
2934 let (rel_start, len, payload) = Self::dense_payload_window(fragment, range);
2935 Self::payload_lowered_text_materialize(payload, rel_start, len)
2936 }
2937
2938 fn dense_payload_window(
2939 fragment: &OverlayFragment,
2940 range: core::ops::Range<usize>,
2941 ) -> (usize, usize, &OverlayFragmentPayload) {
2942 let OverlayFragment::DenseRange { start, payload, .. } = fragment else {
2943 unreachable!("dense payload window requires DenseRange")
2944 };
2945 let rel_start = range.start.saturating_sub(*start as usize);
2946 (rel_start, range.end.saturating_sub(range.start), payload)
2947 }
2948
2949 fn run_numbers(
2950 fragment: &OverlayFragment,
2951 range: core::ops::Range<usize>,
2952 ) -> Arc<Float64Array> {
2953 let mut b = Float64Builder::with_capacity(range.end.saturating_sub(range.start));
2954 Self::for_each_run_payload_index(fragment, range, |payload, run_idx, repeat| {
2955 if let Some(value) = payload.number_at(run_idx) {
2956 for _ in 0..repeat {
2957 b.append_value(value);
2958 }
2959 } else {
2960 for _ in 0..repeat {
2961 b.append_null();
2962 }
2963 }
2964 });
2965 Arc::new(b.finish())
2966 }
2967
2968 fn run_booleans(
2969 fragment: &OverlayFragment,
2970 range: core::ops::Range<usize>,
2971 ) -> Arc<BooleanArray> {
2972 let mut b = BooleanBuilder::with_capacity(range.end.saturating_sub(range.start));
2973 Self::for_each_run_payload_index(fragment, range, |payload, run_idx, repeat| {
2974 if let Some(value) = payload.boolean_at(run_idx) {
2975 for _ in 0..repeat {
2976 b.append_value(value);
2977 }
2978 } else {
2979 for _ in 0..repeat {
2980 b.append_null();
2981 }
2982 }
2983 });
2984 Arc::new(b.finish())
2985 }
2986
2987 fn run_text(fragment: &OverlayFragment, range: core::ops::Range<usize>) -> ArrayRef {
2988 let mut b = StringBuilder::with_capacity(
2989 range.end.saturating_sub(range.start),
2990 range.end.saturating_sub(range.start).saturating_mul(8),
2991 );
2992 Self::for_each_run_payload_index(fragment, range, |payload, run_idx, repeat| {
2993 if let Some(value) = payload.text_at(run_idx) {
2994 for _ in 0..repeat {
2995 b.append_value(value);
2996 }
2997 } else {
2998 for _ in 0..repeat {
2999 b.append_null();
3000 }
3001 }
3002 });
3003 Arc::new(b.finish()) as ArrayRef
3004 }
3005
3006 fn run_errors(fragment: &OverlayFragment, range: core::ops::Range<usize>) -> Arc<UInt8Array> {
3007 let mut b = UInt8Builder::with_capacity(range.end.saturating_sub(range.start));
3008 Self::for_each_run_payload_index(fragment, range, |payload, run_idx, repeat| {
3009 if let Some(value) = payload.error_at(run_idx) {
3010 for _ in 0..repeat {
3011 b.append_value(value);
3012 }
3013 } else {
3014 for _ in 0..repeat {
3015 b.append_null();
3016 }
3017 }
3018 });
3019 Arc::new(b.finish())
3020 }
3021
3022 fn run_type_tags(
3023 fragment: &OverlayFragment,
3024 range: core::ops::Range<usize>,
3025 ) -> Arc<UInt8Array> {
3026 let mut b = UInt8Builder::with_capacity(range.end.saturating_sub(range.start));
3027 Self::for_each_run_payload_index(fragment, range, |payload, run_idx, repeat| {
3028 let tag = payload.type_tag_at(run_idx).unwrap_or(TypeTag::Empty) as u8;
3029 for _ in 0..repeat {
3030 b.append_value(tag);
3031 }
3032 });
3033 Arc::new(b.finish())
3034 }
3035
3036 fn run_lowered_text(
3037 fragment: &OverlayFragment,
3038 range: core::ops::Range<usize>,
3039 ) -> Arc<StringArray> {
3040 let mut b = StringBuilder::with_capacity(
3041 range.end.saturating_sub(range.start),
3042 range.end.saturating_sub(range.start).saturating_mul(8),
3043 );
3044 Self::for_each_run_payload_index(fragment, range, |payload, run_idx, repeat| {
3045 let value = Self::payload_lowered_text_at(payload, run_idx);
3046 if let Some(value) = value {
3047 for _ in 0..repeat {
3048 b.append_value(&value);
3049 }
3050 } else {
3051 for _ in 0..repeat {
3052 b.append_null();
3053 }
3054 }
3055 });
3056 Arc::new(b.finish())
3057 }
3058
3059 fn payload_numbers_slice(
3060 payload: &OverlayFragmentPayload,
3061 start: usize,
3062 len: usize,
3063 ) -> Arc<Float64Array> {
3064 if let Some(array) = &payload.numbers {
3065 let sliced = array.slice(start, len);
3066 Arc::new(
3067 sliced
3068 .as_any()
3069 .downcast_ref::<Float64Array>()
3070 .unwrap()
3071 .clone(),
3072 )
3073 } else {
3074 Self::null_numbers(len)
3075 }
3076 }
3077
3078 fn payload_booleans_slice(
3079 payload: &OverlayFragmentPayload,
3080 start: usize,
3081 len: usize,
3082 ) -> Arc<BooleanArray> {
3083 if let Some(array) = &payload.booleans {
3084 let sliced = array.slice(start, len);
3085 Arc::new(
3086 sliced
3087 .as_any()
3088 .downcast_ref::<BooleanArray>()
3089 .unwrap()
3090 .clone(),
3091 )
3092 } else {
3093 Self::null_booleans(len)
3094 }
3095 }
3096
3097 fn payload_text_slice(payload: &OverlayFragmentPayload, start: usize, len: usize) -> ArrayRef {
3098 if let Some(array) = &payload.text {
3099 array.slice(start, len)
3100 } else {
3101 new_null_array(&DataType::Utf8, len)
3102 }
3103 }
3104
3105 fn payload_errors_slice(
3106 payload: &OverlayFragmentPayload,
3107 start: usize,
3108 len: usize,
3109 ) -> Arc<UInt8Array> {
3110 if let Some(array) = &payload.errors {
3111 let sliced = array.slice(start, len);
3112 Arc::new(
3113 sliced
3114 .as_any()
3115 .downcast_ref::<UInt8Array>()
3116 .unwrap()
3117 .clone(),
3118 )
3119 } else {
3120 Self::null_errors(len)
3121 }
3122 }
3123
3124 fn payload_type_tags_slice(
3125 payload: &OverlayFragmentPayload,
3126 start: usize,
3127 len: usize,
3128 ) -> Arc<UInt8Array> {
3129 let sliced = payload.type_tags.slice(start, len);
3130 Arc::new(
3131 sliced
3132 .as_any()
3133 .downcast_ref::<UInt8Array>()
3134 .unwrap()
3135 .clone(),
3136 )
3137 }
3138
3139 fn payload_lowered_text_materialize(
3140 payload: &OverlayFragmentPayload,
3141 start: usize,
3142 len: usize,
3143 ) -> Arc<StringArray> {
3144 let mut b = StringBuilder::with_capacity(len, len.saturating_mul(8));
3145 for idx in start..start.saturating_add(len) {
3146 if let Some(value) = Self::payload_lowered_text_at(payload, idx) {
3147 b.append_value(&value);
3148 } else {
3149 b.append_null();
3150 }
3151 }
3152 Arc::new(b.finish())
3153 }
3154
3155 fn payload_lowered_text_at(payload: &OverlayFragmentPayload, idx: usize) -> Option<String> {
3156 match payload.type_tag_at(idx)? {
3157 TypeTag::Text => payload.text_at(idx).map(|value| value.to_lowercase()),
3158 TypeTag::Number | TypeTag::DateTime | TypeTag::Duration => {
3159 payload.number_at(idx).map(|value| value.to_string())
3160 }
3161 TypeTag::Boolean => payload
3162 .boolean_at(idx)
3163 .map(|value| if value { "true" } else { "false" }.to_string()),
3164 TypeTag::Empty | TypeTag::Error | TypeTag::Pending => None,
3165 }
3166 }
3167
3168 fn null_numbers(len: usize) -> Arc<Float64Array> {
3169 let arr = new_null_array(&DataType::Float64, len);
3170 Arc::new(arr.as_any().downcast_ref::<Float64Array>().unwrap().clone())
3171 }
3172
3173 fn null_booleans(len: usize) -> Arc<BooleanArray> {
3174 let arr = new_null_array(&DataType::Boolean, len);
3175 Arc::new(arr.as_any().downcast_ref::<BooleanArray>().unwrap().clone())
3176 }
3177
3178 fn null_errors(len: usize) -> Arc<UInt8Array> {
3179 let arr = new_null_array(&DataType::UInt8, len);
3180 Arc::new(arr.as_any().downcast_ref::<UInt8Array>().unwrap().clone())
3181 }
3182
3183 fn apply_number_layer(
3184 layer: &Overlay,
3185 range: core::ops::Range<usize>,
3186 slots: &mut OverlaySlots<f64>,
3187 ) {
3188 Self::apply_fragment_layer(layer, range.clone(), slots, |payload, idx| {
3189 payload.number_at(idx)
3190 });
3191 for (off, value) in layer.iter_points() {
3192 if range.contains(off) {
3193 slots.set(*off - range.start, value.numeric_lane_value());
3194 record_overlay_select_stats(|stats| stats.point_entries_applied += 1);
3195 }
3196 }
3197 }
3198
3199 fn apply_boolean_layer(
3200 layer: &Overlay,
3201 range: core::ops::Range<usize>,
3202 slots: &mut OverlaySlots<bool>,
3203 ) {
3204 Self::apply_fragment_layer(layer, range.clone(), slots, |payload, idx| {
3205 payload.boolean_at(idx)
3206 });
3207 for (off, value) in layer.iter_points() {
3208 if range.contains(off) {
3209 slots.set(*off - range.start, value.boolean_lane_value());
3210 record_overlay_select_stats(|stats| stats.point_entries_applied += 1);
3211 }
3212 }
3213 }
3214
3215 fn apply_text_layer(
3216 layer: &Overlay,
3217 range: core::ops::Range<usize>,
3218 slots: &mut OverlaySlots<String>,
3219 ) {
3220 Self::apply_fragment_layer(layer, range.clone(), slots, |payload, idx| {
3221 payload.text_at(idx).map(ToString::to_string)
3222 });
3223 for (off, value) in layer.iter_points() {
3224 if range.contains(off) {
3225 slots.set(
3226 *off - range.start,
3227 value.text_lane_value().map(ToString::to_string),
3228 );
3229 record_overlay_select_stats(|stats| stats.point_entries_applied += 1);
3230 }
3231 }
3232 }
3233
3234 fn apply_error_layer(
3235 layer: &Overlay,
3236 range: core::ops::Range<usize>,
3237 slots: &mut OverlaySlots<u8>,
3238 ) {
3239 Self::apply_fragment_layer(layer, range.clone(), slots, |payload, idx| {
3240 payload.error_at(idx)
3241 });
3242 for (off, value) in layer.iter_points() {
3243 if range.contains(off) {
3244 slots.set(*off - range.start, value.error_lane_value());
3245 record_overlay_select_stats(|stats| stats.point_entries_applied += 1);
3246 }
3247 }
3248 }
3249
3250 fn apply_type_tag_layer(
3251 layer: &Overlay,
3252 range: core::ops::Range<usize>,
3253 slots: &mut OverlaySlots<u8>,
3254 ) {
3255 Self::apply_fragment_layer(layer, range.clone(), slots, |payload, idx| {
3256 payload.type_tag_at(idx).map(|tag| tag as u8)
3257 });
3258 for (off, value) in layer.iter_points() {
3259 if range.contains(off) {
3260 slots.set(*off - range.start, Some(value.type_tag() as u8));
3261 record_overlay_select_stats(|stats| stats.point_entries_applied += 1);
3262 }
3263 }
3264 }
3265
3266 fn apply_lowered_text_layer(
3267 layer: &Overlay,
3268 range: core::ops::Range<usize>,
3269 slots: &mut OverlaySlots<String>,
3270 ) {
3271 Self::apply_fragment_layer(layer, range.clone(), slots, Self::payload_lowered_text_at);
3272 for (off, value) in layer.iter_points() {
3273 if range.contains(off) {
3274 slots.set(*off - range.start, value.lowered_text_value());
3275 record_overlay_select_stats(|stats| stats.point_entries_applied += 1);
3276 }
3277 }
3278 }
3279
3280 fn apply_fragment_layer<T>(
3281 layer: &Overlay,
3282 range: core::ops::Range<usize>,
3283 slots: &mut OverlaySlots<T>,
3284 mut value_at: impl FnMut(&OverlayFragmentPayload, usize) -> Option<T>,
3285 ) {
3286 for fragment in &layer.fragments {
3287 if !fragment.has_any_in_range(range.clone()) {
3288 continue;
3289 }
3290 Self::record_fragment_intersection(fragment);
3291 Self::for_each_fragment_payload_index(
3292 fragment,
3293 range.clone(),
3294 |out_idx, payload, payload_idx| {
3295 slots.set(out_idx, value_at(payload, payload_idx));
3296 },
3297 );
3298 }
3299 }
3300
3301 fn record_fragment_intersection(fragment: &OverlayFragment) {
3302 let shape = match fragment {
3303 OverlayFragment::SparseOffsets { .. } => OverlayFragmentShape::Sparse,
3304 OverlayFragment::DenseRange { .. } => OverlayFragmentShape::Dense,
3305 OverlayFragment::RunRange { .. } => OverlayFragmentShape::Run,
3306 };
3307 record_overlay_select_stats(|stats| {
3308 stats.fragment_intersections += 1;
3309 match shape {
3310 OverlayFragmentShape::Sparse => stats.partial_sparse_intersections += 1,
3311 OverlayFragmentShape::Dense => stats.partial_dense_intersections += 1,
3312 OverlayFragmentShape::Run => stats.partial_run_intersections += 1,
3313 }
3314 });
3315 }
3316
3317 fn for_each_fragment_payload_index(
3318 fragment: &OverlayFragment,
3319 range: core::ops::Range<usize>,
3320 mut f: impl FnMut(usize, &OverlayFragmentPayload, usize),
3321 ) {
3322 if range.is_empty() {
3323 return;
3324 }
3325 match fragment {
3326 OverlayFragment::SparseOffsets { offsets, payload } => {
3327 let start = u32::try_from(range.start).unwrap_or(u32::MAX);
3328 let lo = offsets.partition_point(|off| *off < start);
3329 let hi = offsets.partition_point(|off| (*off as usize) < range.end);
3330 for (idx, off) in offsets.iter().enumerate().take(hi).skip(lo) {
3331 let out_idx = (*off as usize).saturating_sub(range.start);
3332 f(out_idx, payload, idx);
3333 }
3334 }
3335 OverlayFragment::DenseRange {
3336 start,
3337 len,
3338 payload,
3339 } => {
3340 let frag_start = *start as usize;
3341 let frag_end = frag_start.saturating_add(*len as usize);
3342 let inter_start = frag_start.max(range.start);
3343 let inter_end = frag_end.min(range.end);
3344 if inter_start >= inter_end {
3345 return;
3346 }
3347 for abs in inter_start..inter_end {
3348 f(abs - range.start, payload, abs - frag_start);
3349 }
3350 }
3351 OverlayFragment::RunRange {
3352 start,
3353 len,
3354 run_ends,
3355 payload,
3356 } => {
3357 let frag_start = *start as usize;
3358 let frag_end = frag_start.saturating_add(*len as usize);
3359 let inter_start = frag_start.max(range.start);
3360 let inter_end = frag_end.min(range.end);
3361 if inter_start >= inter_end {
3362 return;
3363 }
3364 let mut prev_end = 0usize;
3365 for (run_idx, run_end) in run_ends.iter().enumerate() {
3366 let run_start_abs = frag_start.saturating_add(prev_end);
3367 let run_end_abs = frag_start.saturating_add(*run_end as usize);
3368 let start_abs = run_start_abs.max(inter_start);
3369 let end_abs = run_end_abs.min(inter_end);
3370 if start_abs < end_abs {
3371 for abs in start_abs..end_abs {
3372 f(abs - range.start, payload, run_idx);
3373 }
3374 }
3375 prev_end = *run_end as usize;
3376 if run_end_abs >= inter_end {
3377 break;
3378 }
3379 }
3380 }
3381 }
3382 }
3383
3384 fn for_each_run_payload_index(
3385 fragment: &OverlayFragment,
3386 range: core::ops::Range<usize>,
3387 mut f: impl FnMut(&OverlayFragmentPayload, usize, usize),
3388 ) {
3389 let OverlayFragment::RunRange {
3390 start,
3391 len,
3392 run_ends,
3393 payload,
3394 } = fragment
3395 else {
3396 unreachable!("run payload iteration requires RunRange")
3397 };
3398 let frag_start = *start as usize;
3399 let frag_end = frag_start.saturating_add(*len as usize);
3400 let inter_start = frag_start.max(range.start);
3401 let inter_end = frag_end.min(range.end);
3402 if inter_start >= inter_end {
3403 return;
3404 }
3405 let mut prev_end = 0usize;
3406 for (run_idx, run_end) in run_ends.iter().enumerate() {
3407 let run_start_abs = frag_start.saturating_add(prev_end);
3408 let run_end_abs = frag_start.saturating_add(*run_end as usize);
3409 let start_abs = run_start_abs.max(inter_start);
3410 let end_abs = run_end_abs.min(inter_end);
3411 if start_abs < end_abs {
3412 f(payload, run_idx, end_abs - start_abs);
3413 }
3414 prev_end = *run_end as usize;
3415 if run_end_abs >= inter_end {
3416 break;
3417 }
3418 }
3419 }
3420}
3421
3422impl OverlayFragmentPayload {
3423 #[inline]
3424 fn type_tag_at(&self, idx: usize) -> Option<TypeTag> {
3425 if idx >= self.type_tags.len() || self.type_tags.is_null(idx) {
3426 return None;
3427 }
3428 Some(TypeTag::from_u8(self.type_tags.value(idx)))
3429 }
3430}
3431
3432impl Overlay {
3433 fn full_cover_dense_fragment(
3434 &self,
3435 range: core::ops::Range<usize>,
3436 ) -> Option<&OverlayFragment> {
3437 self.full_cover_single_fragment(range, OverlayFragmentShape::Dense)
3438 }
3439
3440 fn full_cover_run_fragment(&self, range: core::ops::Range<usize>) -> Option<&OverlayFragment> {
3441 self.full_cover_single_fragment(range, OverlayFragmentShape::Run)
3442 }
3443
3444 fn full_cover_single_fragment(
3445 &self,
3446 range: core::ops::Range<usize>,
3447 shape: OverlayFragmentShape,
3448 ) -> Option<&OverlayFragment> {
3449 if range.is_empty() || self.points.keys().any(|off| range.contains(off)) {
3450 return None;
3451 }
3452 let mut found = None;
3453 for fragment in &self.fragments {
3454 if !fragment.has_any_in_range(range.clone()) {
3455 continue;
3456 }
3457 let shape_matches = matches!(
3458 (shape, fragment),
3459 (
3460 OverlayFragmentShape::Dense,
3461 OverlayFragment::DenseRange { .. }
3462 ) | (OverlayFragmentShape::Run, OverlayFragment::RunRange { .. })
3463 );
3464 let covers = fragment
3465 .interval_coverage()
3466 .is_some_and(|own| own.start <= range.start && range.end <= own.end);
3467 if shape_matches && covers && found.is_none() {
3468 found = Some(fragment);
3469 } else {
3470 return None;
3471 }
3472 }
3473 found
3474 }
3475}
3476fn append_overlay_value_to_lane_builders(
3477 ov: &OverlayValue,
3478 tag_b: &mut UInt8Builder,
3479 nb: &mut Float64Builder,
3480 bb: &mut BooleanBuilder,
3481 sb: &mut StringBuilder,
3482 eb: &mut UInt8Builder,
3483 non_num: &mut usize,
3484 non_bool: &mut usize,
3485 non_text: &mut usize,
3486 non_err: &mut usize,
3487) {
3488 match ov {
3489 OverlayValue::Empty => {
3490 tag_b.append_value(TypeTag::Empty as u8);
3491 nb.append_null();
3492 bb.append_null();
3493 sb.append_null();
3494 eb.append_null();
3495 }
3496 OverlayValue::Number(n) => {
3497 tag_b.append_value(TypeTag::Number as u8);
3498 nb.append_value(*n);
3499 *non_num += 1;
3500 bb.append_null();
3501 sb.append_null();
3502 eb.append_null();
3503 }
3504 OverlayValue::DateTime(serial) => {
3505 tag_b.append_value(TypeTag::DateTime as u8);
3506 nb.append_value(*serial);
3507 *non_num += 1;
3508 bb.append_null();
3509 sb.append_null();
3510 eb.append_null();
3511 }
3512 OverlayValue::Duration(serial) => {
3513 tag_b.append_value(TypeTag::Duration as u8);
3514 nb.append_value(*serial);
3515 *non_num += 1;
3516 bb.append_null();
3517 sb.append_null();
3518 eb.append_null();
3519 }
3520 OverlayValue::Boolean(b) => {
3521 tag_b.append_value(TypeTag::Boolean as u8);
3522 nb.append_null();
3523 bb.append_value(*b);
3524 *non_bool += 1;
3525 sb.append_null();
3526 eb.append_null();
3527 }
3528 OverlayValue::Text(s) => {
3529 tag_b.append_value(TypeTag::Text as u8);
3530 nb.append_null();
3531 bb.append_null();
3532 sb.append_value(s);
3533 *non_text += 1;
3534 eb.append_null();
3535 }
3536 OverlayValue::Error(code) => {
3537 tag_b.append_value(TypeTag::Error as u8);
3538 nb.append_null();
3539 bb.append_null();
3540 sb.append_null();
3541 eb.append_value(*code);
3542 *non_err += 1;
3543 }
3544 OverlayValue::Pending => {
3545 tag_b.append_value(TypeTag::Pending as u8);
3546 nb.append_null();
3547 bb.append_null();
3548 sb.append_null();
3549 eb.append_null();
3550 }
3551 }
3552}
3553
3554impl ArrowSheet {
3555 pub fn new_sparse(sheet_name: &str, ncols: usize, nrows: usize, chunk_rows: usize) -> Self {
3561 Self::new_sparse_with_date_system(
3562 sheet_name,
3563 ncols,
3564 nrows,
3565 chunk_rows,
3566 crate::engine::DateSystem::Excel1900,
3567 )
3568 }
3569
3570 pub fn new_sparse_with_date_system(
3572 sheet_name: &str,
3573 ncols: usize,
3574 nrows: usize,
3575 chunk_rows: usize,
3576 date_system: crate::engine::DateSystem,
3577 ) -> Self {
3578 let chunk_rows = chunk_rows.max(1);
3579 let columns = (0..ncols)
3580 .map(|idx| ArrowColumn {
3581 chunks: Vec::new(),
3582 sparse_chunks: FxHashMap::default(),
3583 index: idx as u32,
3584 })
3585 .collect();
3586 let mut sheet = Self {
3587 name: Arc::from(sheet_name.to_string()),
3588 date_system,
3589 columns,
3590 nrows: 0,
3591 chunk_starts: Vec::new(),
3592 chunk_rows,
3593 };
3594 sheet.ensure_row_capacity(nrows);
3595 sheet
3596 }
3597
3598 pub fn set_sparse_overlay_value(
3602 &mut self,
3603 abs_row: usize,
3604 abs_col: usize,
3605 value: OverlayValue,
3606 ) -> isize {
3607 if abs_col >= self.columns.len() {
3608 let start = self.columns.len();
3609 self.columns
3610 .extend((start..=abs_col).map(|idx| ArrowColumn {
3611 chunks: Vec::new(),
3612 sparse_chunks: FxHashMap::default(),
3613 index: idx as u32,
3614 }));
3615 }
3616 if abs_row >= self.nrows as usize {
3617 self.ensure_row_capacity(abs_row + 1);
3618 }
3619 let Some((ch_idx, in_off)) = self.chunk_of_row(abs_row) else {
3620 return 0;
3621 };
3622 let Some(ch) = self.ensure_column_chunk_mut(abs_col, ch_idx) else {
3623 return 0;
3624 };
3625 ch.overlay.set(in_off, value)
3626 }
3627
3628 pub fn set_sparse_overlay_format(
3629 &mut self,
3630 abs_row: usize,
3631 abs_col: usize,
3632 format: Option<FormatId>,
3633 ) {
3634 if abs_row >= self.nrows as usize || abs_col >= self.columns.len() {
3635 return;
3636 }
3637 let Some((ch_idx, in_off)) = self.chunk_of_row(abs_row) else {
3638 return;
3639 };
3640 if let Some(ch) = self.ensure_column_chunk_mut(abs_col, ch_idx) {
3641 ch.overlay.set_format(in_off, format);
3642 }
3643 }
3644
3645 pub(crate) fn clear_format(&mut self, abs_row: usize, abs_col: usize) {
3647 if abs_row >= self.nrows as usize || abs_col >= self.columns.len() {
3648 return;
3649 }
3650 let Some((ch_idx, in_off)) = self.chunk_of_row(abs_row) else {
3651 return;
3652 };
3653 let Some(ch) = self.ensure_column_chunk_mut(abs_col, ch_idx) else {
3654 return;
3655 };
3656 ch.overlay.set_format(in_off, None);
3657 ch.computed_overlay.set_format(in_off, None);
3658 if let Some(runs) = &ch.format {
3659 let mut ids = runs.to_ids(ch.len());
3660 ids[in_off] = FormatId::GENERAL.0;
3661 ch.format = FormatRuns::from_ids(&ids);
3662 }
3663 }
3664
3665 pub fn shape(&self) -> Vec<ColumnShape> {
3667 self.columns
3668 .iter()
3669 .map(|c| {
3670 let chunks = c.chunks.len();
3671 let rows = self.nrows as usize;
3672 let has_num = c.chunks.iter().any(|ch| ch.meta.non_null_num > 0);
3673 let has_bool = c.chunks.iter().any(|ch| ch.meta.non_null_bool > 0);
3674 let has_text = c.chunks.iter().any(|ch| ch.meta.non_null_text > 0);
3675 let has_err = c.chunks.iter().any(|ch| ch.meta.non_null_err > 0);
3676 ColumnShape {
3677 index: c.index,
3678 chunks,
3679 rows,
3680 has_num,
3681 has_bool,
3682 has_text,
3683 has_err,
3684 }
3685 })
3686 .collect()
3687 }
3688
3689 pub fn range_view(
3690 &self,
3691 sr: usize,
3692 sc: usize,
3693 er: usize,
3694 ec: usize,
3695 ) -> crate::engine::range_view::RangeView<'_> {
3696 let r0 = er.checked_sub(sr).map(|d| d + 1).unwrap_or(0);
3697 let c0 = ec.checked_sub(sc).map(|d| d + 1).unwrap_or(0);
3698 let (rows, cols) = if r0 == 0 || c0 == 0 { (0, 0) } else { (r0, c0) };
3699 crate::engine::range_view::RangeView::new(
3700 crate::engine::range_view::RangeBacking::Borrowed(self),
3701 sr,
3702 sc,
3703 er,
3704 ec,
3705 rows,
3706 cols,
3707 )
3708 }
3709
3710 pub(crate) fn has_formats(&self) -> bool {
3711 self.columns.iter().any(|column| {
3712 column
3713 .chunks
3714 .iter()
3715 .chain(column.sparse_chunks.values())
3716 .any(|chunk| {
3717 chunk.format.is_some()
3718 || chunk.overlay.has_formats()
3719 || chunk.computed_overlay.has_formats()
3720 })
3721 })
3722 }
3723
3724 pub fn format_id(&self, abs_row: usize, abs_col: usize) -> Option<FormatId> {
3726 let (ch_idx, in_off) = self.chunk_of_row(abs_row)?;
3727 let ch = self.columns.get(abs_col)?.chunk(ch_idx)?;
3728 ch.overlay
3729 .get_format(in_off)
3730 .or_else(|| {
3731 ch.format
3732 .as_ref()
3733 .map(|runs| runs.get(in_off))
3734 .filter(|id| *id != FormatId::GENERAL)
3735 })
3736 .or_else(|| ch.computed_overlay.get_format(in_off))
3737 .filter(|id| *id != FormatId::GENERAL)
3738 }
3739
3740 #[inline]
3744 pub fn get_cell_value(&self, abs_row: usize, abs_col: usize) -> LiteralValue {
3745 let sheet_rows = self.nrows as usize;
3746 if abs_row >= sheet_rows {
3747 return LiteralValue::Empty;
3748 }
3749 if abs_col >= self.columns.len() {
3750 return LiteralValue::Empty;
3751 }
3752 let Some((ch_idx, in_off)) = self.chunk_of_row(abs_row) else {
3753 return LiteralValue::Empty;
3754 };
3755 let col_ref = &self.columns[abs_col];
3756 let Some(ch) = col_ref.chunk(ch_idx) else {
3757 return LiteralValue::Empty;
3758 };
3759
3760 let cascade = OverlayCascade::new(&ch.overlay, &ch.computed_overlay);
3762 if let Some(ov) = cascade.get_scalar(in_off) {
3763 return ov.to_literal_for(self.date_system);
3764 }
3765
3766 let tag_u8 = ch.type_tag.value(in_off);
3768 match TypeTag::from_u8(tag_u8) {
3769 TypeTag::Empty => LiteralValue::Empty,
3770 TypeTag::Number => {
3771 if let Some(arr) = &ch.numbers {
3772 if arr.is_null(in_off) {
3773 return LiteralValue::Empty;
3774 }
3775 LiteralValue::Number(arr.value(in_off))
3776 } else {
3777 LiteralValue::Empty
3778 }
3779 }
3780 TypeTag::DateTime | TypeTag::Duration => {
3781 if let Some(arr) = &ch.numbers {
3782 if arr.is_null(in_off) {
3783 LiteralValue::Empty
3784 } else {
3785 LiteralValue::Number(arr.value(in_off))
3786 }
3787 } else {
3788 LiteralValue::Empty
3789 }
3790 }
3791 TypeTag::Boolean => {
3792 if let Some(arr) = &ch.booleans {
3793 if arr.is_null(in_off) {
3794 return LiteralValue::Empty;
3795 }
3796 LiteralValue::Boolean(arr.value(in_off))
3797 } else {
3798 LiteralValue::Empty
3799 }
3800 }
3801 TypeTag::Text => {
3802 if let Some(arr) = &ch.text {
3803 if arr.is_null(in_off) {
3804 return LiteralValue::Empty;
3805 }
3806 let sa = arr
3807 .as_any()
3808 .downcast_ref::<arrow_array::StringArray>()
3809 .unwrap();
3810 LiteralValue::Text(sa.value(in_off).to_string())
3811 } else {
3812 LiteralValue::Empty
3813 }
3814 }
3815 TypeTag::Error => {
3816 if let Some(arr) = &ch.errors {
3817 if arr.is_null(in_off) {
3818 return LiteralValue::Empty;
3819 }
3820 let kind = unmap_error_code(arr.value(in_off));
3821 LiteralValue::Error(ExcelError::new(kind))
3822 } else {
3823 LiteralValue::Empty
3824 }
3825 }
3826 TypeTag::Pending => LiteralValue::Pending,
3827 }
3828 }
3829
3830 pub fn ensure_row_capacity(&mut self, target_rows: usize) {
3835 if target_rows as u32 <= self.nrows {
3836 return;
3837 }
3838
3839 let chunk_size = self.chunk_rows.max(1);
3840
3841 if self.chunk_starts.is_empty() {
3845 self.chunk_starts.push(0);
3846 }
3847
3848 let mut next_start = self
3851 .chunk_starts
3852 .last()
3853 .copied()
3854 .unwrap_or(0)
3855 .saturating_add(chunk_size);
3856 while next_start < target_rows {
3857 self.chunk_starts.push(next_start);
3858 next_start = next_start.saturating_add(chunk_size);
3859 }
3860
3861 self.nrows = target_rows as u32;
3862
3863 let starts = self.chunk_starts.clone();
3868 let nrows = self.nrows as usize;
3869 let required_len_for = |ch_idx: usize| -> Option<usize> {
3870 let start = *starts.get(ch_idx)?;
3871 let end = starts.get(ch_idx + 1).copied().unwrap_or(nrows);
3872 Some(end.saturating_sub(start))
3873 };
3874
3875 for col in &mut self.columns {
3876 for (idx, ch) in col.chunks.iter_mut().enumerate() {
3877 if let Some(req) = required_len_for(idx) {
3878 ch.grow_len_to(req);
3879 }
3880 }
3881 if !col.sparse_chunks.is_empty() {
3882 let keys: Vec<usize> = col.sparse_chunks.keys().copied().collect();
3883 for idx in keys {
3884 if let (Some(req), Some(ch)) =
3885 (required_len_for(idx), col.sparse_chunks.get_mut(&idx))
3886 {
3887 ch.grow_len_to(req);
3888 }
3889 }
3890 }
3891 }
3892 }
3893
3894 pub fn ensure_column_chunk_mut(
3898 &mut self,
3899 col_idx: usize,
3900 ch_idx: usize,
3901 ) -> Option<&mut ColumnChunk> {
3902 let start = *self.chunk_starts.get(ch_idx)?;
3903 let end = self
3904 .chunk_starts
3905 .get(ch_idx + 1)
3906 .copied()
3907 .unwrap_or(self.nrows as usize);
3908 let len = end.saturating_sub(start);
3909
3910 let col = self.columns.get_mut(col_idx)?;
3911 if ch_idx < col.chunks.len() {
3912 return Some(&mut col.chunks[ch_idx]);
3913 }
3914 Some(
3915 col.sparse_chunks
3916 .entry(ch_idx)
3917 .or_insert_with(|| Self::make_empty_chunk(len)),
3918 )
3919 }
3920
3921 pub fn chunk_of_row(&self, abs_row: usize) -> Option<(usize, usize)> {
3923 if abs_row >= self.nrows as usize {
3924 return None;
3925 }
3926 let ch_idx = match self.chunk_starts.binary_search(&abs_row) {
3927 Ok(i) => i,
3928 Err(0) => 0,
3929 Err(i) => i - 1,
3930 };
3931 let start = self.chunk_starts[ch_idx];
3932 Some((ch_idx, abs_row - start))
3933 }
3934
3935 fn recompute_chunk_starts(&mut self) {
3936 self.chunk_starts.clear();
3937 if let Some(col0) = self.columns.first() {
3938 let mut cur = 0usize;
3939 for ch in &col0.chunks {
3940 self.chunk_starts.push(cur);
3941 cur += ch.type_tag.len();
3942 }
3943 }
3944 }
3945
3946 fn make_empty_chunk(len: usize) -> ColumnChunk {
3947 ColumnChunk {
3948 numbers: None,
3949 booleans: None,
3950 text: None,
3951 errors: None,
3952 type_tag: Arc::new(UInt8Array::from(vec![TypeTag::Empty as u8; len])),
3953 formula_id: None,
3954 format: None,
3955 meta: ColumnChunkMeta {
3956 len,
3957 non_null_num: 0,
3958 non_null_bool: 0,
3959 non_null_text: 0,
3960 non_null_err: 0,
3961 },
3962 lazy_null_numbers: OnceCell::new(),
3963 lazy_null_booleans: OnceCell::new(),
3964 lazy_null_text: OnceCell::new(),
3965 lazy_null_errors: OnceCell::new(),
3966 lowered_text: OnceCell::new(),
3967 overlay: Overlay::new(),
3968 computed_overlay: Overlay::new(),
3969 }
3970 }
3971
3972 fn slice_chunk(ch: &ColumnChunk, off: usize, len: usize) -> ColumnChunk {
3973 use arrow_array::Array;
3975 let type_tag: Arc<UInt8Array> = Arc::new(
3976 Array::slice(ch.type_tag.as_ref(), off, len)
3977 .as_any()
3978 .downcast_ref::<UInt8Array>()
3979 .unwrap()
3980 .clone(),
3981 );
3982 let numbers: Option<Arc<Float64Array>> = ch.numbers.as_ref().and_then(|a| {
3984 let sl = Array::slice(a.as_ref(), off, len);
3985 let fa = sl.as_any().downcast_ref::<Float64Array>().unwrap().clone();
3986 let nn = len.saturating_sub(fa.null_count());
3987 if nn == 0 { None } else { Some(Arc::new(fa)) }
3988 });
3989 let booleans: Option<Arc<BooleanArray>> = ch.booleans.as_ref().and_then(|a| {
3990 let sl = Array::slice(a.as_ref(), off, len);
3991 let ba = sl.as_any().downcast_ref::<BooleanArray>().unwrap().clone();
3992 let nn = len.saturating_sub(ba.null_count());
3993 if nn == 0 { None } else { Some(Arc::new(ba)) }
3994 });
3995 let text: Option<ArrayRef> = ch.text.as_ref().and_then(|a| {
3996 let sl = Array::slice(a.as_ref(), off, len);
3997 let sa = sl.as_any().downcast_ref::<StringArray>().unwrap().clone();
3998 let nn = len.saturating_sub(sa.null_count());
3999 if nn == 0 {
4000 None
4001 } else {
4002 Some(Arc::new(sa) as ArrayRef)
4003 }
4004 });
4005 let errors: Option<Arc<UInt8Array>> = ch.errors.as_ref().and_then(|a| {
4006 let sl = Array::slice(a.as_ref(), off, len);
4007 let ea = sl.as_any().downcast_ref::<UInt8Array>().unwrap().clone();
4008 let nn = len.saturating_sub(ea.null_count());
4009 if nn == 0 { None } else { Some(Arc::new(ea)) }
4010 });
4011 let overlay = ch.overlay.slice(off, len);
4013 let computed_overlay = ch.computed_overlay.slice(off, len);
4014 let non_null_num = numbers.as_ref().map(|a| len - a.null_count()).unwrap_or(0);
4015 let non_null_bool = booleans.as_ref().map(|a| len - a.null_count()).unwrap_or(0);
4016 let non_null_text = text.as_ref().map(|a| len - a.null_count()).unwrap_or(0);
4017 let non_null_err = errors.as_ref().map(|a| len - a.null_count()).unwrap_or(0);
4018 ColumnChunk {
4019 numbers: numbers.clone(),
4020 booleans: booleans.clone(),
4021 text: text.clone(),
4022 errors: errors.clone(),
4023 type_tag,
4024 formula_id: None,
4025 format: ch.format.as_ref().and_then(|runs| runs.slice(off, len)),
4026 meta: ColumnChunkMeta {
4027 len,
4028 non_null_num,
4029 non_null_bool,
4030 non_null_text,
4031 non_null_err,
4032 },
4033 lazy_null_numbers: OnceCell::new(),
4034 lazy_null_booleans: OnceCell::new(),
4035 lazy_null_text: OnceCell::new(),
4036 lazy_null_errors: OnceCell::new(),
4037 lowered_text: OnceCell::new(),
4038 overlay,
4039 computed_overlay,
4040 }
4041 }
4042
4043 pub fn maybe_compact_chunk(
4046 &mut self,
4047 col_idx: usize,
4048 ch_idx: usize,
4049 abs_threshold: usize,
4050 frac_den: usize,
4051 ) -> usize {
4052 if col_idx >= self.columns.len() {
4053 return 0;
4054 }
4055
4056 let (len, tags, numbers, booleans, text, errors, non_num, non_bool, non_text, non_err) = {
4057 let Some(ch_ref) = self.columns[col_idx].chunk(ch_idx) else {
4058 return 0;
4059 };
4060 let len = ch_ref.type_tag.len();
4061 if len == 0 {
4062 return 0;
4063 }
4064
4065 let ov_len = ch_ref.overlay.len();
4066 let den = frac_den.max(1);
4067 let trig = ov_len > (len / den) || ov_len > abs_threshold;
4068 if !trig {
4069 return 0;
4070 }
4071
4072 let mut tag_b = UInt8Builder::with_capacity(len);
4074 let mut nb = Float64Builder::with_capacity(len);
4075 let mut bb = BooleanBuilder::with_capacity(len);
4076 let mut sb = StringBuilder::with_capacity(len, len * 8);
4077 let mut eb = UInt8Builder::with_capacity(len);
4078 let mut non_num = 0usize;
4079 let mut non_bool = 0usize;
4080 let mut non_text = 0usize;
4081 let mut non_err = 0usize;
4082
4083 for i in 0..len {
4084 if let Some(ov) = ch_ref.overlay.get_scalar(i) {
4086 let ov = ov.to_overlay_value();
4087 append_overlay_value_to_lane_builders(
4088 &ov,
4089 &mut tag_b,
4090 &mut nb,
4091 &mut bb,
4092 &mut sb,
4093 &mut eb,
4094 &mut non_num,
4095 &mut non_bool,
4096 &mut non_text,
4097 &mut non_err,
4098 );
4099 } else {
4100 let tag = TypeTag::from_u8(ch_ref.type_tag.value(i));
4101 match tag {
4102 TypeTag::Empty => {
4103 tag_b.append_value(TypeTag::Empty as u8);
4104 nb.append_null();
4105 bb.append_null();
4106 sb.append_null();
4107 eb.append_null();
4108 }
4109 TypeTag::Number | TypeTag::DateTime | TypeTag::Duration => {
4110 tag_b.append_value(tag as u8);
4111 if let Some(a) = &ch_ref.numbers {
4112 let fa = a.as_any().downcast_ref::<Float64Array>().unwrap();
4113 if fa.is_null(i) {
4114 nb.append_null();
4115 } else {
4116 nb.append_value(fa.value(i));
4117 non_num += 1;
4118 }
4119 } else {
4120 nb.append_null();
4121 }
4122 bb.append_null();
4123 sb.append_null();
4124 eb.append_null();
4125 }
4126 TypeTag::Boolean => {
4127 tag_b.append_value(TypeTag::Boolean as u8);
4128 nb.append_null();
4129 if let Some(a) = &ch_ref.booleans {
4130 let ba = a.as_any().downcast_ref::<BooleanArray>().unwrap();
4131 if ba.is_null(i) {
4132 bb.append_null();
4133 } else {
4134 bb.append_value(ba.value(i));
4135 non_bool += 1;
4136 }
4137 } else {
4138 bb.append_null();
4139 }
4140 sb.append_null();
4141 eb.append_null();
4142 }
4143 TypeTag::Text => {
4144 tag_b.append_value(TypeTag::Text as u8);
4145 nb.append_null();
4146 bb.append_null();
4147 if let Some(a) = &ch_ref.text {
4148 let sa = a.as_any().downcast_ref::<StringArray>().unwrap();
4149 if sa.is_null(i) {
4150 sb.append_null();
4151 } else {
4152 sb.append_value(sa.value(i));
4153 non_text += 1;
4154 }
4155 } else {
4156 sb.append_null();
4157 }
4158 eb.append_null();
4159 }
4160 TypeTag::Error => {
4161 tag_b.append_value(TypeTag::Error as u8);
4162 nb.append_null();
4163 bb.append_null();
4164 sb.append_null();
4165 if let Some(a) = &ch_ref.errors {
4166 let ea = a.as_any().downcast_ref::<UInt8Array>().unwrap();
4167 if ea.is_null(i) {
4168 eb.append_null();
4169 } else {
4170 eb.append_value(ea.value(i));
4171 non_err += 1;
4172 }
4173 } else {
4174 eb.append_null();
4175 }
4176 }
4177 TypeTag::Pending => {
4178 tag_b.append_value(TypeTag::Pending as u8);
4179 nb.append_null();
4180 bb.append_null();
4181 sb.append_null();
4182 eb.append_null();
4183 }
4184 }
4185 }
4186 }
4187
4188 let tags = Arc::new(tag_b.finish());
4189 let numbers = {
4190 let a = nb.finish();
4191 if non_num == 0 {
4192 None
4193 } else {
4194 Some(Arc::new(a))
4195 }
4196 };
4197 let booleans = {
4198 let a = bb.finish();
4199 if non_bool == 0 {
4200 None
4201 } else {
4202 Some(Arc::new(a))
4203 }
4204 };
4205 let text = {
4206 let a = sb.finish();
4207 if non_text == 0 {
4208 None
4209 } else {
4210 Some(Arc::new(a) as ArrayRef)
4211 }
4212 };
4213 let errors = {
4214 let a = eb.finish();
4215 if non_err == 0 {
4216 None
4217 } else {
4218 Some(Arc::new(a))
4219 }
4220 };
4221
4222 (
4223 len, tags, numbers, booleans, text, errors, non_num, non_bool, non_text, non_err,
4224 )
4225 };
4226
4227 let Some(ch_mut) = self.columns[col_idx].chunk_mut(ch_idx) else {
4228 return 0;
4229 };
4230
4231 ch_mut.type_tag = tags;
4232 ch_mut.numbers = numbers;
4233 ch_mut.booleans = booleans;
4234 ch_mut.text = text;
4235 ch_mut.errors = errors;
4236 let freed = ch_mut.overlay.clear();
4237 ch_mut.lowered_text = OnceCell::new();
4238 ch_mut.meta.len = len;
4239 ch_mut.meta.non_null_num = non_num;
4240 ch_mut.meta.non_null_bool = non_bool;
4241 ch_mut.meta.non_null_text = non_text;
4242 ch_mut.meta.non_null_err = non_err;
4243 freed
4244 }
4245
4246 pub fn compact_computed_overlay_chunk(&mut self, col_idx: usize, ch_idx: usize) -> usize {
4254 if col_idx >= self.columns.len() {
4255 return 0;
4256 }
4257
4258 let (len, tags, numbers, booleans, text, errors, non_num, non_bool, non_text, non_err) = {
4259 let Some(ch_ref) = self.columns[col_idx].chunk(ch_idx) else {
4260 return 0;
4261 };
4262 let len = ch_ref.type_tag.len();
4263 if len == 0 || ch_ref.computed_overlay.is_empty() {
4264 return 0;
4265 }
4266
4267 let mut tag_b = UInt8Builder::with_capacity(len);
4268 let mut nb = Float64Builder::with_capacity(len);
4269 let mut bb = BooleanBuilder::with_capacity(len);
4270 let mut sb = StringBuilder::with_capacity(len, len * 8);
4271 let mut eb = UInt8Builder::with_capacity(len);
4272 let mut non_num = 0usize;
4273 let mut non_bool = 0usize;
4274 let mut non_text = 0usize;
4275 let mut non_err = 0usize;
4276
4277 for i in 0..len {
4278 if let Some(ov) = ch_ref.computed_overlay.get_scalar(i) {
4279 let ov = ov.to_overlay_value();
4280 append_overlay_value_to_lane_builders(
4281 &ov,
4282 &mut tag_b,
4283 &mut nb,
4284 &mut bb,
4285 &mut sb,
4286 &mut eb,
4287 &mut non_num,
4288 &mut non_bool,
4289 &mut non_text,
4290 &mut non_err,
4291 );
4292 } else {
4293 let tag = TypeTag::from_u8(ch_ref.type_tag.value(i));
4294 match tag {
4295 TypeTag::Empty => {
4296 tag_b.append_value(TypeTag::Empty as u8);
4297 nb.append_null();
4298 bb.append_null();
4299 sb.append_null();
4300 eb.append_null();
4301 }
4302 TypeTag::Number | TypeTag::DateTime | TypeTag::Duration => {
4303 tag_b.append_value(tag as u8);
4304 if let Some(a) = &ch_ref.numbers {
4305 let fa = a.as_any().downcast_ref::<Float64Array>().unwrap();
4306 if fa.is_null(i) {
4307 nb.append_null();
4308 } else {
4309 nb.append_value(fa.value(i));
4310 non_num += 1;
4311 }
4312 } else {
4313 nb.append_null();
4314 }
4315 bb.append_null();
4316 sb.append_null();
4317 eb.append_null();
4318 }
4319 TypeTag::Boolean => {
4320 tag_b.append_value(TypeTag::Boolean as u8);
4321 nb.append_null();
4322 if let Some(a) = &ch_ref.booleans {
4323 let ba = a.as_any().downcast_ref::<BooleanArray>().unwrap();
4324 if ba.is_null(i) {
4325 bb.append_null();
4326 } else {
4327 bb.append_value(ba.value(i));
4328 non_bool += 1;
4329 }
4330 } else {
4331 bb.append_null();
4332 }
4333 sb.append_null();
4334 eb.append_null();
4335 }
4336 TypeTag::Text => {
4337 tag_b.append_value(TypeTag::Text as u8);
4338 nb.append_null();
4339 bb.append_null();
4340 if let Some(a) = &ch_ref.text {
4341 let sa = a.as_any().downcast_ref::<StringArray>().unwrap();
4342 if sa.is_null(i) {
4343 sb.append_null();
4344 } else {
4345 sb.append_value(sa.value(i));
4346 non_text += 1;
4347 }
4348 } else {
4349 sb.append_null();
4350 }
4351 eb.append_null();
4352 }
4353 TypeTag::Error => {
4354 tag_b.append_value(TypeTag::Error as u8);
4355 nb.append_null();
4356 bb.append_null();
4357 sb.append_null();
4358 if let Some(a) = &ch_ref.errors {
4359 let ea = a.as_any().downcast_ref::<UInt8Array>().unwrap();
4360 if ea.is_null(i) {
4361 eb.append_null();
4362 } else {
4363 eb.append_value(ea.value(i));
4364 non_err += 1;
4365 }
4366 } else {
4367 eb.append_null();
4368 }
4369 }
4370 TypeTag::Pending => {
4371 tag_b.append_value(TypeTag::Pending as u8);
4372 nb.append_null();
4373 bb.append_null();
4374 sb.append_null();
4375 eb.append_null();
4376 }
4377 }
4378 }
4379 }
4380
4381 let tags = Arc::new(tag_b.finish());
4382 let numbers = {
4383 let a = nb.finish();
4384 if non_num == 0 {
4385 None
4386 } else {
4387 Some(Arc::new(a))
4388 }
4389 };
4390 let booleans = {
4391 let a = bb.finish();
4392 if non_bool == 0 {
4393 None
4394 } else {
4395 Some(Arc::new(a))
4396 }
4397 };
4398 let text = {
4399 let a = sb.finish();
4400 if non_text == 0 {
4401 None
4402 } else {
4403 Some(Arc::new(a) as ArrayRef)
4404 }
4405 };
4406 let errors = {
4407 let a = eb.finish();
4408 if non_err == 0 {
4409 None
4410 } else {
4411 Some(Arc::new(a))
4412 }
4413 };
4414
4415 (
4416 len, tags, numbers, booleans, text, errors, non_num, non_bool, non_text, non_err,
4417 )
4418 };
4419
4420 let Some(ch_mut) = self.columns[col_idx].chunk_mut(ch_idx) else {
4421 return 0;
4422 };
4423
4424 ch_mut.type_tag = tags;
4425 ch_mut.numbers = numbers;
4426 ch_mut.booleans = booleans;
4427 ch_mut.text = text;
4428 ch_mut.errors = errors;
4429 let freed = ch_mut.computed_overlay.clear();
4430 ch_mut.lowered_text = OnceCell::new();
4431 ch_mut.meta.len = len;
4432 ch_mut.meta.non_null_num = non_num;
4433 ch_mut.meta.non_null_bool = non_bool;
4434 ch_mut.meta.non_null_text = non_text;
4435 ch_mut.meta.non_null_err = non_err;
4436 freed
4437 }
4438
4439 pub fn compact_computed_overlay_sparse_chunk(
4442 &mut self,
4443 col_idx: usize,
4444 ch_idx: usize,
4445 ) -> usize {
4446 self.compact_computed_overlay_chunk(col_idx, ch_idx)
4449 }
4450
4451 pub fn insert_rows(&mut self, before: usize, count: usize) {
4453 if count == 0 {
4454 return;
4455 }
4456
4457 let total_rows = self.nrows as usize;
4458 if total_rows == 0 {
4459 self.nrows = count as u32;
4460 if self.nrows > 0 && self.chunk_starts.is_empty() {
4461 self.chunk_starts.push(0);
4462 }
4463 return;
4464 }
4465
4466 if self.chunk_starts.is_empty() {
4468 self.chunk_starts.push(0);
4469 }
4470
4471 let dense_aligned = self
4473 .columns
4474 .iter()
4475 .all(|c| c.sparse_chunks.is_empty() && c.chunks.len() == self.chunk_starts.len());
4476
4477 let insert_at = before.min(total_rows);
4478 let (split_idx, split_off) = if insert_at == total_rows {
4479 let last_idx = self.chunk_starts.len() - 1;
4481 let last_start = self.chunk_starts[last_idx];
4482 let last_len = total_rows.saturating_sub(last_start);
4483 (last_idx, last_len)
4484 } else {
4485 self.chunk_of_row(insert_at).unwrap_or((0, 0))
4486 };
4487
4488 if dense_aligned {
4489 for col in &mut self.columns {
4491 let mut new_chunks: Vec<ColumnChunk> = Vec::with_capacity(col.chunks.len() + 2);
4492 for i in 0..col.chunks.len() {
4493 if i != split_idx {
4494 new_chunks.push(col.chunks[i].clone());
4495 } else {
4496 let orig = &col.chunks[i];
4497 let len = orig.type_tag.len();
4498 if split_off > 0 {
4499 new_chunks.push(Self::slice_chunk(orig, 0, split_off));
4500 }
4501 new_chunks.push(Self::make_empty_chunk(count));
4502 if split_off < len {
4503 new_chunks.push(Self::slice_chunk(orig, split_off, len - split_off));
4504 }
4505 }
4506 }
4507 col.chunks = new_chunks;
4508 col.sparse_chunks.clear();
4509 }
4510 self.nrows = (total_rows + count) as u32;
4511 self.recompute_chunk_starts();
4512 return;
4513 }
4514
4515 #[derive(Clone, Copy)]
4517 enum PlanItem {
4518 Slice {
4519 old_idx: usize,
4520 off: usize,
4521 len: usize,
4522 },
4523 Empty {
4524 len: usize,
4525 },
4526 }
4527
4528 let mut plan: Vec<PlanItem> = Vec::with_capacity(self.chunk_starts.len() + 2);
4529 for old_idx in 0..self.chunk_starts.len() {
4530 let ch_start = self.chunk_starts[old_idx];
4531 let ch_end = self
4532 .chunk_starts
4533 .get(old_idx + 1)
4534 .copied()
4535 .unwrap_or(total_rows);
4536 let ch_len = ch_end.saturating_sub(ch_start);
4537 if ch_len == 0 {
4538 continue;
4539 }
4540
4541 if old_idx != split_idx {
4542 plan.push(PlanItem::Slice {
4543 old_idx,
4544 off: 0,
4545 len: ch_len,
4546 });
4547 continue;
4548 }
4549
4550 let left_len = split_off.min(ch_len);
4551 let right_len = ch_len.saturating_sub(left_len);
4552 if left_len > 0 {
4553 plan.push(PlanItem::Slice {
4554 old_idx,
4555 off: 0,
4556 len: left_len,
4557 });
4558 }
4559 plan.push(PlanItem::Empty { len: count });
4560 if right_len > 0 {
4561 plan.push(PlanItem::Slice {
4562 old_idx,
4563 off: left_len,
4564 len: right_len,
4565 });
4566 }
4567 }
4568
4569 let mut new_starts: Vec<usize> = Vec::with_capacity(plan.len());
4570 let mut cur = 0usize;
4571 for item in &plan {
4572 let len = match *item {
4573 PlanItem::Slice { len, .. } => len,
4574 PlanItem::Empty { len } => len,
4575 };
4576 if len == 0 {
4577 continue;
4578 }
4579 new_starts.push(cur);
4580 cur = cur.saturating_add(len);
4581 }
4582
4583 debug_assert_eq!(cur, total_rows.saturating_add(count));
4584
4585 self.nrows = (total_rows + count) as u32;
4587 self.chunk_starts = new_starts;
4588
4589 for col in &mut self.columns {
4591 let old_dense = std::mem::take(&mut col.chunks);
4592 let old_sparse = std::mem::take(&mut col.sparse_chunks);
4593 let get_old = |idx: usize| -> Option<&ColumnChunk> {
4594 if idx < old_dense.len() {
4595 Some(&old_dense[idx])
4596 } else {
4597 old_sparse.get(&idx)
4598 }
4599 };
4600
4601 let mut dense: Vec<ColumnChunk> = Vec::new();
4602 let mut sparse: FxHashMap<usize, ColumnChunk> = FxHashMap::default();
4603 let mut dense_prefix = true;
4604
4605 for (new_idx, item) in plan.iter().enumerate() {
4606 let produced: Option<ColumnChunk> = match *item {
4607 PlanItem::Empty { .. } => None,
4608 PlanItem::Slice { old_idx, off, len } => match get_old(old_idx) {
4609 Some(orig) => {
4610 if off == 0 && len == orig.type_tag.len() {
4611 Some(orig.clone())
4612 } else {
4613 Some(Self::slice_chunk(orig, off, len))
4614 }
4615 }
4616 None => None,
4617 },
4618 };
4619
4620 if let Some(ch) = produced {
4621 if dense_prefix && new_idx == dense.len() {
4622 dense.push(ch);
4623 } else {
4624 sparse.insert(new_idx, ch);
4625 dense_prefix = false;
4626 }
4627 } else if dense_prefix && new_idx == dense.len() {
4628 dense_prefix = false;
4629 }
4630 }
4631
4632 col.chunks = dense;
4633 col.sparse_chunks = sparse;
4634 }
4635 }
4636
4637 pub fn delete_rows(&mut self, start: usize, count: usize) {
4639 if count == 0 || self.nrows == 0 {
4640 return;
4641 }
4642
4643 let total_rows = self.nrows as usize;
4644 if start >= total_rows {
4645 return;
4646 }
4647 let end = (start + count).min(total_rows);
4648 let del_len = end.saturating_sub(start);
4649 if del_len == 0 {
4650 return;
4651 }
4652
4653 if total_rows > 0 && self.chunk_starts.is_empty() {
4655 self.chunk_starts.push(0);
4656 }
4657
4658 let dense_aligned = self
4660 .columns
4661 .iter()
4662 .all(|c| c.sparse_chunks.is_empty() && c.chunks.len() == self.chunk_starts.len());
4663
4664 if dense_aligned {
4665 for col in &mut self.columns {
4667 let mut new_chunks: Vec<ColumnChunk> = Vec::new();
4668 let mut cur_start = 0usize;
4669 for ch in &col.chunks {
4670 let len = ch.type_tag.len();
4671 let ch_end = cur_start + len;
4672 if ch_end <= start || cur_start >= end {
4674 new_chunks.push(ch.clone());
4675 } else {
4676 let del_start = start.max(cur_start);
4678 let del_end = end.min(ch_end);
4679 let left_len = del_start.saturating_sub(cur_start);
4680 let right_len = ch_end.saturating_sub(del_end);
4681 if left_len > 0 {
4682 new_chunks.push(Self::slice_chunk(ch, 0, left_len));
4683 }
4684 if right_len > 0 {
4685 let off = len - right_len;
4686 new_chunks.push(Self::slice_chunk(ch, off, right_len));
4687 }
4688 }
4689 cur_start = ch_end;
4690 }
4691 col.chunks = new_chunks;
4692 col.sparse_chunks.clear();
4693 }
4694 self.nrows = (total_rows - del_len) as u32;
4695 self.recompute_chunk_starts();
4696 return;
4697 }
4698
4699 #[derive(Clone, Copy)]
4701 enum PlanItem {
4702 Slice {
4703 old_idx: usize,
4704 off: usize,
4705 len: usize,
4706 },
4707 }
4708
4709 let mut plan: Vec<PlanItem> = Vec::with_capacity(self.chunk_starts.len());
4710 for old_idx in 0..self.chunk_starts.len() {
4711 let ch_start = self.chunk_starts[old_idx];
4712 let ch_end = self
4713 .chunk_starts
4714 .get(old_idx + 1)
4715 .copied()
4716 .unwrap_or(total_rows);
4717 let ch_len = ch_end.saturating_sub(ch_start);
4718 if ch_len == 0 {
4719 continue;
4720 }
4721
4722 if ch_end <= start || ch_start >= end {
4724 plan.push(PlanItem::Slice {
4725 old_idx,
4726 off: 0,
4727 len: ch_len,
4728 });
4729 continue;
4730 }
4731
4732 if start > ch_start {
4734 let left_end = start.min(ch_end);
4735 let left_len = left_end.saturating_sub(ch_start);
4736 if left_len > 0 {
4737 plan.push(PlanItem::Slice {
4738 old_idx,
4739 off: 0,
4740 len: left_len,
4741 });
4742 }
4743 }
4744
4745 if end < ch_end {
4747 let right_off = end.saturating_sub(ch_start);
4748 let right_len = ch_end.saturating_sub(end);
4749 if right_len > 0 {
4750 plan.push(PlanItem::Slice {
4751 old_idx,
4752 off: right_off,
4753 len: right_len,
4754 });
4755 }
4756 }
4757 }
4758
4759 let mut new_starts: Vec<usize> = Vec::with_capacity(plan.len());
4760 let mut cur = 0usize;
4761 for item in &plan {
4762 let len = match *item {
4763 PlanItem::Slice { len, .. } => len,
4764 };
4765 if len == 0 {
4766 continue;
4767 }
4768 new_starts.push(cur);
4769 cur = cur.saturating_add(len);
4770 }
4771
4772 debug_assert_eq!(cur, total_rows.saturating_sub(del_len));
4773
4774 self.nrows = (total_rows - del_len) as u32;
4776 self.chunk_starts = new_starts;
4777
4778 for col in &mut self.columns {
4780 let old_dense = std::mem::take(&mut col.chunks);
4781 let old_sparse = std::mem::take(&mut col.sparse_chunks);
4782 let get_old = |idx: usize| -> Option<&ColumnChunk> {
4783 if idx < old_dense.len() {
4784 Some(&old_dense[idx])
4785 } else {
4786 old_sparse.get(&idx)
4787 }
4788 };
4789
4790 let mut dense: Vec<ColumnChunk> = Vec::new();
4791 let mut sparse: FxHashMap<usize, ColumnChunk> = FxHashMap::default();
4792 let mut dense_prefix = true;
4793
4794 for (new_idx, item) in plan.iter().enumerate() {
4795 let produced: Option<ColumnChunk> = match *item {
4796 PlanItem::Slice { old_idx, off, len } => match get_old(old_idx) {
4797 Some(orig) => {
4798 if off == 0 && len == orig.type_tag.len() {
4799 Some(orig.clone())
4800 } else {
4801 Some(Self::slice_chunk(orig, off, len))
4802 }
4803 }
4804 None => None,
4805 },
4806 };
4807
4808 if let Some(ch) = produced {
4809 if dense_prefix && new_idx == dense.len() {
4810 dense.push(ch);
4811 } else {
4812 sparse.insert(new_idx, ch);
4813 dense_prefix = false;
4814 }
4815 } else if dense_prefix && new_idx == dense.len() {
4816 dense_prefix = false;
4817 }
4818 }
4819
4820 col.chunks = dense;
4821 col.sparse_chunks = sparse;
4822 }
4823 }
4824
4825 pub fn insert_columns(&mut self, before: usize, count: usize) {
4827 if count == 0 {
4828 return;
4829 }
4830 let empty_col = |lens: &[usize]| -> ArrowColumn {
4832 let mut chunks = Vec::with_capacity(lens.len());
4833 for &l in lens {
4834 chunks.push(Self::make_empty_chunk(l));
4835 }
4836 ArrowColumn {
4837 chunks,
4838 sparse_chunks: FxHashMap::default(),
4839 index: 0,
4840 }
4841 };
4842 let dense_aligned = !self.columns.is_empty()
4843 && self
4844 .columns
4845 .iter()
4846 .all(|c| c.sparse_chunks.is_empty() && c.chunks.len() == self.chunk_starts.len());
4847
4848 let lens: Vec<usize> = if dense_aligned {
4849 self.columns[0]
4850 .chunks
4851 .iter()
4852 .map(|c| c.type_tag.len())
4853 .collect()
4854 } else if self.columns.is_empty() {
4855 if self.nrows > 0 {
4857 vec![self.nrows as usize]
4858 } else {
4859 Vec::new()
4860 }
4861 } else {
4862 Vec::new()
4864 };
4865 let mut cols_new: Vec<ArrowColumn> = Vec::with_capacity(self.columns.len() + count);
4866 let before_idx = before.min(self.columns.len());
4867 for (i, col) in self.columns.iter_mut().enumerate() {
4868 if i == before_idx {
4869 for _ in 0..count {
4870 cols_new.push(empty_col(&lens));
4871 }
4872 }
4873 cols_new.push(col.clone());
4874 }
4875 if before_idx == self.columns.len() {
4876 for _ in 0..count {
4877 cols_new.push(empty_col(&lens));
4878 }
4879 }
4880 for (idx, col) in cols_new.iter_mut().enumerate() {
4882 col.index = idx as u32;
4883 }
4884 self.columns = cols_new;
4885 }
4887
4888 pub fn delete_columns(&mut self, start: usize, count: usize) {
4890 if count == 0 || self.columns.is_empty() {
4891 return;
4892 }
4893 let end = (start + count).min(self.columns.len());
4894 if start >= end {
4895 return;
4896 }
4897 self.columns.drain(start..end);
4898 for (idx, col) in self.columns.iter_mut().enumerate() {
4899 col.index = idx as u32;
4900 }
4901 }
4902}
4903
4904#[derive(Debug, Clone, Copy)]
4905pub struct ColumnShape {
4906 pub index: u32,
4907 pub chunks: usize,
4908 pub rows: usize,
4909 pub has_num: bool,
4910 pub has_bool: bool,
4911 pub has_text: bool,
4912 pub has_err: bool,
4913}
4914
4915#[cfg(test)]
4916mod tests {
4917 use super::*;
4918
4919 #[test]
4920 fn explicit_format_precedence_and_general_filter_are_stable() {
4921 let date = chrono::NaiveDate::from_ymd_opt(2024, 1, 15).unwrap();
4922 let mut ingest = IngestBuilder::new("Sheet1", 1, 16, crate::engine::DateSystem::Excel1900);
4923 ingest.append_row(&[LiteralValue::Date(date)]).unwrap();
4924 ingest.append_row(&[LiteralValue::Number(1.0)]).unwrap();
4925 let mut sheet = ingest.finish();
4926
4927 let chunk = sheet.columns[0].chunk_mut(0).unwrap();
4928 chunk.computed_overlay.set_format(0, Some(FormatId::TIME));
4929 assert_eq!(
4930 sheet.format_id(0, 0),
4931 Some(FormatId::DATE),
4932 "base explicit format must beat the derived overlay"
4933 );
4934
4935 sheet.columns[0]
4936 .chunk_mut(0)
4937 .unwrap()
4938 .overlay
4939 .set_format(0, Some(FormatId::DATETIME));
4940 assert_eq!(
4941 sheet.format_id(0, 0),
4942 Some(FormatId::DATETIME),
4943 "user explicit overlay must beat base and derived formats"
4944 );
4945 assert_eq!(
4946 sheet.format_id(1, 0),
4947 None,
4948 "General is absence, not an effective explicit format"
4949 );
4950 sheet.ensure_row_capacity(3);
4951 assert_eq!(
4952 sheet.format_id(2, 0),
4953 None,
4954 "growing a formatted chunk must fill new rows with General"
4955 );
4956 }
4957
4958 #[test]
4959 fn known_error_storage_codes_are_stable() {
4960 let cases = [
4961 (ExcelErrorKind::Null, 1),
4962 (ExcelErrorKind::Ref, 2),
4963 (ExcelErrorKind::Name, 3),
4964 (ExcelErrorKind::Value, 4),
4965 (ExcelErrorKind::Div, 5),
4966 (ExcelErrorKind::Na, 6),
4967 (ExcelErrorKind::Num, 7),
4968 (ExcelErrorKind::Error, 8),
4969 (ExcelErrorKind::NImpl, 9),
4970 (ExcelErrorKind::Spill, 10),
4971 (ExcelErrorKind::Calc, 11),
4972 (ExcelErrorKind::Circ, 12),
4973 (ExcelErrorKind::Cancelled, 13),
4974 ];
4975 for (kind, code) in cases {
4976 assert_eq!(map_error_code(kind), code, "{kind:?}");
4977 assert_eq!(unmap_error_code(code), kind, "code {code}");
4978 }
4979 assert_eq!(unmap_error_code(u8::MAX), ExcelErrorKind::Error);
4980 }
4981 use arrow_array::Array;
4982 use arrow_schema::DataType;
4983 use chrono::{Datelike, Timelike};
4984
4985 #[test]
4986 fn sparse_constructor_defaults_to_excel_1900_and_decodes_excel_1904() {
4987 let date = chrono::NaiveDate::from_ymd_opt(1904, 1, 1).unwrap();
4988 let _datetime = date.and_hms_opt(12, 0, 0).unwrap();
4989
4990 let mut default_sheet = ArrowSheet::new_sparse("Default", 1, 1, 16);
4991 assert_eq!(
4992 default_sheet.date_system,
4993 crate::engine::DateSystem::Excel1900
4994 );
4995 default_sheet.set_sparse_overlay_value(0, 0, OverlayValue::DateTime(1462.5));
4996 assert_eq!(
4997 default_sheet.get_cell_value(0, 0),
4998 LiteralValue::Number(1462.5)
4999 );
5000
5001 let mut excel_1904 = ArrowSheet::new_sparse_with_date_system(
5002 "1904",
5003 1,
5004 1,
5005 16,
5006 crate::engine::DateSystem::Excel1904,
5007 );
5008 assert_eq!(excel_1904.date_system, crate::engine::DateSystem::Excel1904);
5009 excel_1904.set_sparse_overlay_value(0, 0, OverlayValue::DateTime(0.5));
5010 assert_eq!(excel_1904.get_cell_value(0, 0), LiteralValue::Number(0.5));
5011 }
5012
5013 #[test]
5014 fn datetime_lanes_round_trip_the_sheet_date_system() {
5015 let date = chrono::NaiveDate::from_ymd_opt(2024, 1, 15).unwrap();
5016 let datetime = date.and_hms_opt(12, 30, 0).unwrap();
5017 let time = chrono::NaiveTime::from_hms_opt(12, 30, 0).unwrap();
5018
5019 for system in [
5020 crate::engine::DateSystem::Excel1900,
5021 crate::engine::DateSystem::Excel1904,
5022 ] {
5023 let values = vec![
5024 LiteralValue::Date(date),
5025 LiteralValue::DateTime(datetime),
5026 LiteralValue::Time(time),
5027 ];
5028 let mut ingest = IngestBuilder::new("Sheet1", 3, 16, system);
5029 ingest.append_row(&values).unwrap();
5030 let sheet = ingest.finish();
5031
5032 assert_eq!(sheet.date_system, system);
5033 let date_serial = formualizer_common::date_to_serial_for(system, &date);
5034 let datetime_serial = formualizer_common::datetime_to_serial_for(system, &datetime);
5035 assert_eq!(
5036 sheet.get_cell_value(0, 0),
5037 LiteralValue::Number(date_serial)
5038 );
5039 assert_eq!(
5040 sheet.get_cell_value(0, 1),
5041 LiteralValue::Number(datetime_serial)
5042 );
5043 assert_eq!(sheet.format_id(0, 0), Some(FormatId::DATE));
5044 assert_eq!(sheet.format_id(0, 1), Some(FormatId::DATETIME));
5045 assert_eq!(sheet.format_id(0, 2), Some(FormatId::TIME));
5046 let view = sheet.range_view(0, 0, 0, 1);
5047 assert_eq!(view.get_cell(0, 0), LiteralValue::Number(date_serial));
5048 assert_eq!(view.get_cell(0, 1), LiteralValue::Number(datetime_serial));
5049
5050 let mut sparse = ArrowSheet::new_sparse_with_date_system("Sparse", 1, 1, 16, system);
5051 sparse.set_sparse_overlay_value(
5052 0,
5053 0,
5054 OverlayValue::from_literal_value(&values[1], system),
5055 );
5056 assert_eq!(
5057 sparse.get_cell_value(0, 0),
5058 LiteralValue::Number(datetime_serial)
5059 );
5060 }
5061 }
5062
5063 fn add_overlay_stats(into: &mut OverlayDebugStats, next: OverlayDebugStats) {
5064 into.points += next.points;
5065 into.sparse_fragments += next.sparse_fragments;
5066 into.dense_fragments += next.dense_fragments;
5067 into.run_fragments += next.run_fragments;
5068 into.covered_len += next.covered_len;
5069 }
5070
5071 fn column_overlay_stats(
5072 sheet: &ArrowSheet,
5073 col_idx: usize,
5074 computed: bool,
5075 ) -> OverlayDebugStats {
5076 let mut stats = OverlayDebugStats::default();
5077 let Some(column) = sheet.columns.get(col_idx) else {
5078 return stats;
5079 };
5080 for chunk in &column.chunks {
5081 add_overlay_stats(
5082 &mut stats,
5083 if computed {
5084 chunk.computed_overlay.debug_stats()
5085 } else {
5086 chunk.overlay.debug_stats()
5087 },
5088 );
5089 }
5090 for chunk in column.sparse_chunks.values() {
5091 add_overlay_stats(
5092 &mut stats,
5093 if computed {
5094 chunk.computed_overlay.debug_stats()
5095 } else {
5096 chunk.overlay.debug_stats()
5097 },
5098 );
5099 }
5100 stats
5101 }
5102
5103 fn assert_column_overlays_normalized(sheet: &ArrowSheet, col_idx: usize) {
5104 let column = &sheet.columns[col_idx];
5105 for chunk in &column.chunks {
5106 assert!(chunk.overlay.debug_is_normalized());
5107 assert!(chunk.computed_overlay.debug_is_normalized());
5108 assert_eq!(
5109 chunk.overlay.estimated_bytes(),
5110 chunk.overlay.debug_recomputed_estimated_bytes()
5111 );
5112 assert_eq!(
5113 chunk.computed_overlay.estimated_bytes(),
5114 chunk.computed_overlay.debug_recomputed_estimated_bytes()
5115 );
5116 }
5117 for chunk in column.sparse_chunks.values() {
5118 assert!(chunk.overlay.debug_is_normalized());
5119 assert!(chunk.computed_overlay.debug_is_normalized());
5120 assert_eq!(
5121 chunk.overlay.estimated_bytes(),
5122 chunk.overlay.debug_recomputed_estimated_bytes()
5123 );
5124 assert_eq!(
5125 chunk.computed_overlay.estimated_bytes(),
5126 chunk.computed_overlay.debug_recomputed_estimated_bytes()
5127 );
5128 }
5129 }
5130
5131 fn column_computed_overlay_estimated_bytes(sheet: &ArrowSheet, col_idx: usize) -> usize {
5132 let Some(column) = sheet.columns.get(col_idx) else {
5133 return 0;
5134 };
5135 column
5136 .chunks
5137 .iter()
5138 .map(|chunk| chunk.computed_overlay.estimated_bytes())
5139 .chain(
5140 column
5141 .sparse_chunks
5142 .values()
5143 .map(|chunk| chunk.computed_overlay.estimated_bytes()),
5144 )
5145 .fold(0usize, usize::saturating_add)
5146 }
5147
5148 #[derive(Debug, Clone, Copy)]
5149 enum Phase4ProbeFixture {
5150 PointNumeric,
5151 DenseNumeric,
5152 RunNumeric,
5153 SparseNumeric,
5154 EmptyRun,
5155 MixedDense,
5156 }
5157
5158 impl Phase4ProbeFixture {
5159 fn name(self) -> &'static str {
5160 match self {
5161 Phase4ProbeFixture::PointNumeric => "point_numeric",
5162 Phase4ProbeFixture::DenseNumeric => "dense_numeric",
5163 Phase4ProbeFixture::RunNumeric => "run_numeric",
5164 Phase4ProbeFixture::SparseNumeric => "sparse_numeric",
5165 Phase4ProbeFixture::EmptyRun => "empty_run",
5166 Phase4ProbeFixture::MixedDense => "mixed_dense",
5167 }
5168 }
5169 }
5170
5171 #[derive(Debug, serde::Serialize)]
5172 struct Phase4ProbeOp {
5173 ms: f64,
5174 segments: usize,
5175 arrays: usize,
5176 rows_scanned: usize,
5177 checksum: f64,
5178 non_null: usize,
5179 }
5180
5181 #[derive(Debug, serde::Serialize)]
5182 struct Phase4ProbeRow {
5183 fixture: &'static str,
5184 rows: usize,
5185 points: usize,
5186 sparse_fragments: usize,
5187 dense_fragments: usize,
5188 run_fragments: usize,
5189 covered_len: usize,
5190 overlay_estimated_bytes: usize,
5191 numbers: Phase4ProbeOp,
5192 type_tags: Phase4ProbeOp,
5193 lowered_text: Phase4ProbeOp,
5194 get_cell_scan: Phase4ProbeOp,
5195 select_stats: OverlaySelectStats,
5196 }
5197
5198 fn build_phase4_probe_sheet(rows: usize, fixture: Phase4ProbeFixture) -> ArrowSheet {
5199 let mut builder =
5200 IngestBuilder::new("S", 1, rows.max(1), crate::engine::DateSystem::Excel1900);
5201 for row in 0..rows {
5202 builder
5203 .append_row(&[LiteralValue::Number((row + 1) as f64)])
5204 .unwrap();
5205 }
5206 let mut sheet = builder.finish();
5207 let chunk = sheet.columns[0].chunk_mut(0).unwrap();
5208 match fixture {
5209 Phase4ProbeFixture::PointNumeric => {
5210 for row in 0..rows {
5211 chunk
5212 .computed_overlay
5213 .set_scalar(row, OverlayValue::Number((row + 1) as f64));
5214 }
5215 }
5216 Phase4ProbeFixture::DenseNumeric => {
5217 chunk.computed_overlay.apply_fragment(
5218 OverlayFragment::dense_range(
5219 0,
5220 (0..rows)
5221 .map(|row| OverlayValue::Number((row + 1) as f64))
5222 .collect(),
5223 )
5224 .unwrap(),
5225 );
5226 }
5227 Phase4ProbeFixture::RunNumeric => {
5228 chunk.computed_overlay.apply_fragment(
5229 OverlayFragment::run_range(0, vec![OverlayValue::Number(1.0); rows]).unwrap(),
5230 );
5231 }
5232 Phase4ProbeFixture::SparseNumeric => {
5233 chunk.computed_overlay.apply_fragment(
5234 OverlayFragment::sparse_offsets(
5235 (0..rows)
5236 .step_by(10)
5237 .map(|row| (row, OverlayValue::Number(10.0)))
5238 .collect(),
5239 )
5240 .unwrap(),
5241 );
5242 }
5243 Phase4ProbeFixture::EmptyRun => {
5244 chunk.computed_overlay.apply_fragment(
5245 OverlayFragment::run_range(0, vec![OverlayValue::Empty; rows]).unwrap(),
5246 );
5247 }
5248 Phase4ProbeFixture::MixedDense => {
5249 let pattern = [
5250 OverlayValue::Number(1.0),
5251 OverlayValue::Boolean(true),
5252 OverlayValue::Text(Arc::from("Alpha")),
5253 OverlayValue::Empty,
5254 OverlayValue::Error(map_error_code(ExcelErrorKind::Div)),
5255 OverlayValue::Pending,
5256 OverlayValue::DateTime(45000.25),
5257 OverlayValue::Duration(0.5),
5258 ];
5259 chunk.computed_overlay.apply_fragment(
5260 OverlayFragment::dense_range(
5261 0,
5262 (0..rows)
5263 .map(|row| pattern[row % pattern.len()].clone())
5264 .collect(),
5265 )
5266 .unwrap(),
5267 );
5268 }
5269 }
5270 sheet
5271 }
5272
5273 fn measure_probe_numbers(sheet: &ArrowSheet, rows: usize) -> Phase4ProbeOp {
5274 let view = sheet.range_view(0, 0, rows.saturating_sub(1), 0);
5275 let start = std::time::Instant::now();
5276 let mut segments = 0usize;
5277 let mut arrays = 0usize;
5278 let mut rows_scanned = 0usize;
5279 let mut checksum = 0.0;
5280 let mut non_null = 0usize;
5281 for segment in view.numbers_slices() {
5282 let (_row_start, row_len, cols) = segment.unwrap();
5283 segments += 1;
5284 rows_scanned += row_len;
5285 for array in cols {
5286 arrays += 1;
5287 for idx in 0..array.len() {
5288 if array.is_valid(idx) {
5289 checksum += array.value(idx);
5290 non_null += 1;
5291 }
5292 }
5293 }
5294 }
5295 Phase4ProbeOp {
5296 ms: start.elapsed().as_secs_f64() * 1000.0,
5297 segments,
5298 arrays,
5299 rows_scanned,
5300 checksum,
5301 non_null,
5302 }
5303 }
5304
5305 fn measure_probe_type_tags(sheet: &ArrowSheet, rows: usize) -> Phase4ProbeOp {
5306 let view = sheet.range_view(0, 0, rows.saturating_sub(1), 0);
5307 let start = std::time::Instant::now();
5308 let mut segments = 0usize;
5309 let mut arrays = 0usize;
5310 let mut rows_scanned = 0usize;
5311 let mut checksum = 0.0;
5312 let mut non_null = 0usize;
5313 for segment in view.type_tags_slices() {
5314 let (_row_start, row_len, cols) = segment.unwrap();
5315 segments += 1;
5316 rows_scanned += row_len;
5317 for array in cols {
5318 arrays += 1;
5319 for idx in 0..array.len() {
5320 if array.is_valid(idx) {
5321 checksum += array.value(idx) as f64;
5322 non_null += 1;
5323 }
5324 }
5325 }
5326 }
5327 Phase4ProbeOp {
5328 ms: start.elapsed().as_secs_f64() * 1000.0,
5329 segments,
5330 arrays,
5331 rows_scanned,
5332 checksum,
5333 non_null,
5334 }
5335 }
5336
5337 fn measure_probe_lowered_text(sheet: &ArrowSheet, rows: usize) -> Phase4ProbeOp {
5338 let view = sheet.range_view(0, 0, rows.saturating_sub(1), 0);
5339 let start = std::time::Instant::now();
5340 let mut segments = 0usize;
5341 let mut arrays = 0usize;
5342 let mut rows_scanned = 0usize;
5343 let mut checksum = 0.0;
5344 let mut non_null = 0usize;
5345 for segment in view.lowered_text_slices() {
5346 let (_row_start, row_len, cols) = segment.unwrap();
5347 segments += 1;
5348 rows_scanned += row_len;
5349 for array in cols {
5350 arrays += 1;
5351 for idx in 0..array.len() {
5352 if array.is_valid(idx) {
5353 checksum += array.value(idx).len() as f64;
5354 non_null += 1;
5355 }
5356 }
5357 }
5358 }
5359 Phase4ProbeOp {
5360 ms: start.elapsed().as_secs_f64() * 1000.0,
5361 segments,
5362 arrays,
5363 rows_scanned,
5364 checksum,
5365 non_null,
5366 }
5367 }
5368
5369 fn literal_probe_weight(value: LiteralValue) -> f64 {
5370 match value {
5371 LiteralValue::Empty => 0.0,
5372 LiteralValue::Int(value) => value as f64,
5373 LiteralValue::Number(value) => value,
5374 LiteralValue::Boolean(value) => {
5375 if value {
5376 1.0
5377 } else {
5378 0.0
5379 }
5380 }
5381 LiteralValue::Text(value) => value.len() as f64,
5382 LiteralValue::Error(_) => -1.0,
5383 LiteralValue::Date(value) => value.num_days_from_ce() as f64,
5384 LiteralValue::DateTime(value) => value.and_utc().timestamp() as f64,
5385 LiteralValue::Time(value) => value.num_seconds_from_midnight() as f64,
5386 LiteralValue::Duration(value) => value.num_seconds() as f64,
5387 LiteralValue::Array(values) => values.len() as f64,
5388 LiteralValue::Pending => -2.0,
5389 }
5390 }
5391
5392 fn measure_probe_get_cell(sheet: &ArrowSheet, rows: usize) -> Phase4ProbeOp {
5393 let view = sheet.range_view(0, 0, rows.saturating_sub(1), 0);
5394 let start = std::time::Instant::now();
5395 let mut checksum = 0.0;
5396 for row in 0..rows {
5397 checksum += literal_probe_weight(view.get_cell(row, 0));
5398 }
5399 Phase4ProbeOp {
5400 ms: start.elapsed().as_secs_f64() * 1000.0,
5401 segments: 1,
5402 arrays: 0,
5403 rows_scanned: rows,
5404 checksum,
5405 non_null: rows,
5406 }
5407 }
5408
5409 fn run_phase4_probe_fixture(rows: usize, fixture: Phase4ProbeFixture) -> Phase4ProbeRow {
5410 let sheet = build_phase4_probe_sheet(rows, fixture);
5411 assert_column_overlays_normalized(&sheet, 0);
5412 let stats = column_overlay_stats(&sheet, 0, true);
5413 reset_overlay_select_stats();
5414 let numbers = measure_probe_numbers(&sheet, rows);
5415 let type_tags = measure_probe_type_tags(&sheet, rows);
5416 let lowered_text = measure_probe_lowered_text(&sheet, rows);
5417 let select_stats = snapshot_overlay_select_stats();
5418 let get_cell_scan = measure_probe_get_cell(&sheet, rows);
5419 Phase4ProbeRow {
5420 fixture: fixture.name(),
5421 rows,
5422 points: stats.points,
5423 sparse_fragments: stats.sparse_fragments,
5424 dense_fragments: stats.dense_fragments,
5425 run_fragments: stats.run_fragments,
5426 covered_len: stats.covered_len,
5427 overlay_estimated_bytes: column_computed_overlay_estimated_bytes(&sheet, 0),
5428 numbers,
5429 type_tags,
5430 lowered_text,
5431 get_cell_scan,
5432 select_stats,
5433 }
5434 }
5435
5436 #[test]
5437 #[ignore = "manual Phase 4 observability probe; run with --ignored --nocapture"]
5438 fn phase4_overlay_rangeview_observability_probe() {
5439 let rows = std::env::var("FORMUALIZER_OVERLAY_PROBE_ROWS")
5440 .ok()
5441 .and_then(|value| value.parse::<usize>().ok())
5442 .unwrap_or(100_000)
5443 .max(1);
5444 for fixture in [
5445 Phase4ProbeFixture::PointNumeric,
5446 Phase4ProbeFixture::DenseNumeric,
5447 Phase4ProbeFixture::RunNumeric,
5448 Phase4ProbeFixture::SparseNumeric,
5449 Phase4ProbeFixture::EmptyRun,
5450 Phase4ProbeFixture::MixedDense,
5451 ] {
5452 let row = run_phase4_probe_fixture(rows, fixture);
5453 println!("{}", serde_json::to_string(&row).unwrap());
5454 }
5455 }
5456
5457 #[test]
5458 fn ingest_mixed_rows_into_lanes_and_tags() {
5459 let mut b = IngestBuilder::new("Sheet1", 1, 1024, crate::engine::DateSystem::Excel1900);
5460 let data = vec![
5461 LiteralValue::Number(42.5), LiteralValue::Empty, LiteralValue::Text(String::new()), LiteralValue::Boolean(true), LiteralValue::Error(ExcelError::new_value()), ];
5467 for v in &data {
5468 b.append_row(std::slice::from_ref(v)).unwrap();
5469 }
5470 let sheet = b.finish();
5471 assert_eq!(sheet.nrows, 5);
5472 assert_eq!(sheet.columns.len(), 1);
5473 assert_eq!(sheet.columns[0].chunks.len(), 1);
5474 let ch = &sheet.columns[0].chunks[0];
5475
5476 let tags = ch.type_tag.values();
5478 assert_eq!(tags.len(), 5);
5479 assert_eq!(tags[0], TypeTag::Number as u8);
5480 assert_eq!(tags[1], TypeTag::Empty as u8);
5481 assert_eq!(tags[2], TypeTag::Text as u8);
5482 assert_eq!(tags[3], TypeTag::Boolean as u8);
5483 assert_eq!(tags[4], TypeTag::Error as u8);
5484
5485 let nums = ch.numbers.as_ref().unwrap();
5487 assert_eq!(nums.len(), 5);
5488 assert_eq!(nums.null_count(), 4);
5489 assert!(nums.is_valid(0));
5490
5491 let bools = ch.booleans.as_ref().unwrap();
5493 assert_eq!(bools.len(), 5);
5494 assert_eq!(bools.null_count(), 4);
5495 assert!(bools.is_valid(3));
5496
5497 let txt = ch.text.as_ref().unwrap();
5499 assert_eq!(txt.len(), 5);
5500 assert_eq!(txt.null_count(), 4);
5501 assert!(txt.is_valid(2)); let errs = ch.errors.as_ref().unwrap();
5505 assert_eq!(errs.len(), 5);
5506 assert_eq!(errs.null_count(), 4);
5507 assert!(errs.is_valid(4));
5508 }
5509
5510 #[test]
5511 fn range_view_get_cell_and_padding() {
5512 let mut b = IngestBuilder::new("S", 2, 2, crate::engine::DateSystem::Excel1900);
5513 b.append_row(&[LiteralValue::Number(1.0), LiteralValue::Text("".into())])
5514 .unwrap();
5515 b.append_row(&[LiteralValue::Empty, LiteralValue::Text("x".into())])
5516 .unwrap();
5517 b.append_row(&[LiteralValue::Boolean(true), LiteralValue::Empty])
5518 .unwrap();
5519 let sheet = b.finish();
5520 let rv = sheet.range_view(0, 0, 2, 1);
5521 assert_eq!(rv.dims(), (3, 2));
5522 assert_eq!(rv.get_cell(0, 0), LiteralValue::Number(1.0));
5524 assert_eq!(rv.get_cell(0, 1), LiteralValue::Text(String::new())); assert_eq!(rv.get_cell(1, 0), LiteralValue::Empty); assert_eq!(rv.get_cell(2, 0), LiteralValue::Boolean(true));
5527 assert_eq!(rv.get_cell(3, 0), LiteralValue::Empty);
5529 assert_eq!(rv.get_cell(0, 2), LiteralValue::Empty);
5530
5531 let nums: Vec<_> = rv.numbers_slices().map(|r| r.unwrap()).collect();
5533 assert_eq!(nums.len(), 2);
5534 assert_eq!(nums[0].0, 0);
5535 assert_eq!(nums[0].1, 2);
5536 assert_eq!(nums[1].0, 2);
5537 assert_eq!(nums[1].1, 1);
5538 }
5539
5540 #[test]
5541 fn overlay_precedence_user_over_computed() {
5542 let mut b = IngestBuilder::new("S", 1, 8, crate::engine::DateSystem::Excel1900);
5543 b.append_row(&[LiteralValue::Number(1.0)]).unwrap();
5544 b.append_row(&[LiteralValue::Empty]).unwrap();
5545 b.append_row(&[LiteralValue::Empty]).unwrap();
5546 let mut sheet = b.finish();
5547
5548 let (ch_i, off) = sheet.chunk_of_row(0).unwrap();
5549 sheet.columns[0].chunks[ch_i]
5550 .computed_overlay
5551 .set(off, OverlayValue::Number(2.0));
5552
5553 let rv0 = sheet.range_view(0, 0, 0, 0);
5554 assert_eq!(rv0.get_cell(0, 0), LiteralValue::Number(2.0));
5555 let nums0: Vec<_> = rv0.numbers_slices().map(|r| r.unwrap()).collect();
5556 assert_eq!(nums0.len(), 1);
5557 assert_eq!(nums0[0].2[0].value(0), 2.0);
5558
5559 sheet.columns[0].chunks[ch_i]
5560 .overlay
5561 .set(off, OverlayValue::Number(3.0));
5562
5563 let rv1 = sheet.range_view(0, 0, 0, 0);
5564 assert_eq!(rv1.get_cell(0, 0), LiteralValue::Number(3.0));
5565 let nums1: Vec<_> = rv1.numbers_slices().map(|r| r.unwrap()).collect();
5566 assert_eq!(nums1.len(), 1);
5567 assert_eq!(nums1[0].2[0].value(0), 3.0);
5568 }
5569
5570 #[test]
5571 fn overlay_slice_preserves_explicit_empty_and_offsets() {
5572 let mut overlay = Overlay::new();
5573 overlay.set(2, OverlayValue::Number(2.0));
5574 overlay.set(4, OverlayValue::Empty);
5575 overlay.set(6, OverlayValue::Text(Arc::from("outside")));
5576
5577 let sliced = overlay.slice(1, 4);
5578 assert!(sliced.get_scalar(0).is_none());
5579 assert_eq!(
5580 sliced.get_scalar(1).unwrap().to_literal(),
5581 LiteralValue::Number(2.0)
5582 );
5583 assert_eq!(
5584 sliced.get_scalar(3).unwrap().to_literal(),
5585 LiteralValue::Empty
5586 );
5587 assert!(sliced.get_scalar(5).is_none());
5588 }
5589
5590 #[test]
5591 fn overlay_cascade_user_empty_masks_computed_and_base() {
5592 let mut user = Overlay::new();
5593 let mut computed = Overlay::new();
5594 computed.set(1, OverlayValue::Number(42.0));
5595 user.set(1, OverlayValue::Empty);
5596
5597 let cascade = OverlayCascade::new(&user, &computed);
5598 assert_eq!(
5599 cascade.get_scalar(1).unwrap().to_literal(),
5600 LiteralValue::Empty
5601 );
5602 assert!(cascade.has_any_in_range(1..2));
5603 }
5604
5605 #[test]
5606 fn overlay_storage_pointmap_backward_compat_get_set_remove() {
5607 let mut overlay = Overlay::new();
5608 assert!(overlay.is_empty());
5609
5610 let delta = overlay.set_scalar(1, OverlayValue::Number(10.0));
5611 assert!(delta > 0);
5612 assert_eq!(overlay.len(), 1);
5613 assert_eq!(
5614 overlay.get_scalar(1).unwrap().to_literal(),
5615 LiteralValue::Number(10.0)
5616 );
5617
5618 let replace_delta = overlay.set_scalar(1, OverlayValue::Text(Arc::from("x")));
5619 assert_ne!(replace_delta, 0);
5620 assert_eq!(overlay.len(), 1);
5621 assert_eq!(
5622 overlay.get_scalar(1).unwrap().to_literal(),
5623 LiteralValue::Text("x".into())
5624 );
5625
5626 let remove_delta = overlay.remove_scalar(1);
5627 assert!(remove_delta < 0);
5628 assert!(overlay.is_empty());
5629 assert!(overlay.get_scalar(1).is_none());
5630 }
5631
5632 #[test]
5633 fn overlay_remove_range_splits_fragments_and_points() {
5634 let mut overlay = Overlay::new();
5635 overlay.set_scalar(2, OverlayValue::Number(20.0));
5636 overlay.apply_fragment(
5637 OverlayFragment::dense_range(
5638 0,
5639 (0..6)
5640 .map(|i| OverlayValue::Number(i as f64))
5641 .collect::<Vec<_>>(),
5642 )
5643 .unwrap(),
5644 );
5645 overlay.set_scalar(3, OverlayValue::Number(30.0));
5646 overlay.set_scalar(8, OverlayValue::Number(80.0));
5647
5648 let delta = overlay.remove_range(2..5);
5649
5650 assert!(delta < 0);
5651 assert_eq!(
5652 overlay.get_scalar(0).unwrap().to_literal(),
5653 LiteralValue::Number(0.0)
5654 );
5655 assert_eq!(
5656 overlay.get_scalar(1).unwrap().to_literal(),
5657 LiteralValue::Number(1.0)
5658 );
5659 assert!(overlay.get_scalar(2).is_none());
5660 assert!(overlay.get_scalar(3).is_none());
5661 assert!(overlay.get_scalar(4).is_none());
5662 assert_eq!(
5663 overlay.get_scalar(5).unwrap().to_literal(),
5664 LiteralValue::Number(5.0)
5665 );
5666 assert_eq!(
5667 overlay.get_scalar(8).unwrap().to_literal(),
5668 LiteralValue::Number(80.0)
5669 );
5670 assert!(overlay.debug_is_normalized());
5671 assert_eq!(
5672 overlay.estimated_bytes(),
5673 overlay.debug_recomputed_estimated_bytes()
5674 );
5675 }
5676
5677 #[test]
5678 fn overlay_storage_no_fragments_behavior_matches_old_map() {
5679 let mut overlay = Overlay::new();
5680 overlay.set_scalar(0, OverlayValue::Number(1.0));
5681 overlay.set_scalar(3, OverlayValue::Empty);
5682
5683 assert!(overlay.has_any_in_range(0..1));
5684 assert!(!overlay.has_any_in_range(1..3));
5685 assert!(overlay.has_any_in_range(3..4));
5686
5687 let sliced = overlay.slice(2, 3);
5688 assert!(sliced.get_scalar(0).is_none());
5689 assert_eq!(
5690 sliced.get_scalar(1).unwrap().to_literal(),
5691 LiteralValue::Empty
5692 );
5693 }
5694
5695 #[test]
5696 fn overlay_cascade_user_layer_masks_computed_fragment_regardless_of_sequence() {
5697 let mut user = Overlay::new();
5698 let mut computed = Overlay::new();
5699
5700 user.set_scalar(0, OverlayValue::Number(3.0));
5701 computed.apply_fragment(
5702 OverlayFragment::dense_range(0, vec![OverlayValue::Number(2.0)]).unwrap(),
5703 );
5704
5705 let cascade = OverlayCascade::new(&user, &computed);
5706 assert_eq!(
5707 cascade.get_scalar(0).unwrap().to_literal(),
5708 LiteralValue::Number(3.0)
5709 );
5710 }
5711
5712 #[test]
5713 fn overlay_same_layer_later_point_replaces_fragment_cell() {
5714 let mut overlay = Overlay::new();
5715 overlay.apply_fragment(
5716 OverlayFragment::dense_range(
5717 0,
5718 vec![
5719 OverlayValue::Number(1.0),
5720 OverlayValue::Number(2.0),
5721 OverlayValue::Number(3.0),
5722 ],
5723 )
5724 .unwrap(),
5725 );
5726
5727 overlay.set_scalar(1, OverlayValue::Number(99.0));
5728
5729 assert_eq!(
5730 overlay.get_scalar(0).unwrap().to_literal(),
5731 LiteralValue::Number(1.0)
5732 );
5733 assert_eq!(
5734 overlay.get_scalar(1).unwrap().to_literal(),
5735 LiteralValue::Number(99.0)
5736 );
5737 assert_eq!(
5738 overlay.get_scalar(2).unwrap().to_literal(),
5739 LiteralValue::Number(3.0)
5740 );
5741 }
5742
5743 #[test]
5744 fn overlay_same_layer_later_fragment_replaces_point_range() {
5745 let mut overlay = Overlay::new();
5746 overlay.set_scalar(0, OverlayValue::Number(1.0));
5747 overlay.set_scalar(1, OverlayValue::Number(2.0));
5748 overlay.set_scalar(2, OverlayValue::Number(3.0));
5749
5750 overlay.apply_fragment(
5751 OverlayFragment::dense_range(
5752 0,
5753 vec![
5754 OverlayValue::Number(10.0),
5755 OverlayValue::Number(20.0),
5756 OverlayValue::Number(30.0),
5757 ],
5758 )
5759 .unwrap(),
5760 );
5761
5762 let stats = overlay.debug_stats();
5763 assert_eq!(stats.points, 0);
5764 assert_eq!(stats.dense_fragments, 1);
5765 assert!(overlay.debug_is_normalized());
5766 assert_eq!(
5767 overlay.get_scalar(0).unwrap().to_literal(),
5768 LiteralValue::Number(10.0)
5769 );
5770 assert_eq!(
5771 overlay.get_scalar(1).unwrap().to_literal(),
5772 LiteralValue::Number(20.0)
5773 );
5774 assert_eq!(
5775 overlay.get_scalar(2).unwrap().to_literal(),
5776 LiteralValue::Number(30.0)
5777 );
5778 }
5779
5780 #[test]
5781 fn overlay_sparse_far_apart_replacement_does_not_rewrite_unrelated_dense_fragment() {
5782 let mut overlay = Overlay::new();
5783 overlay.apply_fragment(
5784 OverlayFragment::dense_range(100, vec![OverlayValue::Number(1.0); 10]).unwrap(),
5785 );
5786
5787 overlay.apply_fragment(
5788 OverlayFragment::sparse_offsets(vec![
5789 (0, OverlayValue::Empty),
5790 (1000, OverlayValue::Number(1000.0)),
5791 ])
5792 .unwrap(),
5793 );
5794
5795 let stats = overlay.debug_stats();
5796 assert_eq!(stats.dense_fragments, 1);
5797 assert_eq!(stats.sparse_fragments, 1);
5798 assert_eq!(stats.run_fragments, 0);
5799 assert!(overlay.debug_is_normalized());
5800 assert_eq!(
5801 overlay.get_scalar(105).unwrap().to_literal(),
5802 LiteralValue::Number(1.0)
5803 );
5804 assert_eq!(
5805 overlay.get_scalar(0).unwrap().to_literal(),
5806 LiteralValue::Empty
5807 );
5808 assert_eq!(
5809 overlay.get_scalar(1000).unwrap().to_literal(),
5810 LiteralValue::Number(1000.0)
5811 );
5812 }
5813
5814 #[test]
5815 fn overlay_sparse_offsets_are_sorted_unique_last_write_wins() {
5816 let mut overlay = Overlay::new();
5817 overlay.apply_fragment(
5818 OverlayFragment::sparse_offsets(vec![
5819 (3, OverlayValue::Number(3.0)),
5820 (1, OverlayValue::Number(1.0)),
5821 (3, OverlayValue::Number(33.0)),
5822 ])
5823 .unwrap(),
5824 );
5825
5826 let stats = overlay.debug_stats();
5827 assert_eq!(stats.sparse_fragments, 1);
5828 assert_eq!(overlay.len(), 2);
5829 assert_eq!(
5830 overlay.get_scalar(1).unwrap().to_literal(),
5831 LiteralValue::Number(1.0)
5832 );
5833 assert_eq!(
5834 overlay.get_scalar(3).unwrap().to_literal(),
5835 LiteralValue::Number(33.0)
5836 );
5837 assert!(overlay.debug_is_normalized());
5838 }
5839
5840 #[test]
5841 fn overlay_dense_point_replacement_splits_dense_not_sparse() {
5842 let mut overlay = Overlay::new();
5843 overlay.apply_fragment(
5844 OverlayFragment::dense_range(
5845 0,
5846 (0..6)
5847 .map(|i| OverlayValue::Number(i as f64))
5848 .collect::<Vec<_>>(),
5849 )
5850 .unwrap(),
5851 );
5852
5853 overlay.set_scalar(3, OverlayValue::Number(99.0));
5854
5855 let stats = overlay.debug_stats();
5856 assert_eq!(stats.points, 1);
5857 assert_eq!(stats.dense_fragments, 2);
5858 assert_eq!(stats.sparse_fragments, 0);
5859 assert!(overlay.debug_is_normalized());
5860 assert_eq!(
5861 overlay.get_scalar(2).unwrap().to_literal(),
5862 LiteralValue::Number(2.0)
5863 );
5864 assert_eq!(
5865 overlay.get_scalar(3).unwrap().to_literal(),
5866 LiteralValue::Number(99.0)
5867 );
5868 assert_eq!(
5869 overlay.get_scalar(4).unwrap().to_literal(),
5870 LiteralValue::Number(4.0)
5871 );
5872 }
5873
5874 #[test]
5875 fn overlay_dense_fragment_replacement_splits_left_and_right_dense() {
5876 let mut overlay = Overlay::new();
5877 overlay.apply_fragment(
5878 OverlayFragment::dense_range(
5879 0,
5880 (0..8)
5881 .map(|i| OverlayValue::Number(i as f64))
5882 .collect::<Vec<_>>(),
5883 )
5884 .unwrap(),
5885 );
5886
5887 overlay.apply_fragment(
5888 OverlayFragment::dense_range(
5889 3,
5890 vec![OverlayValue::Number(30.0), OverlayValue::Number(40.0)],
5891 )
5892 .unwrap(),
5893 );
5894
5895 let stats = overlay.debug_stats();
5896 assert_eq!(stats.points, 0);
5897 assert_eq!(stats.dense_fragments, 3);
5898 assert_eq!(stats.sparse_fragments, 0);
5899 assert!(overlay.debug_is_normalized());
5900 assert_eq!(
5901 overlay.get_scalar(2).unwrap().to_literal(),
5902 LiteralValue::Number(2.0)
5903 );
5904 assert_eq!(
5905 overlay.get_scalar(3).unwrap().to_literal(),
5906 LiteralValue::Number(30.0)
5907 );
5908 assert_eq!(
5909 overlay.get_scalar(4).unwrap().to_literal(),
5910 LiteralValue::Number(40.0)
5911 );
5912 assert_eq!(
5913 overlay.get_scalar(5).unwrap().to_literal(),
5914 LiteralValue::Number(5.0)
5915 );
5916 }
5917
5918 #[test]
5919 fn overlay_run_point_replacement_splits_run_not_sparse() {
5920 let mut overlay = Overlay::new();
5921 overlay.apply_fragment(
5922 OverlayFragment::run_range(0, vec![OverlayValue::Number(1.0); 10]).unwrap(),
5923 );
5924
5925 overlay.set_scalar(5, OverlayValue::Number(99.0));
5926
5927 let stats = overlay.debug_stats();
5928 assert_eq!(stats.points, 1);
5929 assert_eq!(stats.run_fragments, 2);
5930 assert_eq!(stats.sparse_fragments, 0);
5931 assert!(overlay.debug_is_normalized());
5932 assert_eq!(
5933 overlay.get_scalar(4).unwrap().to_literal(),
5934 LiteralValue::Number(1.0)
5935 );
5936 assert_eq!(
5937 overlay.get_scalar(5).unwrap().to_literal(),
5938 LiteralValue::Number(99.0)
5939 );
5940 assert_eq!(
5941 overlay.get_scalar(6).unwrap().to_literal(),
5942 LiteralValue::Number(1.0)
5943 );
5944 }
5945
5946 #[test]
5947 fn overlay_run_fragment_replacement_splits_left_and_right_run() {
5948 let mut overlay = Overlay::new();
5949 let values = [
5950 vec![OverlayValue::Number(1.0); 4],
5951 vec![OverlayValue::Number(2.0); 4],
5952 vec![OverlayValue::Number(3.0); 4],
5953 ]
5954 .concat();
5955 overlay.apply_fragment(OverlayFragment::run_range(0, values).unwrap());
5956
5957 overlay.apply_fragment(
5958 OverlayFragment::dense_range(
5959 5,
5960 vec![OverlayValue::Number(50.0), OverlayValue::Number(60.0)],
5961 )
5962 .unwrap(),
5963 );
5964
5965 let stats = overlay.debug_stats();
5966 assert_eq!(stats.run_fragments, 2);
5967 assert_eq!(stats.dense_fragments, 1);
5968 assert_eq!(stats.sparse_fragments, 0);
5969 assert!(overlay.debug_is_normalized());
5970 assert_eq!(
5971 overlay.get_scalar(4).unwrap().to_literal(),
5972 LiteralValue::Number(2.0)
5973 );
5974 assert_eq!(
5975 overlay.get_scalar(5).unwrap().to_literal(),
5976 LiteralValue::Number(50.0)
5977 );
5978 assert_eq!(
5979 overlay.get_scalar(6).unwrap().to_literal(),
5980 LiteralValue::Number(60.0)
5981 );
5982 assert_eq!(
5983 overlay.get_scalar(7).unwrap().to_literal(),
5984 LiteralValue::Number(2.0)
5985 );
5986 }
5987
5988 #[test]
5989 fn overlay_slice_preserves_dense_and_run_encodings() {
5990 let mut overlay = Overlay::new();
5991 overlay.apply_fragment(
5992 OverlayFragment::dense_range(
5993 10,
5994 (0..5)
5995 .map(|i| OverlayValue::Number(i as f64))
5996 .collect::<Vec<_>>(),
5997 )
5998 .unwrap(),
5999 );
6000 overlay.apply_fragment(
6001 OverlayFragment::run_range(
6002 20,
6003 [
6004 vec![OverlayValue::Number(1.0); 3],
6005 vec![OverlayValue::Number(2.0); 3],
6006 ]
6007 .concat(),
6008 )
6009 .unwrap(),
6010 );
6011
6012 let dense_slice = overlay.slice(12, 2);
6013 let dense_stats = dense_slice.debug_stats();
6014 assert_eq!(dense_stats.dense_fragments, 1);
6015 assert_eq!(dense_stats.sparse_fragments, 0);
6016 assert_eq!(
6017 dense_slice.get_scalar(0).unwrap().to_literal(),
6018 LiteralValue::Number(2.0)
6019 );
6020 assert_eq!(
6021 dense_slice.get_scalar(1).unwrap().to_literal(),
6022 LiteralValue::Number(3.0)
6023 );
6024 assert!(dense_slice.debug_is_normalized());
6025
6026 let run_slice = overlay.slice(22, 3);
6027 let run_stats = run_slice.debug_stats();
6028 assert_eq!(run_stats.run_fragments, 1);
6029 assert_eq!(run_stats.sparse_fragments, 0);
6030 assert_eq!(
6031 run_slice.get_scalar(0).unwrap().to_literal(),
6032 LiteralValue::Number(1.0)
6033 );
6034 assert_eq!(
6035 run_slice.get_scalar(1).unwrap().to_literal(),
6036 LiteralValue::Number(2.0)
6037 );
6038 assert_eq!(
6039 run_slice.get_scalar(2).unwrap().to_literal(),
6040 LiteralValue::Number(2.0)
6041 );
6042 assert!(run_slice.debug_is_normalized());
6043 }
6044
6045 #[test]
6046 fn overlay_computed_empty_run_masks_non_empty_base() {
6047 let mut b = IngestBuilder::new("S", 1, 8, crate::engine::DateSystem::Excel1900);
6048 b.append_row(&[LiteralValue::Number(1.0)]).unwrap();
6049 b.append_row(&[LiteralValue::Number(2.0)]).unwrap();
6050 b.append_row(&[LiteralValue::Number(3.0)]).unwrap();
6051 let mut sheet = b.finish();
6052
6053 let (ch_i, _) = sheet.chunk_of_row(0).unwrap();
6054 sheet.columns[0].chunks[ch_i]
6055 .computed_overlay
6056 .apply_fragment(
6057 OverlayFragment::run_range(
6058 0,
6059 vec![
6060 OverlayValue::Empty,
6061 OverlayValue::Empty,
6062 OverlayValue::Empty,
6063 ],
6064 )
6065 .unwrap(),
6066 );
6067
6068 assert_eq!(sheet.get_cell_value(0, 0), LiteralValue::Empty);
6069 assert_eq!(sheet.get_cell_value(1, 0), LiteralValue::Empty);
6070 assert_eq!(sheet.get_cell_value(2, 0), LiteralValue::Empty);
6071 }
6072
6073 #[test]
6074 fn overlay_fragments_reconstruct_scalars_from_typed_lanes() {
6075 let values = vec![
6076 OverlayValue::Empty,
6077 OverlayValue::Number(1.5),
6078 OverlayValue::DateTime(45000.25),
6079 OverlayValue::Duration(0.5),
6080 OverlayValue::Boolean(true),
6081 OverlayValue::Text(Arc::from("Hello")),
6082 OverlayValue::Error(map_error_code(ExcelErrorKind::Div)),
6083 OverlayValue::Pending,
6084 ];
6085
6086 let mut dense = Overlay::new();
6087 dense.apply_fragment(OverlayFragment::dense_range(0, values.clone()).unwrap());
6088 for (idx, expected) in values.iter().enumerate() {
6089 assert_eq!(
6090 dense.get_scalar(idx).unwrap().to_overlay_value(),
6091 expected.clone()
6092 );
6093 }
6094
6095 let mut sparse = Overlay::new();
6096 sparse.apply_fragment(
6097 OverlayFragment::sparse_offsets(
6098 values
6099 .iter()
6100 .cloned()
6101 .enumerate()
6102 .map(|(idx, value)| (idx * 2, value))
6103 .collect(),
6104 )
6105 .unwrap(),
6106 );
6107 for (idx, expected) in values.iter().enumerate() {
6108 assert_eq!(
6109 sparse.get_scalar(idx * 2).unwrap().to_overlay_value(),
6110 expected.clone()
6111 );
6112 }
6113
6114 let mut run = Overlay::new();
6115 run.apply_fragment(
6116 OverlayFragment::run_range(
6117 0,
6118 vec![
6119 OverlayValue::Number(7.0),
6120 OverlayValue::Number(7.0),
6121 OverlayValue::Text(Arc::from("run")),
6122 OverlayValue::Text(Arc::from("run")),
6123 ],
6124 )
6125 .unwrap(),
6126 );
6127 assert_eq!(
6128 run.get_scalar(0).unwrap().to_overlay_value(),
6129 OverlayValue::Number(7.0)
6130 );
6131 assert_eq!(
6132 run.get_scalar(2).unwrap().to_overlay_value(),
6133 OverlayValue::Text(Arc::from("run"))
6134 );
6135 }
6136
6137 #[test]
6138 fn overlay_iter_returns_complete_logical_entries() {
6139 let mut overlay = Overlay::new();
6140 overlay.apply_fragment(
6141 OverlayFragment::dense_range(
6142 2,
6143 vec![OverlayValue::Number(2.0), OverlayValue::Number(3.0)],
6144 )
6145 .unwrap(),
6146 );
6147 overlay.set_scalar(5, OverlayValue::Text(Arc::from("point")));
6148
6149 let entries: Vec<_> = overlay.iter().collect();
6150 assert_eq!(
6151 entries,
6152 vec![
6153 (2, OverlayValue::Number(2.0)),
6154 (3, OverlayValue::Number(3.0)),
6155 (5, OverlayValue::Text(Arc::from("point"))),
6156 ]
6157 );
6158 assert_eq!(overlay.iter_points().count(), 1);
6159 }
6160
6161 #[test]
6162 fn overlay_fragment_estimates_follow_encoded_shapes() {
6163 let mut points = Overlay::new();
6164 for idx in 0..512 {
6165 points.set_scalar(idx, OverlayValue::Number(idx as f64));
6166 }
6167
6168 let mut dense = Overlay::new();
6169 dense.apply_fragment(
6170 OverlayFragment::dense_range(
6171 0,
6172 (0..512)
6173 .map(|idx| OverlayValue::Number(idx as f64))
6174 .collect::<Vec<_>>(),
6175 )
6176 .unwrap(),
6177 );
6178 assert_eq!(
6179 dense.estimated_bytes(),
6180 dense.debug_recomputed_estimated_bytes()
6181 );
6182 assert!(
6183 dense.estimated_bytes() < points.estimated_bytes(),
6184 "dense fragment should account like encoded lanes, not point-map entries"
6185 );
6186
6187 let mut short_run = Overlay::new();
6188 short_run.apply_fragment(
6189 OverlayFragment::run_range(0, vec![OverlayValue::Number(1.0); 8]).unwrap(),
6190 );
6191 let mut long_run = Overlay::new();
6192 long_run.apply_fragment(
6193 OverlayFragment::run_range(0, vec![OverlayValue::Number(1.0); 4096]).unwrap(),
6194 );
6195 assert_eq!(
6196 short_run.estimated_bytes(),
6197 short_run.debug_recomputed_estimated_bytes()
6198 );
6199 assert_eq!(
6200 long_run.estimated_bytes(),
6201 long_run.debug_recomputed_estimated_bytes()
6202 );
6203 assert_eq!(
6204 short_run.estimated_bytes(),
6205 long_run.estimated_bytes(),
6206 "single-run estimate should scale with run count, not covered rows"
6207 );
6208
6209 let sparse10 = OverlayFragment::sparse_offsets(
6210 (0..10)
6211 .map(|idx| (idx * 3, OverlayValue::Number(idx as f64)))
6212 .collect(),
6213 )
6214 .unwrap();
6215 let sparse20 = OverlayFragment::sparse_offsets(
6216 (0..20)
6217 .map(|idx| (idx * 3, OverlayValue::Number(idx as f64)))
6218 .collect(),
6219 )
6220 .unwrap();
6221 assert!(sparse20.estimated_bytes() > sparse10.estimated_bytes());
6222 }
6223
6224 #[test]
6225 fn overlay_estimated_bytes_stay_consistent_after_split_and_clear() {
6226 let mut overlay = Overlay::new();
6227 overlay.apply_fragment(
6228 OverlayFragment::dense_range(
6229 0,
6230 (0..16)
6231 .map(|idx| OverlayValue::Number(idx as f64))
6232 .collect::<Vec<_>>(),
6233 )
6234 .unwrap(),
6235 );
6236 assert_eq!(
6237 overlay.estimated_bytes(),
6238 overlay.debug_recomputed_estimated_bytes()
6239 );
6240
6241 overlay.set_scalar(8, OverlayValue::Text(Arc::from("split")));
6242 assert!(overlay.debug_is_normalized());
6243 assert_eq!(
6244 overlay.estimated_bytes(),
6245 overlay.debug_recomputed_estimated_bytes()
6246 );
6247
6248 overlay.apply_fragment(
6249 OverlayFragment::sparse_offsets(vec![
6250 (0, OverlayValue::Empty),
6251 (15, OverlayValue::Boolean(true)),
6252 ])
6253 .unwrap(),
6254 );
6255 assert!(overlay.debug_is_normalized());
6256 assert_eq!(
6257 overlay.estimated_bytes(),
6258 overlay.debug_recomputed_estimated_bytes()
6259 );
6260
6261 let freed = overlay.clear_all();
6262 assert!(freed > 0);
6263 assert_eq!(overlay.estimated_bytes(), 0);
6264 assert_eq!(overlay.debug_recomputed_estimated_bytes(), 0);
6265 assert!(overlay.is_empty());
6266 }
6267
6268 #[test]
6269 fn overlay_segment_numbers_masks_base_for_non_numeric_overlays() {
6270 let mut user = Overlay::new();
6271 user.set(1, OverlayValue::Text(Arc::from("x")));
6272 user.set(2, OverlayValue::Empty);
6273 user.set(3, OverlayValue::Error(map_error_code(ExcelErrorKind::Div)));
6274 user.set(4, OverlayValue::Pending);
6275 let computed = Overlay::new();
6276 let cascade = OverlayCascade::new(&user, &computed);
6277
6278 let base = Float64Array::from(vec![10.0, 20.0, 30.0, 40.0, 50.0]);
6279 let selected = cascade.select_numbers(0..5, &base);
6280 assert_eq!(selected.value(0), 10.0);
6281 assert!(selected.is_null(1));
6282 assert!(selected.is_null(2));
6283 assert!(selected.is_null(3));
6284 assert!(selected.is_null(4));
6285 }
6286
6287 #[test]
6288 fn overlay_segment_type_tags_preserve_temporal_tags() {
6289 let mut computed = Overlay::new();
6290 computed.set(0, OverlayValue::DateTime(45000.5));
6291 computed.set(1, OverlayValue::Duration(0.25));
6292 let user = Overlay::new();
6293 let cascade = OverlayCascade::new(&user, &computed);
6294
6295 let base = UInt8Array::from(vec![TypeTag::Empty as u8; 2]);
6296 let selected = cascade.select_type_tags(0..2, &base);
6297 assert_eq!(selected.value(0), TypeTag::DateTime as u8);
6298 assert_eq!(selected.value(1), TypeTag::Duration as u8);
6299 }
6300
6301 #[test]
6302 fn overlay_lowered_text_matches_existing_overlay_semantics() {
6303 let mut user = Overlay::new();
6304 user.set(0, OverlayValue::Text(Arc::from("HeLLo")));
6305 user.set(1, OverlayValue::Number(1.5));
6306 user.set(2, OverlayValue::Boolean(true));
6307 user.set(3, OverlayValue::Empty);
6308 let computed = Overlay::new();
6309 let cascade = OverlayCascade::new(&user, &computed);
6310
6311 let base = StringArray::from(vec![Some("A"), Some("B"), Some("C"), Some("D")]);
6312 let selected = cascade.select_lowered_text(0..4, &base);
6313 assert_eq!(selected.value(0), "hello");
6314 assert_eq!(selected.value(1), "1.5");
6315 assert_eq!(selected.value(2), "true");
6316 assert!(selected.is_null(3));
6317 }
6318
6319 fn numeric_sheet(rows: usize) -> ArrowSheet {
6320 let mut b = IngestBuilder::new("S", 1, rows.max(1), crate::engine::DateSystem::Excel1900);
6321 for row in 0..rows {
6322 b.append_row(&[LiteralValue::Number((row + 1) as f64)])
6323 .unwrap();
6324 }
6325 b.finish()
6326 }
6327
6328 fn numbers_for_range(sheet: &ArrowSheet, sr: usize, er: usize) -> Arc<Float64Array> {
6329 let view = sheet.range_view(sr, 0, er, 0);
6330 let segments: Vec<_> = view.numbers_slices().map(|res| res.unwrap()).collect();
6331 assert_eq!(segments.len(), 1);
6332 assert_eq!(segments[0].2.len(), 1);
6333 segments[0].2[0].clone()
6334 }
6335
6336 fn type_tags_for_range(sheet: &ArrowSheet, sr: usize, er: usize) -> Arc<UInt8Array> {
6337 let view = sheet.range_view(sr, 0, er, 0);
6338 let segments: Vec<_> = view.type_tags_slices().map(|res| res.unwrap()).collect();
6339 assert_eq!(segments.len(), 1);
6340 assert_eq!(segments[0].2.len(), 1);
6341 segments[0].2[0].clone()
6342 }
6343
6344 fn lowered_for_range(sheet: &ArrowSheet, sr: usize, er: usize) -> Arc<StringArray> {
6345 let view = sheet.range_view(sr, 0, er, 0);
6346 let segments: Vec<_> = view.lowered_text_slices().map(|res| res.unwrap()).collect();
6347 assert_eq!(segments.len(), 1);
6348 assert_eq!(segments[0].2.len(), 1);
6349 segments[0].2[0].clone()
6350 }
6351
6352 #[test]
6353 fn rangeview_dense_text_masks_base_numbers() {
6354 let mut sheet = numeric_sheet(4);
6355 sheet.columns[0].chunks[0].computed_overlay.apply_fragment(
6356 OverlayFragment::dense_range(
6357 0,
6358 vec![
6359 OverlayValue::Text(Arc::from("x")),
6360 OverlayValue::Text(Arc::from("y")),
6361 OverlayValue::Text(Arc::from("z")),
6362 OverlayValue::Text(Arc::from("w")),
6363 ],
6364 )
6365 .unwrap(),
6366 );
6367
6368 reset_overlay_select_stats();
6369 let numbers = numbers_for_range(&sheet, 0, 3);
6370 assert_eq!(numbers.null_count(), 4);
6371 let stats = snapshot_overlay_select_stats();
6372 assert_eq!(stats.direct_dense_slices, 1);
6373 assert_eq!(stats.zip_select_calls, 0);
6374 }
6375
6376 #[test]
6377 fn rangeview_empty_dense_masks_base_all_selectors() {
6378 let mut sheet = numeric_sheet(3);
6379 sheet.columns[0].chunks[0]
6380 .computed_overlay
6381 .apply_fragment(OverlayFragment::dense_range(0, vec![OverlayValue::Empty; 3]).unwrap());
6382
6383 reset_overlay_select_stats();
6384 let numbers = numbers_for_range(&sheet, 0, 2);
6385 let type_tags = type_tags_for_range(&sheet, 0, 2);
6386 let lowered = lowered_for_range(&sheet, 0, 2);
6387 assert_eq!(numbers.null_count(), 3);
6388 assert_eq!(lowered.null_count(), 3);
6389 assert_eq!(type_tags.values(), &[TypeTag::Empty as u8; 3]);
6390 let stats = snapshot_overlay_select_stats();
6391 assert_eq!(stats.direct_dense_slices, 3);
6392 assert_eq!(stats.zip_select_calls, 0);
6393 }
6394
6395 #[test]
6396 fn rangeview_pending_masks_base_type_tag_present_lanes_null() {
6397 let mut sheet = numeric_sheet(2);
6398 sheet.columns[0].chunks[0].computed_overlay.apply_fragment(
6399 OverlayFragment::dense_range(0, vec![OverlayValue::Pending; 2]).unwrap(),
6400 );
6401
6402 reset_overlay_select_stats();
6403 let numbers = numbers_for_range(&sheet, 0, 1);
6404 let type_tags = type_tags_for_range(&sheet, 0, 1);
6405 let lowered = lowered_for_range(&sheet, 0, 1);
6406 assert_eq!(numbers.null_count(), 2);
6407 assert_eq!(lowered.null_count(), 2);
6408 assert_eq!(type_tags.values(), &[TypeTag::Pending as u8; 2]);
6409 let stats = snapshot_overlay_select_stats();
6410 assert_eq!(stats.direct_dense_slices, 3);
6411 assert_eq!(stats.zip_select_calls, 0);
6412 }
6413
6414 #[test]
6415 fn rangeview_subrange_inside_dense_fragment_uses_direct_path() {
6416 let mut sheet = numeric_sheet(10);
6417 sheet.columns[0].chunks[0].computed_overlay.apply_fragment(
6418 OverlayFragment::dense_range(
6419 0,
6420 (0..10)
6421 .map(|row| OverlayValue::Number((row + 10) as f64))
6422 .collect(),
6423 )
6424 .unwrap(),
6425 );
6426
6427 reset_overlay_select_stats();
6428 let numbers = numbers_for_range(&sheet, 2, 6);
6429 assert_eq!(numbers.len(), 5);
6430 assert_eq!(numbers.value(0), 12.0);
6431 assert_eq!(numbers.value(4), 16.0);
6432 let stats = snapshot_overlay_select_stats();
6433 assert_eq!(stats.direct_dense_slices, 1);
6434 assert_eq!(stats.zip_select_calls, 0);
6435 }
6436
6437 #[test]
6438 fn rangeview_subrange_inside_run_fragment_uses_direct_path() {
6439 let mut sheet = numeric_sheet(10);
6440 sheet.columns[0].chunks[0].computed_overlay.apply_fragment(
6441 OverlayFragment::run_range(0, vec![OverlayValue::Number(7.0); 10]).unwrap(),
6442 );
6443
6444 reset_overlay_select_stats();
6445 let numbers = numbers_for_range(&sheet, 2, 6);
6446 assert_eq!(numbers.len(), 5);
6447 for idx in 0..numbers.len() {
6448 assert_eq!(numbers.value(idx), 7.0);
6449 }
6450 let stats = snapshot_overlay_select_stats();
6451 assert_eq!(stats.direct_run_materializations, 1);
6452 assert_eq!(stats.zip_select_calls, 0);
6453 }
6454
6455 #[test]
6456 fn rangeview_user_partial_wrong_type_masks_computed_numeric() {
6457 let mut sheet = numeric_sheet(5);
6458 let chunk = &mut sheet.columns[0].chunks[0];
6459 chunk.computed_overlay.apply_fragment(
6460 OverlayFragment::dense_range(
6461 0,
6462 (0..5)
6463 .map(|row| OverlayValue::Number((row + 10) as f64))
6464 .collect(),
6465 )
6466 .unwrap(),
6467 );
6468 chunk.overlay.apply_fragment(
6469 OverlayFragment::dense_range(2, vec![OverlayValue::Text(Arc::from("mask"))]).unwrap(),
6470 );
6471
6472 reset_overlay_select_stats();
6473 let numbers = numbers_for_range(&sheet, 0, 4);
6474 assert_eq!(numbers.value(0), 10.0);
6475 assert_eq!(numbers.value(1), 11.0);
6476 assert!(numbers.is_null(2));
6477 assert_eq!(numbers.value(3), 13.0);
6478 assert_eq!(numbers.value(4), 14.0);
6479 let stats = snapshot_overlay_select_stats();
6480 assert_eq!(stats.direct_dense_slices, 0);
6481 assert_eq!(stats.zip_select_calls, 1);
6482 assert_eq!(stats.partial_dense_intersections, 2);
6483 }
6484
6485 #[test]
6486 fn rangeview_computed_full_cover_user_no_overlap_uses_computed_direct() {
6487 let mut sheet = numeric_sheet(5);
6488 let chunk = &mut sheet.columns[0].chunks[0];
6489 chunk.computed_overlay.apply_fragment(
6490 OverlayFragment::dense_range(0, vec![OverlayValue::Number(3.0); 5]).unwrap(),
6491 );
6492 chunk
6493 .overlay
6494 .set_scalar(10, OverlayValue::Text(Arc::from("outside")));
6495
6496 reset_overlay_select_stats();
6497 let numbers = numbers_for_range(&sheet, 0, 4);
6498 assert_eq!(numbers.value(0), 3.0);
6499 assert_eq!(numbers.value(4), 3.0);
6500 let stats = snapshot_overlay_select_stats();
6501 assert_eq!(stats.direct_dense_slices, 1);
6502 assert_eq!(stats.zip_select_calls, 0);
6503 }
6504
6505 #[test]
6506 fn rangeview_user_full_cover_ignores_computed() {
6507 let mut sheet = numeric_sheet(4);
6508 let chunk = &mut sheet.columns[0].chunks[0];
6509 chunk.computed_overlay.apply_fragment(
6510 OverlayFragment::dense_range(0, vec![OverlayValue::Number(99.0); 4]).unwrap(),
6511 );
6512 chunk.overlay.apply_fragment(
6513 OverlayFragment::dense_range(0, vec![OverlayValue::Text(Arc::from("user")); 4])
6514 .unwrap(),
6515 );
6516
6517 reset_overlay_select_stats();
6518 let numbers = numbers_for_range(&sheet, 0, 3);
6519 assert_eq!(numbers.null_count(), 4);
6520 let stats = snapshot_overlay_select_stats();
6521 assert_eq!(stats.direct_dense_slices, 1);
6522 assert_eq!(stats.zip_select_calls, 0);
6523 }
6524
6525 #[test]
6526 fn rangeview_point_overlay_still_matches_legacy_scalar_path() {
6527 let mut sheet = numeric_sheet(3);
6528 sheet.columns[0].chunks[0]
6529 .computed_overlay
6530 .set_scalar(1, OverlayValue::Text(Arc::from("point")));
6531
6532 reset_overlay_select_stats();
6533 let numbers = numbers_for_range(&sheet, 0, 2);
6534 assert_eq!(numbers.value(0), 1.0);
6535 assert!(numbers.is_null(1));
6536 assert_eq!(numbers.value(2), 3.0);
6537 let stats = snapshot_overlay_select_stats();
6538 assert_eq!(stats.zip_select_calls, 1);
6539 assert_eq!(stats.point_entries_applied, 1);
6540 assert_eq!(stats.row_scalar_fallbacks, 0);
6541 }
6542
6543 #[test]
6544 fn rangeview_multi_fragment_full_union_does_not_use_direct_path() {
6545 let mut sheet = numeric_sheet(4);
6546 let chunk = &mut sheet.columns[0].chunks[0];
6547 chunk.computed_overlay.apply_fragment(
6548 OverlayFragment::dense_range(0, vec![OverlayValue::Number(10.0); 2]).unwrap(),
6549 );
6550 chunk.computed_overlay.apply_fragment(
6551 OverlayFragment::dense_range(2, vec![OverlayValue::Number(20.0); 2]).unwrap(),
6552 );
6553
6554 reset_overlay_select_stats();
6555 let numbers = numbers_for_range(&sheet, 0, 3);
6556 assert_eq!(numbers.value(0), 10.0);
6557 assert_eq!(numbers.value(1), 10.0);
6558 assert_eq!(numbers.value(2), 20.0);
6559 assert_eq!(numbers.value(3), 20.0);
6560 let stats = snapshot_overlay_select_stats();
6561 assert_eq!(stats.direct_dense_slices, 0);
6562 assert_eq!(stats.zip_select_calls, 1);
6563 assert_eq!(stats.partial_dense_intersections, 2);
6564 }
6565
6566 #[test]
6567 fn rangeview_lowered_text_fragment_semantics_match_scalar_semantics() {
6568 let mut sheet = numeric_sheet(8);
6569 sheet.columns[0].chunks[0].computed_overlay.apply_fragment(
6570 OverlayFragment::dense_range(
6571 0,
6572 vec![
6573 OverlayValue::Text(Arc::from("HeLLo")),
6574 OverlayValue::Number(1.5),
6575 OverlayValue::DateTime(45000.25),
6576 OverlayValue::Duration(0.5),
6577 OverlayValue::Boolean(true),
6578 OverlayValue::Empty,
6579 OverlayValue::Error(map_error_code(ExcelErrorKind::Div)),
6580 OverlayValue::Pending,
6581 ],
6582 )
6583 .unwrap(),
6584 );
6585
6586 reset_overlay_select_stats();
6587 let lowered = lowered_for_range(&sheet, 0, 7);
6588 assert_eq!(lowered.value(0), "hello");
6589 assert_eq!(lowered.value(1), "1.5");
6590 assert_eq!(lowered.value(2), "45000.25");
6591 assert_eq!(lowered.value(3), "0.5");
6592 assert_eq!(lowered.value(4), "true");
6593 assert!(lowered.is_null(5));
6594 assert!(lowered.is_null(6));
6595 assert!(lowered.is_null(7));
6596 let stats = snapshot_overlay_select_stats();
6597 assert_eq!(stats.direct_dense_slices, 1);
6598 assert_eq!(stats.zip_select_calls, 0);
6599 }
6600
6601 #[test]
6602 fn row_chunk_slices_shape() {
6603 let mut b = IngestBuilder::new("S", 2, 2, crate::engine::DateSystem::Excel1900);
6605 b.append_row(&[LiteralValue::Text("a".into()), LiteralValue::Number(1.0)])
6606 .unwrap();
6607 b.append_row(&[LiteralValue::Text("b".into()), LiteralValue::Number(2.0)])
6608 .unwrap();
6609 b.append_row(&[LiteralValue::Text("c".into()), LiteralValue::Number(3.0)])
6610 .unwrap();
6611 let sheet = b.finish();
6612 let rv = sheet.range_view(0, 0, 2, 1);
6613 let slices: Vec<_> = rv.iter_row_chunks().map(|r| r.unwrap()).collect();
6614 assert_eq!(slices.len(), 2);
6615 assert_eq!(slices[0].row_start, 0);
6616 assert_eq!(slices[0].row_len, 2);
6617 assert_eq!(slices[0].cols.len(), 2);
6618 assert_eq!(slices[1].row_start, 2);
6619 assert_eq!(slices[1].row_len, 1);
6620 assert_eq!(slices[1].cols.len(), 2);
6621 }
6622
6623 #[test]
6624 fn oob_columns_are_padded() {
6625 let mut b = IngestBuilder::new("S", 2, 2, crate::engine::DateSystem::Excel1900);
6627 b.append_row(&[LiteralValue::Number(1.0), LiteralValue::Text("a".into())])
6628 .unwrap();
6629 b.append_row(&[LiteralValue::Number(2.0), LiteralValue::Text("b".into())])
6630 .unwrap();
6631 let sheet = b.finish();
6632 let rv = sheet.range_view(0, 0, 1, 2);
6634 assert_eq!(rv.dims(), (2, 3));
6635 let slices: Vec<_> = rv.iter_row_chunks().map(|r| r.unwrap()).collect();
6636 assert!(!slices.is_empty());
6637 for cs in &slices {
6638 assert_eq!(cs.cols.len(), 3);
6639 }
6640 for res in rv.numbers_slices() {
6642 let (_rs, _rl, cols) = res.unwrap();
6643 assert_eq!(cols.len(), 3);
6644 }
6645 for res in rv.booleans_slices() {
6646 let (_rs, _rl, cols) = res.unwrap();
6647 assert_eq!(cols.len(), 3);
6648 }
6649 for res in rv.text_slices() {
6650 let (_rs, _rl, cols) = res.unwrap();
6651 assert_eq!(cols.len(), 3);
6652 }
6653 for res in rv.errors_slices() {
6654 let (_rs, _rl, cols) = res.unwrap();
6655 assert_eq!(cols.len(), 3);
6656 }
6657 for res in rv.lowered_text_slices() {
6658 let (_rs, _rl, cols) = res.unwrap();
6659 assert_eq!(cols.len(), 3);
6660 }
6661 }
6662
6663 #[test]
6664 fn reversed_range_is_empty() {
6665 let mut b = IngestBuilder::new("S", 1, 4, crate::engine::DateSystem::Excel1900);
6666 b.append_row(&[LiteralValue::Number(1.0)]).unwrap();
6667 b.append_row(&[LiteralValue::Number(2.0)]).unwrap();
6668 let sheet = b.finish();
6669 let rv = sheet.range_view(3, 0, 1, 0); assert_eq!(rv.dims(), (0, 0));
6671 assert!(rv.iter_row_chunks().next().is_none());
6672 assert_eq!(rv.get_cell(0, 0), LiteralValue::Empty);
6673 }
6674
6675 #[test]
6676 fn chunk_alignment_invariant() {
6677 let mut b = IngestBuilder::new("S", 3, 2, crate::engine::DateSystem::Excel1900);
6678 for r in 0..5 {
6680 b.append_row(&[
6681 LiteralValue::Number(r as f64),
6682 LiteralValue::Text(format!("{r}")),
6683 if r % 2 == 0 {
6684 LiteralValue::Empty
6685 } else {
6686 LiteralValue::Boolean(true)
6687 },
6688 ])
6689 .unwrap();
6690 }
6691 let sheet = b.finish();
6692 assert_eq!(sheet.chunk_starts, vec![0, 2, 4]);
6694 let lens0: Vec<usize> = sheet.columns[0]
6696 .chunks
6697 .iter()
6698 .map(|ch| ch.type_tag.len())
6699 .collect();
6700 for col in &sheet.columns[1..] {
6701 let lens: Vec<usize> = col.chunks.iter().map(|ch| ch.type_tag.len()).collect();
6702 assert_eq!(lens, lens0);
6703 }
6704 }
6705
6706 #[test]
6707 fn chunking_splits_rows() {
6708 let mut b = IngestBuilder::new("S", 2, 2, crate::engine::DateSystem::Excel1900);
6710 let rows = vec![
6711 vec![LiteralValue::Number(1.0), LiteralValue::Text("a".into())],
6712 vec![LiteralValue::Empty, LiteralValue::Text("b".into())],
6713 vec![LiteralValue::Boolean(true), LiteralValue::Empty],
6714 ];
6715 for r in rows {
6716 b.append_row(&r).unwrap();
6717 }
6718 let sheet = b.finish();
6719 assert_eq!(sheet.columns[0].chunks.len(), 2);
6720 assert_eq!(sheet.columns[1].chunks.len(), 2);
6721 assert_eq!(sheet.columns[0].chunks[0].numbers_or_null().len(), 2);
6722 assert_eq!(sheet.columns[0].chunks[1].numbers_or_null().len(), 1);
6723 }
6724
6725 #[test]
6726 fn pending_is_not_error() {
6727 let mut b = IngestBuilder::new("S", 1, 8, crate::engine::DateSystem::Excel1900);
6728 b.append_row(&[LiteralValue::Pending]).unwrap();
6729 let sheet = b.finish();
6730 let ch = &sheet.columns[0].chunks[0];
6731 assert_eq!(ch.type_tag.values()[0], super::TypeTag::Pending as u8);
6733 let errs = ch.errors_or_null();
6735 assert_eq!(errs.null_count(), 1);
6736 }
6737
6738 #[test]
6739 fn all_null_numeric_lane_uses_null_array() {
6740 let mut b = IngestBuilder::new("S", 1, 16, crate::engine::DateSystem::Excel1900);
6742 b.append_row(&[LiteralValue::Text("a".into())]).unwrap();
6743 b.append_row(&[LiteralValue::Text("".into())]).unwrap();
6744 b.append_row(&[LiteralValue::Text("b".into())]).unwrap();
6745 let sheet = b.finish();
6746 let ch = &sheet.columns[0].chunks[0];
6747 let nums = ch.numbers_or_null();
6748 assert_eq!(nums.len(), 3);
6749 assert_eq!(nums.null_count(), 3);
6750 assert_eq!(nums.data_type(), &DataType::Float64);
6751 }
6752
6753 #[test]
6754 fn row_insert_delete_across_chunk_boundaries_with_overlays() {
6755 let mut b = IngestBuilder::new("S", 1, 4, crate::engine::DateSystem::Excel1900);
6757 for _ in 0..10 {
6758 b.append_row(&[LiteralValue::Empty]).unwrap();
6759 }
6760 let mut sheet = b.finish();
6761 {
6763 let (c0, o0) = sheet.chunk_of_row(3).unwrap();
6764 sheet.columns[0].chunks[c0]
6765 .overlay
6766 .set(o0, OverlayValue::Number(30.0));
6767 let (c1, o1) = sheet.chunk_of_row(4).unwrap();
6768 sheet.columns[0].chunks[c1]
6769 .overlay
6770 .set(o1, OverlayValue::Number(40.0));
6771 }
6772 sheet.insert_rows(4, 2);
6774 assert_eq!(sheet.nrows, 12);
6775 let av = sheet.range_view(0, 0, (sheet.nrows - 1) as usize, 0);
6777 assert_eq!(av.get_cell(3, 0), LiteralValue::Number(30.0));
6778 assert_eq!(av.get_cell(4, 0), LiteralValue::Empty);
6779 assert_eq!(av.get_cell(6, 0), LiteralValue::Number(40.0));
6780
6781 sheet.delete_rows(3, 3);
6783 assert_eq!(sheet.nrows, 9);
6784 let av2 = sheet.range_view(0, 0, (sheet.nrows - 1) as usize, 0);
6785 assert_eq!(av2.get_cell(3, 0), LiteralValue::Number(40.0));
6786 let lens0: Vec<usize> = sheet.columns[0]
6788 .chunks
6789 .iter()
6790 .map(|ch| ch.type_tag.len())
6791 .collect();
6792 for col in &sheet.columns {
6793 let lens: Vec<usize> = col.chunks.iter().map(|ch| ch.type_tag.len()).collect();
6794 assert_eq!(lens, lens0);
6795 }
6796 assert!(sheet.chunk_starts.windows(2).all(|w| w[0] < w[1]));
6798 let last_start = *sheet.chunk_starts.last().unwrap_or(&0);
6799 let last_len = sheet.columns[0]
6800 .chunks
6801 .last()
6802 .map(|c| c.type_tag.len())
6803 .unwrap_or(0);
6804 assert_eq!(last_start + last_len, sheet.nrows as usize);
6805 }
6806
6807 #[test]
6808 fn row_insert_delete_preserves_user_dense_fragments() {
6809 let mut b = IngestBuilder::new("S", 1, 4, crate::engine::DateSystem::Excel1900);
6810 for _ in 0..10 {
6811 b.append_row(&[LiteralValue::Empty]).unwrap();
6812 }
6813 let mut sheet = b.finish();
6814
6815 let (ch_idx, off) = sheet.chunk_of_row(1).unwrap();
6816 sheet.columns[0]
6817 .chunk_mut(ch_idx)
6818 .unwrap()
6819 .overlay
6820 .apply_fragment(
6821 OverlayFragment::dense_range(
6822 off,
6823 vec![
6824 OverlayValue::Number(10.0),
6825 OverlayValue::Number(20.0),
6826 OverlayValue::Number(30.0),
6827 ],
6828 )
6829 .unwrap(),
6830 );
6831
6832 let before = column_overlay_stats(&sheet, 0, false);
6833 assert_eq!(before.dense_fragments, 1);
6834 assert_eq!(before.sparse_fragments, 0);
6835 assert_column_overlays_normalized(&sheet, 0);
6836
6837 sheet.insert_rows(2, 2);
6838 assert_eq!(sheet.nrows, 12);
6839 let av = sheet.range_view(0, 0, (sheet.nrows - 1) as usize, 0);
6840 assert_eq!(av.get_cell(1, 0), LiteralValue::Number(10.0));
6841 assert_eq!(av.get_cell(2, 0), LiteralValue::Empty);
6842 assert_eq!(av.get_cell(3, 0), LiteralValue::Empty);
6843 assert_eq!(av.get_cell(4, 0), LiteralValue::Number(20.0));
6844 assert_eq!(av.get_cell(5, 0), LiteralValue::Number(30.0));
6845 let after_insert = column_overlay_stats(&sheet, 0, false);
6846 assert_eq!(after_insert.sparse_fragments, 0);
6847 assert!(after_insert.dense_fragments >= 2);
6848 assert_column_overlays_normalized(&sheet, 0);
6849
6850 sheet.delete_rows(2, 2);
6851 assert_eq!(sheet.nrows, 10);
6852 let av = sheet.range_view(0, 0, (sheet.nrows - 1) as usize, 0);
6853 assert_eq!(av.get_cell(1, 0), LiteralValue::Number(10.0));
6854 assert_eq!(av.get_cell(2, 0), LiteralValue::Number(20.0));
6855 assert_eq!(av.get_cell(3, 0), LiteralValue::Number(30.0));
6856 let after_delete = column_overlay_stats(&sheet, 0, false);
6857 assert_eq!(after_delete.sparse_fragments, 0);
6858 assert!(after_delete.dense_fragments >= 1);
6859 assert_column_overlays_normalized(&sheet, 0);
6860 }
6861
6862 #[test]
6863 fn row_insert_delete_preserves_computed_empty_run_fragments() {
6864 let mut b = IngestBuilder::new("S", 1, 4, crate::engine::DateSystem::Excel1900);
6865 for row in 0..8 {
6866 b.append_row(&[LiteralValue::Number((row + 1) as f64)])
6867 .unwrap();
6868 }
6869 let mut sheet = b.finish();
6870
6871 let (ch_idx, off) = sheet.chunk_of_row(1).unwrap();
6872 sheet.columns[0]
6873 .chunk_mut(ch_idx)
6874 .unwrap()
6875 .computed_overlay
6876 .apply_fragment(
6877 OverlayFragment::run_range(
6878 off,
6879 vec![
6880 OverlayValue::Empty,
6881 OverlayValue::Empty,
6882 OverlayValue::Empty,
6883 ],
6884 )
6885 .unwrap(),
6886 );
6887
6888 let before = column_overlay_stats(&sheet, 0, true);
6889 assert_eq!(before.run_fragments, 1);
6890 assert_eq!(before.sparse_fragments, 0);
6891 assert_column_overlays_normalized(&sheet, 0);
6892
6893 sheet.insert_rows(2, 1);
6894 assert_eq!(sheet.nrows, 9);
6895 let av = sheet.range_view(0, 0, (sheet.nrows - 1) as usize, 0);
6896 assert_eq!(av.get_cell(1, 0), LiteralValue::Empty);
6897 assert_eq!(av.get_cell(2, 0), LiteralValue::Empty);
6898 assert_eq!(av.get_cell(3, 0), LiteralValue::Empty);
6899 assert_eq!(av.get_cell(4, 0), LiteralValue::Empty);
6900 assert_eq!(av.get_cell(5, 0), LiteralValue::Number(5.0));
6901 let after_insert = column_overlay_stats(&sheet, 0, true);
6902 assert_eq!(after_insert.sparse_fragments, 0);
6903 assert!(after_insert.run_fragments >= 2);
6904 assert_column_overlays_normalized(&sheet, 0);
6905
6906 sheet.delete_rows(2, 1);
6907 assert_eq!(sheet.nrows, 8);
6908 let av = sheet.range_view(0, 0, (sheet.nrows - 1) as usize, 0);
6909 assert_eq!(av.get_cell(1, 0), LiteralValue::Empty);
6910 assert_eq!(av.get_cell(2, 0), LiteralValue::Empty);
6911 assert_eq!(av.get_cell(3, 0), LiteralValue::Empty);
6912 assert_eq!(av.get_cell(4, 0), LiteralValue::Number(5.0));
6913 let after_delete = column_overlay_stats(&sheet, 0, true);
6914 assert_eq!(after_delete.sparse_fragments, 0);
6915 assert!(after_delete.run_fragments >= 1);
6916 assert_column_overlays_normalized(&sheet, 0);
6917 }
6918
6919 #[test]
6920 fn column_insert_delete_retains_chunk_alignment() {
6921 let mut b = IngestBuilder::new("S", 3, 3, crate::engine::DateSystem::Excel1900);
6922 for _ in 0..5 {
6923 b.append_row(&[
6924 LiteralValue::Empty,
6925 LiteralValue::Empty,
6926 LiteralValue::Empty,
6927 ])
6928 .unwrap();
6929 }
6930 let mut sheet = b.finish();
6931 let ref_lens: Vec<usize> = sheet.columns[0]
6933 .chunks
6934 .iter()
6935 .map(|ch| ch.type_tag.len())
6936 .collect();
6937 sheet.insert_columns(1, 2);
6939 assert_eq!(sheet.columns.len(), 5);
6940 for col in &sheet.columns {
6941 let lens: Vec<usize> = col.chunks.iter().map(|ch| ch.type_tag.len()).collect();
6942 assert_eq!(lens, ref_lens);
6943 }
6944 let starts_before = sheet.chunk_starts.clone();
6945 sheet.delete_columns(2, 2);
6947 assert_eq!(sheet.columns.len(), 3);
6948 for col in &sheet.columns {
6949 let lens: Vec<usize> = col.chunks.iter().map(|ch| ch.type_tag.len()).collect();
6950 assert_eq!(lens, ref_lens);
6951 }
6952 assert_eq!(sheet.chunk_starts, starts_before);
6954 }
6955
6956 #[test]
6957 fn multiple_adjacent_row_ops_overlay_mixed_types() {
6958 use formualizer_common::ExcelErrorKind;
6959 let mut b = IngestBuilder::new("S", 2, 3, crate::engine::DateSystem::Excel1900);
6961 for _ in 0..9 {
6962 b.append_row(&[LiteralValue::Empty, LiteralValue::Empty])
6963 .unwrap();
6964 }
6965 let mut sheet = b.finish();
6966 let set_ov = |sh: &mut ArrowSheet, row: usize, ov: OverlayValue| {
6969 let (ch_i, off) = sh.chunk_of_row(row).unwrap();
6970 let _ = sh.columns[0].chunks[ch_i].overlay.set(off, ov);
6971 };
6972 set_ov(&mut sheet, 2, OverlayValue::Number(12.5));
6973 set_ov(&mut sheet, 3, OverlayValue::Text(Arc::from("hello")));
6974 set_ov(&mut sheet, 5, OverlayValue::Boolean(true));
6975 set_ov(
6976 &mut sheet,
6977 6,
6978 OverlayValue::Error(map_error_code(ExcelErrorKind::Div)),
6979 );
6980 set_ov(&mut sheet, 8, OverlayValue::Empty);
6981
6982 sheet.insert_rows(3, 1);
6984 let av1 = sheet.range_view(0, 0, (sheet.nrows - 1) as usize, 0);
6986 assert_eq!(av1.get_cell(2, 0), LiteralValue::Number(12.5));
6987 assert_eq!(av1.get_cell(4, 0), LiteralValue::Text("hello".into()));
6988 assert_eq!(av1.get_cell(6, 0), LiteralValue::Boolean(true));
6989 match av1.get_cell(7, 0) {
6990 LiteralValue::Error(e) => assert_eq!(e.kind, ExcelErrorKind::Div),
6991 other => panic!("expected error at row 7, got {other:?}"),
6992 }
6993 assert_eq!(av1.get_cell(9, 0), LiteralValue::Empty);
6994
6995 sheet.insert_rows(4, 2);
6997 let av2 = sheet.range_view(0, 0, (sheet.nrows - 1) as usize, 0);
6999 assert_eq!(av2.get_cell(2, 0), LiteralValue::Number(12.5));
7000 assert_eq!(av2.get_cell(6, 0), LiteralValue::Text("hello".into()));
7001 assert_eq!(av2.get_cell(8, 0), LiteralValue::Boolean(true));
7002 match av2.get_cell(9, 0) {
7003 LiteralValue::Error(e) => assert_eq!(e.kind, ExcelErrorKind::Div),
7004 other => panic!("expected error at row 9, got {other:?}"),
7005 }
7006 assert_eq!(av2.get_cell(11, 0), LiteralValue::Empty);
7007
7008 sheet.delete_rows(6, 2);
7010 let av3 = sheet.range_view(0, 0, (sheet.nrows - 1) as usize, 0);
7011 assert_eq!(av3.get_cell(2, 0), LiteralValue::Number(12.5));
7013 assert_eq!(av3.get_cell(6, 0), LiteralValue::Boolean(true));
7014 match av3.get_cell(7, 0) {
7015 LiteralValue::Error(e) => assert_eq!(e.kind, ExcelErrorKind::Div),
7016 other => panic!("expected error at row 8, got {other:?}"),
7017 }
7018 assert_eq!(av3.get_cell(9, 0), LiteralValue::Empty);
7019
7020 let lens0: Vec<usize> = sheet.columns[0]
7022 .chunks
7023 .iter()
7024 .map(|ch| ch.type_tag.len())
7025 .collect();
7026 for col in &sheet.columns {
7027 let lens: Vec<usize> = col.chunks.iter().map(|ch| ch.type_tag.len()).collect();
7028 assert_eq!(lens, lens0);
7029 }
7030 assert!(sheet.chunk_starts.windows(2).all(|w| w[0] < w[1]));
7032 let last_start = *sheet.chunk_starts.last().unwrap_or(&0);
7033 let last_len = sheet.columns[0]
7034 .chunks
7035 .last()
7036 .map(|c| c.type_tag.len())
7037 .unwrap_or(0);
7038 assert_eq!(last_start + last_len, sheet.nrows as usize);
7039 }
7040
7041 #[test]
7042 fn multiple_adjacent_column_ops_alignment() {
7043 let mut b = IngestBuilder::new("S", 2, 2, crate::engine::DateSystem::Excel1900);
7045 for _ in 0..5 {
7046 b.append_row(&[LiteralValue::Empty, LiteralValue::Empty])
7047 .unwrap();
7048 }
7049 let mut sheet = b.finish();
7050 let ref_lens: Vec<usize> = sheet.columns[0]
7051 .chunks
7052 .iter()
7053 .map(|ch| ch.type_tag.len())
7054 .collect();
7055 sheet.insert_columns(0, 1);
7057 sheet.insert_columns(2, 2);
7058 assert_eq!(sheet.columns.len(), 5);
7059 for col in &sheet.columns {
7060 let lens: Vec<usize> = col.chunks.iter().map(|ch| ch.type_tag.len()).collect();
7061 assert_eq!(lens, ref_lens);
7062 }
7063 let starts_before = sheet.chunk_starts.clone();
7064 sheet.delete_columns(1, 1);
7066 let remain = sheet.columns.len();
7067 if remain >= 3 {
7068 sheet.delete_columns(remain - 2, 2);
7069 }
7070 for col in &sheet.columns {
7071 let lens: Vec<usize> = col.chunks.iter().map(|ch| ch.type_tag.len()).collect();
7072 assert_eq!(lens, ref_lens);
7073 }
7074 assert_eq!(sheet.chunk_starts, starts_before);
7075 }
7076
7077 #[test]
7078 fn overlays_on_multiple_columns_row_col_ops() {
7079 let mut b = IngestBuilder::new("S", 3, 3, crate::engine::DateSystem::Excel1900);
7081 for _ in 0..6 {
7082 b.append_row(&[
7083 LiteralValue::Empty,
7084 LiteralValue::Empty,
7085 LiteralValue::Empty,
7086 ])
7087 .unwrap();
7088 }
7089 let mut sheet = b.finish();
7090 let set_ov = |sh: &mut ArrowSheet, col: usize, row: usize, ov: OverlayValue| {
7092 let (ch_i, off) = sh.chunk_of_row(row).unwrap();
7093 let _ = sh.columns[col].chunks[ch_i].overlay.set(off, ov);
7094 };
7095 set_ov(&mut sheet, 0, 2, OverlayValue::Number(12.0));
7096 set_ov(&mut sheet, 1, 2, OverlayValue::Text(Arc::from("xx")));
7097 set_ov(&mut sheet, 2, 2, OverlayValue::Boolean(true));
7098 set_ov(&mut sheet, 0, 3, OverlayValue::Number(33.0));
7099 set_ov(&mut sheet, 1, 3, OverlayValue::Text(Arc::from("yy")));
7100 set_ov(&mut sheet, 2, 3, OverlayValue::Boolean(false));
7101
7102 sheet.insert_rows(3, 1);
7104 let av = sheet.range_view(0, 0, (sheet.nrows - 1) as usize, 2);
7106 assert_eq!(av.get_cell(2, 0), LiteralValue::Number(12.0));
7108 assert_eq!(av.get_cell(2, 1), LiteralValue::Text("xx".into()));
7109 assert_eq!(av.get_cell(2, 2), LiteralValue::Boolean(true));
7110 assert_eq!(av.get_cell(3, 0), LiteralValue::Empty);
7112 assert_eq!(av.get_cell(4, 0), LiteralValue::Number(33.0));
7114 assert_eq!(av.get_cell(4, 1), LiteralValue::Text("yy".into()));
7115 assert_eq!(av.get_cell(4, 2), LiteralValue::Boolean(false));
7116
7117 sheet.delete_columns(1, 1);
7119 let av2 = sheet.range_view(0, 0, (sheet.nrows - 1) as usize, 1);
7120 assert_eq!(av2.get_cell(2, 0), LiteralValue::Number(12.0));
7121 assert_eq!(av2.get_cell(2, 1), LiteralValue::Boolean(true));
7123 assert_eq!(av2.get_cell(4, 0), LiteralValue::Number(33.0));
7124 assert_eq!(av2.get_cell(4, 1), LiteralValue::Boolean(false));
7125
7126 let lens0: Vec<usize> = sheet.columns[0]
7128 .chunks
7129 .iter()
7130 .map(|ch| ch.type_tag.len())
7131 .collect();
7132 for col in &sheet.columns {
7133 let lens: Vec<usize> = col.chunks.iter().map(|ch| ch.type_tag.len()).collect();
7134 assert_eq!(lens, lens0);
7135 }
7136 }
7137
7138 #[test]
7139 fn effective_slices_overlay_precedence_numbers_text() {
7140 let mut b = IngestBuilder::new("S", 1, 3, crate::engine::DateSystem::Excel1900);
7142 for i in 0..6 {
7143 b.append_row(&[LiteralValue::Number((i + 1) as f64)])
7144 .unwrap();
7145 }
7146 let mut sheet = b.finish();
7147 let (c1, o1) = sheet.chunk_of_row(1).unwrap();
7149 sheet.columns[0].chunks[c1]
7150 .overlay
7151 .set(o1, OverlayValue::Text(Arc::from("X")));
7152 let (c4, o4) = sheet.chunk_of_row(4).unwrap();
7153 sheet.columns[0].chunks[c4]
7154 .overlay
7155 .set(o4, OverlayValue::Number(99.0));
7156
7157 let av = sheet.range_view(0, 0, 5, 0);
7158 let mut numeric: Vec<Option<f64>> = vec![None; 6];
7160 for res in av.numbers_slices() {
7161 let (row_start, row_len, cols) = res.unwrap();
7162 let a = &cols[0];
7163 for i in 0..row_len {
7164 let idx = row_start + i;
7165 numeric[idx] = if a.is_null(i) { None } else { Some(a.value(i)) };
7166 }
7167 }
7168 assert_eq!(numeric[0], Some(1.0));
7169 assert_eq!(numeric[1], None); assert_eq!(numeric[2], Some(3.0));
7171 assert_eq!(numeric[3], Some(4.0));
7172 assert_eq!(numeric[4], Some(99.0));
7173 assert_eq!(numeric[5], Some(6.0));
7174
7175 let mut texts: Vec<Option<String>> = vec![None; 6];
7177 for res in av.text_slices() {
7178 let (row_start, row_len, cols) = res.unwrap();
7179 let a = cols[0].as_any().downcast_ref::<StringArray>().unwrap();
7180 for i in 0..row_len {
7181 let idx = row_start + i;
7182 texts[idx] = if a.is_null(i) {
7183 None
7184 } else {
7185 Some(a.value(i).to_string())
7186 };
7187 }
7188 }
7189 assert_eq!(texts[1].as_deref(), Some("X"));
7190 assert!(texts[0].is_none());
7191 assert!(texts[2].is_none());
7192 assert!(texts[3].is_none());
7193 assert!(texts[4].is_none());
7194 assert!(texts[5].is_none());
7195 }
7196
7197 #[test]
7198 fn effective_slices_overlay_precedence_booleans() {
7199 let mut b = IngestBuilder::new("S", 1, 4, crate::engine::DateSystem::Excel1900);
7201 for i in 0..6 {
7202 let v = if i % 2 == 0 {
7203 LiteralValue::Boolean(true)
7204 } else {
7205 LiteralValue::Boolean(false)
7206 };
7207 b.append_row(&[v]).unwrap();
7208 }
7209 let mut sheet = b.finish();
7210 let (c1, o1) = sheet.chunk_of_row(1).unwrap();
7212 sheet.columns[0].chunks[c1]
7213 .overlay
7214 .set(o1, OverlayValue::Boolean(true));
7215 let (c2, o2) = sheet.chunk_of_row(2).unwrap();
7216 sheet.columns[0].chunks[c2]
7217 .overlay
7218 .set(o2, OverlayValue::Text(Arc::from("T")));
7219
7220 let av = sheet.range_view(0, 0, 5, 0);
7221 let mut bools: Vec<Option<bool>> = vec![None; 6];
7223 for res in av.booleans_slices() {
7224 let (row_start, row_len, cols) = res.unwrap();
7225 let a = &cols[0];
7226 for i in 0..row_len {
7227 let idx = row_start + i;
7228 bools[idx] = if a.is_null(i) { None } else { Some(a.value(i)) };
7229 }
7230 }
7231 assert_eq!(bools[0], Some(true));
7232 assert_eq!(bools[1], Some(true)); assert_eq!(bools[2], None); assert_eq!(bools[3], Some(false));
7236 }
7237
7238 #[test]
7239 fn effective_slices_overlay_precedence_errors() {
7240 let mut b = IngestBuilder::new("S", 1, 3, crate::engine::DateSystem::Excel1900);
7242 for i in 0..6 {
7243 b.append_row(&[LiteralValue::Number((i + 1) as f64)])
7244 .unwrap();
7245 }
7246 let mut sheet = b.finish();
7247 let (c4, o4) = sheet.chunk_of_row(4).unwrap();
7249 sheet.columns[0].chunks[c4]
7250 .overlay
7251 .set(o4, OverlayValue::Error(map_error_code(ExcelErrorKind::Div)));
7252
7253 let av = sheet.range_view(0, 0, 5, 0);
7254 let mut errs: Vec<Option<u8>> = vec![None; 6];
7255 for res in av.errors_slices() {
7256 let (row_start, row_len, cols) = res.unwrap();
7257 let a = &cols[0];
7258 for i in 0..row_len {
7259 let idx = row_start + i;
7260 errs[idx] = if a.is_null(i) { None } else { Some(a.value(i)) };
7261 }
7262 }
7263 assert_eq!(errs[4], Some(map_error_code(ExcelErrorKind::Div)));
7264 assert!(errs[3].is_none());
7265 }
7266}