• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vortex-data / vortex / 16275012398

14 Jul 2025 06:38PM UTC coverage: 81.568% (+0.4%) from 81.147%
16275012398

Pull #3852

github

web-flow
Merge e4d6d19f4 into 65447ae8a
Pull Request #3852: feat: call optimize in compressor

5 of 6 new or added lines in 1 file covered. (83.33%)

370 existing lines in 35 files now uncovered.

46288 of 56748 relevant lines covered (81.57%)

157514.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.94
/vortex-array/src/array/mod.rs
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3

4
mod convert;
5
pub mod display;
6
mod statistics;
7
mod visitor;
8

9
use std::any::Any;
10
use std::fmt::{Debug, Formatter};
11
use std::sync::Arc;
12

13
pub use convert::*;
14
pub use visitor::*;
15
use vortex_buffer::ByteBuffer;
16
use vortex_dtype::DType;
17
use vortex_error::{VortexExpect, VortexResult, vortex_bail, vortex_err};
18
use vortex_mask::Mask;
19
use vortex_scalar::Scalar;
20

21
use crate::arrays::{
22
    BoolEncoding, DecimalEncoding, ExtensionEncoding, ListEncoding, NullEncoding,
23
    PrimitiveEncoding, StructEncoding, VarBinEncoding, VarBinViewEncoding,
24
};
25
use crate::builders::ArrayBuilder;
26
use crate::compute::{ComputeFn, Cost, InvocationArgs, Output};
27
use crate::serde::ArrayChildren;
28
use crate::stats::{Precision, Stat, StatsProviderExt, StatsSetRef};
29
use crate::vtable::{
30
    ArrayVTable, CanonicalVTable, ComputeVTable, OperationsVTable, SerdeVTable, VTable,
31
    ValidityVTable, VisitorVTable,
32
};
33
use crate::{Canonical, EncodingId, EncodingRef, SerializeMetadata};
34

35
/// The public API trait for all Vortex arrays.
36
pub trait Array: 'static + private::Sealed + Send + Sync + Debug + ArrayVisitor {
37
    /// Returns the array as a reference to a generic [`Any`] trait object.
38
    fn as_any(&self) -> &dyn Any;
39

40
    /// Returns the array as an [`ArrayRef`].
41
    fn to_array(&self) -> ArrayRef;
42

43
    /// Returns the length of the array.
44
    fn len(&self) -> usize;
45

46
    /// Returns whether the array is empty (has zero rows).
47
    fn is_empty(&self) -> bool {
210,684✔
48
        self.len() == 0
210,684✔
49
    }
210,684✔
50

51
    /// Returns the logical Vortex [`DType`] of the array.
52
    fn dtype(&self) -> &DType;
53

54
    /// Returns the encoding of the array.
55
    fn encoding(&self) -> EncodingRef;
56

57
    /// Returns the encoding ID of the array.
58
    fn encoding_id(&self) -> EncodingId;
59

60
    /// Performs a constant-time slice of the array.
61
    fn slice(&self, start: usize, end: usize) -> VortexResult<ArrayRef>;
62

63
    /// Fetch the scalar at the given index.
64
    fn scalar_at(&self, index: usize) -> VortexResult<Scalar>;
65

66
    /// Return an optimized version of the same array.
67
    ///
68
    /// See [`OperationsVTable::optimize`] for more details.
69
    fn optimize(&self) -> VortexResult<ArrayRef>;
70

71
    /// Returns whether the array is of the given encoding.
72
    fn is_encoding(&self, encoding: EncodingId) -> bool {
351,689✔
73
        self.encoding_id() == encoding
351,689✔
74
    }
351,689✔
75

76
    /// Returns whether this array is an arrow encoding.
77
    // TODO(ngates): this shouldn't live here.
78
    fn is_arrow(&self) -> bool {
8,657✔
79
        self.is_encoding(NullEncoding.id())
8,657✔
80
            || self.is_encoding(BoolEncoding.id())
8,657✔
81
            || self.is_encoding(PrimitiveEncoding.id())
7,526✔
82
            || self.is_encoding(VarBinEncoding.id())
5,599✔
83
            || self.is_encoding(VarBinViewEncoding.id())
5,599✔
84
    }
8,657✔
85

86
    /// Whether the array is of a canonical encoding.
87
    // TODO(ngates): this shouldn't live here.
88
    fn is_canonical(&self) -> bool {
50,755✔
89
        self.is_encoding(NullEncoding.id())
50,755✔
90
            || self.is_encoding(BoolEncoding.id())
50,755✔
91
            || self.is_encoding(PrimitiveEncoding.id())
49,245✔
92
            || self.is_encoding(DecimalEncoding.id())
33,829✔
93
            || self.is_encoding(StructEncoding.id())
32,518✔
94
            || self.is_encoding(ListEncoding.id())
31,251✔
95
            || self.is_encoding(VarBinViewEncoding.id())
31,249✔
96
            || self.is_encoding(ExtensionEncoding.id())
29,599✔
97
    }
50,755✔
98

99
    /// Returns whether the item at `index` is valid.
100
    fn is_valid(&self, index: usize) -> VortexResult<bool>;
101

102
    /// Returns whether the item at `index` is invalid.
103
    fn is_invalid(&self, index: usize) -> VortexResult<bool>;
104

105
    /// Returns whether all items in the array are valid.
106
    ///
107
    /// This is usually cheaper than computing a precise `valid_count`.
108
    fn all_valid(&self) -> VortexResult<bool>;
109

110
    /// Returns whether the array is all invalid.
111
    ///
112
    /// This is usually cheaper than computing a precise `invalid_count`.
113
    fn all_invalid(&self) -> VortexResult<bool>;
114

115
    /// Returns the number of valid elements in the array.
116
    fn valid_count(&self) -> VortexResult<usize>;
117

118
    /// Returns the number of invalid elements in the array.
119
    fn invalid_count(&self) -> VortexResult<usize>;
120

121
    /// Returns the canonical validity mask for the array.
122
    fn validity_mask(&self) -> VortexResult<Mask>;
123

124
    /// Returns the canonical representation of the array.
125
    fn to_canonical(&self) -> VortexResult<Canonical>;
126

127
    /// Writes the array into the canonical builder.
128
    ///
129
    /// The [`DType`] of the builder must match that of the array.
130
    fn append_to_builder(&self, builder: &mut dyn ArrayBuilder) -> VortexResult<()>;
131

132
    /// Returns the statistics of the array.
133
    // TODO(ngates): change how this works. It's weird.
134
    fn statistics(&self) -> StatsSetRef<'_>;
135

136
    /// Replaces the children of the array with the given array references.
137
    fn with_children(&self, children: &[ArrayRef]) -> VortexResult<ArrayRef>;
138

139
    /// Optionally invoke a kernel for the given compute function.
140
    ///
141
    /// These encoding-specific kernels are independent of kernels registered directly with
142
    /// compute functions using [`ComputeFn::register_kernel`], and are attempted only if none of
143
    /// the function-specific kernels returns a result.
144
    ///
145
    /// This allows encodings the opportunity to generically implement many compute functions
146
    /// that share some property, for example [`ComputeFn::is_elementwise`], without prior
147
    /// knowledge of the function itself, while still allowing users to override the implementation
148
    /// of compute functions for built-in encodings. For an example, see the implementation for
149
    /// chunked arrays.
150
    ///
151
    /// The first input in the [`InvocationArgs`] is always the array itself.
152
    ///
153
    /// Warning: do not call `compute_fn.invoke(args)` directly, as this will result in a recursive
154
    /// call.
155
    fn invoke(&self, compute_fn: &ComputeFn, args: &InvocationArgs)
156
    -> VortexResult<Option<Output>>;
157
}
158

159
impl Array for Arc<dyn Array> {
160
    fn as_any(&self) -> &dyn Any {
529,677✔
161
        self.as_ref().as_any()
529,677✔
162
    }
529,677✔
163

164
    fn to_array(&self) -> ArrayRef {
153,841✔
165
        self.clone()
153,841✔
166
    }
153,841✔
167

168
    fn len(&self) -> usize {
1,088,605✔
169
        self.as_ref().len()
1,088,605✔
170
    }
1,088,605✔
171

172
    fn dtype(&self) -> &DType {
869,777✔
173
        self.as_ref().dtype()
869,777✔
174
    }
869,777✔
175

176
    fn encoding(&self) -> EncodingRef {
17,872✔
177
        self.as_ref().encoding()
17,872✔
178
    }
17,872✔
179

180
    fn encoding_id(&self) -> EncodingId {
311,064✔
181
        self.as_ref().encoding_id()
311,064✔
182
    }
311,064✔
183

184
    fn slice(&self, start: usize, end: usize) -> VortexResult<ArrayRef> {
34,971✔
185
        self.as_ref().slice(start, end)
34,971✔
186
    }
34,971✔
187

188
    fn scalar_at(&self, index: usize) -> VortexResult<Scalar> {
504,986✔
189
        self.as_ref().scalar_at(index)
504,986✔
190
    }
504,986✔
191

192
    fn optimize(&self) -> VortexResult<ArrayRef> {
20,334✔
193
        self.as_ref().optimize()
20,334✔
194
    }
20,334✔
195

196
    fn is_valid(&self, index: usize) -> VortexResult<bool> {
31,110✔
197
        self.as_ref().is_valid(index)
31,110✔
198
    }
31,110✔
199

200
    fn is_invalid(&self, index: usize) -> VortexResult<bool> {
364✔
201
        self.as_ref().is_invalid(index)
364✔
202
    }
364✔
203

204
    fn all_valid(&self) -> VortexResult<bool> {
25,255✔
205
        self.as_ref().all_valid()
25,255✔
206
    }
25,255✔
207

208
    fn all_invalid(&self) -> VortexResult<bool> {
43,147✔
209
        self.as_ref().all_invalid()
43,147✔
210
    }
43,147✔
211

212
    fn valid_count(&self) -> VortexResult<usize> {
2,668✔
213
        self.as_ref().valid_count()
2,668✔
214
    }
2,668✔
215

216
    fn invalid_count(&self) -> VortexResult<usize> {
444✔
217
        self.as_ref().invalid_count()
444✔
218
    }
444✔
219

220
    fn validity_mask(&self) -> VortexResult<Mask> {
6,166✔
221
        self.as_ref().validity_mask()
6,166✔
222
    }
6,166✔
223

224
    fn to_canonical(&self) -> VortexResult<Canonical> {
220,473✔
225
        self.as_ref().to_canonical()
220,473✔
226
    }
220,473✔
227

228
    fn append_to_builder(&self, builder: &mut dyn ArrayBuilder) -> VortexResult<()> {
40,854✔
229
        self.as_ref().append_to_builder(builder)
40,854✔
230
    }
40,854✔
231

232
    fn statistics(&self) -> StatsSetRef<'_> {
391,826✔
233
        self.as_ref().statistics()
391,826✔
234
    }
391,826✔
235

236
    fn with_children(&self, children: &[ArrayRef]) -> VortexResult<ArrayRef> {
×
237
        self.as_ref().with_children(children)
×
UNCOV
238
    }
×
239

240
    fn invoke(
33,721✔
241
        &self,
33,721✔
242
        compute_fn: &ComputeFn,
33,721✔
243
        args: &InvocationArgs,
33,721✔
244
    ) -> VortexResult<Option<Output>> {
33,721✔
245
        self.as_ref().invoke(compute_fn, args)
33,721✔
246
    }
33,721✔
247
}
248

249
/// A reference counted pointer to a dynamic [`Array`] trait object.
250
pub type ArrayRef = Arc<dyn Array>;
251

252
impl ToOwned for dyn Array {
253
    type Owned = ArrayRef;
254

255
    fn to_owned(&self) -> Self::Owned {
×
256
        self.to_array()
×
UNCOV
257
    }
×
258
}
259

260
impl dyn Array + '_ {
261
    /// Returns the array downcast to the given `A`.
262
    pub fn as_<V: VTable>(&self) -> &V::Array {
177✔
263
        self.as_opt::<V>().vortex_expect("Failed to downcast")
177✔
264
    }
177✔
265

266
    /// Returns the array downcast to the given `A`.
267
    pub fn as_opt<V: VTable>(&self) -> Option<&V::Array> {
1,337,748✔
268
        self.as_any()
1,337,748✔
269
            .downcast_ref::<ArrayAdapter<V>>()
1,337,748✔
270
            .map(|array_adapter| &array_adapter.0)
1,337,748✔
271
    }
1,337,748✔
272

273
    /// Is self an array with encoding from vtable `V`.
274
    pub fn is<V: VTable>(&self) -> bool {
9,451✔
275
        self.as_opt::<V>().is_some()
9,451✔
276
    }
9,451✔
277
}
278

279
impl dyn Array + '_ {
280
    /// Total size of the array in bytes, including all children and buffers.
281
    // TODO(ngates): this should return u64
282
    pub fn nbytes(&self) -> usize {
226,005✔
283
        let mut nbytes = 0;
226,005✔
284
        for array in self.depth_first_traversal() {
315,221✔
285
            for buffer in array.buffers() {
350,970✔
286
                nbytes += buffer.len();
348,882✔
287
            }
348,882✔
288
        }
289
        nbytes
226,005✔
290
    }
226,005✔
291
}
292

293
mod private {
294
    use super::*;
295

296
    pub trait Sealed {}
297

298
    impl<V: VTable> Sealed for ArrayAdapter<V> {}
299
    impl Sealed for Arc<dyn Array> {}
300
}
301

302
/// Adapter struct used to lift the [`VTable`] trait into an object-safe [`Array`]
303
/// implementation.
304
///
305
/// Since this is a unit struct with `repr(transparent)`, we are able to turn un-adapted array
306
/// structs into [`dyn Array`] using some cheeky casting inside [`std::ops::Deref`] and
307
/// [`AsRef`]. See the `vtable!` macro for more details.
308
#[repr(transparent)]
309
pub struct ArrayAdapter<V: VTable>(V::Array);
310

311
impl<V: VTable> Debug for ArrayAdapter<V> {
UNCOV
312
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
×
UNCOV
313
        self.0.fmt(f)
×
UNCOV
314
    }
×
315
}
316

317
impl<V: VTable> Array for ArrayAdapter<V> {
318
    fn as_any(&self) -> &dyn Any {
1,254,428✔
319
        self
1,254,428✔
320
    }
1,254,428✔
321

322
    fn to_array(&self) -> ArrayRef {
364,153✔
323
        Arc::new(ArrayAdapter::<V>(self.0.clone()))
364,153✔
324
    }
364,153✔
325

326
    fn len(&self) -> usize {
13,520,800✔
327
        <V::ArrayVTable as ArrayVTable<V>>::len(&self.0)
13,520,800✔
328
    }
13,520,800✔
329

330
    fn dtype(&self) -> &DType {
27,712,269✔
331
        <V::ArrayVTable as ArrayVTable<V>>::dtype(&self.0)
27,712,269✔
332
    }
27,712,269✔
333

334
    fn encoding(&self) -> EncodingRef {
24,151✔
335
        V::encoding(&self.0)
24,151✔
336
    }
24,151✔
337

338
    fn encoding_id(&self) -> EncodingId {
345,026✔
339
        V::encoding(&self.0).id()
345,026✔
340
    }
345,026✔
341

342
    fn slice(&self, start: usize, stop: usize) -> VortexResult<ArrayRef> {
69,196✔
343
        if start == 0 && stop == self.len() {
69,196✔
344
            return Ok(self.to_array());
9,753✔
345
        }
59,443✔
346

59,443✔
347
        if start > self.len() {
59,443✔
UNCOV
348
            vortex_bail!(OutOfBounds: start, 0, self.len());
×
349
        }
59,443✔
350
        if stop > self.len() {
59,443✔
UNCOV
351
            vortex_bail!(OutOfBounds: stop, 0, self.len());
×
352
        }
59,443✔
353
        if start > stop {
59,443✔
UNCOV
354
            vortex_bail!("start ({start}) must be <= stop ({stop})");
×
355
        }
59,443✔
356

59,443✔
357
        if start == stop {
59,443✔
358
            return Ok(Canonical::empty(self.dtype()).into_array());
15✔
359
        }
59,428✔
360

59,428✔
361
        // We know that constant array don't need stats propagation, so we can avoid the overhead of
59,428✔
362
        // computing derived stats and merging them in.
59,428✔
363
        // TODO(ngates): skip the is_constant check here, it can force an expensive compute.
59,428✔
364
        // TODO(ngates): provide a means to slice an array _without_ propagating stats.
59,428✔
365
        let derived_stats = (!self.0.is_constant_opts(Cost::Negligible)).then(|| {
59,428✔
366
            let stats = self.statistics().to_owned();
50,206✔
367

50,206✔
368
            // an array that is not constant can become constant after slicing
50,206✔
369
            let is_constant = stats.get_as::<bool>(Stat::IsConstant);
50,206✔
370
            let is_sorted = stats.get_as::<bool>(Stat::IsSorted);
50,206✔
371
            let is_strict_sorted = stats.get_as::<bool>(Stat::IsStrictSorted);
50,206✔
372

50,206✔
373
            let mut stats = stats.keep_inexact_stats(&[
50,206✔
374
                Stat::Max,
50,206✔
375
                Stat::Min,
50,206✔
376
                Stat::NullCount,
50,206✔
377
                Stat::UncompressedSizeInBytes,
50,206✔
378
            ]);
50,206✔
379

50,206✔
380
            if is_constant == Some(Precision::Exact(true)) {
50,206✔
UNCOV
381
                stats.set(Stat::IsConstant, Precision::exact(true));
×
382
            }
50,206✔
383
            if is_sorted == Some(Precision::Exact(true)) {
50,206✔
384
                stats.set(Stat::IsSorted, Precision::exact(true));
1,150✔
385
            }
49,056✔
386
            if is_strict_sorted == Some(Precision::Exact(true)) {
50,206✔
387
                stats.set(Stat::IsStrictSorted, Precision::exact(true));
840✔
388
            }
49,366✔
389

390
            stats
50,206✔
391
        });
59,428✔
392

393
        let sliced = <V::OperationsVTable as OperationsVTable<V>>::slice(&self.0, start, stop)?;
59,428✔
394

395
        assert_eq!(
59,428✔
396
            sliced.len(),
59,428✔
397
            stop - start,
59,428✔
UNCOV
398
            "Slice length mismatch {}",
×
UNCOV
399
            self.encoding_id()
×
400
        );
401
        assert_eq!(
59,428✔
402
            sliced.dtype(),
59,428✔
403
            self.dtype(),
59,428✔
UNCOV
404
            "Slice dtype mismatch {}",
×
UNCOV
405
            self.encoding_id()
×
406
        );
407

408
        if let Some(derived_stats) = derived_stats {
59,428✔
409
            let mut stats = sliced.statistics().to_owned();
50,206✔
410
            stats.combine_sets(&derived_stats, self.dtype())?;
50,206✔
411
            for (stat, val) in stats.into_iter() {
94,969✔
412
                sliced.statistics().set(stat, val)
94,631✔
413
            }
414
        }
9,222✔
415

416
        Ok(sliced)
59,428✔
417
    }
69,196✔
418

419
    fn scalar_at(&self, index: usize) -> VortexResult<Scalar> {
3,542,430✔
420
        if index >= self.len() {
3,542,430✔
421
            vortex_bail!(OutOfBounds: index, 0, self.len());
8✔
422
        }
3,542,422✔
423
        if self.is_invalid(index)? {
3,542,422✔
424
            return Ok(Scalar::null(self.dtype().clone()));
2,738✔
425
        }
3,539,684✔
426
        let scalar = <V::OperationsVTable as OperationsVTable<V>>::scalar_at(&self.0, index)?;
3,539,684✔
427
        assert_eq!(self.dtype(), scalar.dtype(), "Scalar dtype mismatch");
3,539,684✔
428
        Ok(scalar)
3,539,684✔
429
    }
3,542,430✔
430

431
    fn optimize(&self) -> VortexResult<ArrayRef> {
38,210✔
432
        let result = <V::OperationsVTable as OperationsVTable<V>>::optimize(&self.0)?.into_array();
38,210✔
433

38,210✔
434
        #[cfg(debug_assertions)]
38,210✔
435
        {
38,210✔
436
            let nbytes = self.0.nbytes();
38,210✔
437
            let result_nbytes = result.nbytes();
38,210✔
438
            assert!(
38,210✔
439
                result_nbytes <= nbytes,
38,210✔
UNCOV
440
                "optimize() made the array larger: {} bytes -> {} bytes",
×
441
                nbytes,
442
                result_nbytes
443
            );
444
        }
445

446
        assert_eq!(
38,210✔
447
            self.dtype(),
38,210✔
448
            result.dtype(),
38,210✔
UNCOV
449
            "optimize() changed DType from {} to {}",
×
UNCOV
450
            self.dtype(),
×
451
            result.dtype()
×
452
        );
453
        assert_eq!(
38,210✔
454
            result.len(),
38,210✔
455
            self.len(),
38,210✔
UNCOV
456
            "optimize() changed len from {} to {}",
×
UNCOV
457
            self.len(),
×
UNCOV
458
            result.len()
×
459
        );
460

461
        Ok(result)
38,210✔
462
    }
38,210✔
463

464
    fn is_valid(&self, index: usize) -> VortexResult<bool> {
5,999,990✔
465
        if index >= self.len() {
5,999,990✔
UNCOV
466
            vortex_bail!(OutOfBounds: index, 0, self.len());
×
467
        }
5,999,990✔
468
        <V::ValidityVTable as ValidityVTable<V>>::is_valid(&self.0, index)
5,999,990✔
469
    }
5,999,990✔
470

471
    fn is_invalid(&self, index: usize) -> VortexResult<bool> {
3,543,168✔
472
        self.is_valid(index).map(|valid| !valid)
3,543,168✔
473
    }
3,543,168✔
474

475
    fn all_valid(&self) -> VortexResult<bool> {
3,160,263✔
476
        <V::ValidityVTable as ValidityVTable<V>>::all_valid(&self.0)
3,160,263✔
477
    }
3,160,263✔
478

479
    fn all_invalid(&self) -> VortexResult<bool> {
161,915✔
480
        <V::ValidityVTable as ValidityVTable<V>>::all_invalid(&self.0)
161,915✔
481
    }
161,915✔
482

483
    fn valid_count(&self) -> VortexResult<usize> {
54,586✔
484
        if let Some(Precision::Exact(invalid_count)) =
4,362✔
485
            self.statistics().get_as::<usize>(Stat::NullCount)
54,586✔
486
        {
487
            return Ok(self.len() - invalid_count);
4,362✔
488
        }
50,224✔
489

490
        let count = <V::ValidityVTable as ValidityVTable<V>>::valid_count(&self.0)?;
50,224✔
491
        assert!(count <= self.len(), "Valid count exceeds array length");
50,224✔
492

493
        self.statistics()
50,224✔
494
            .set(Stat::NullCount, Precision::exact(self.len() - count));
50,224✔
495

50,224✔
496
        Ok(count)
50,224✔
497
    }
54,586✔
498

499
    fn invalid_count(&self) -> VortexResult<usize> {
12,595✔
500
        if let Some(Precision::Exact(invalid_count)) =
3,497✔
501
            self.statistics().get_as::<usize>(Stat::NullCount)
12,595✔
502
        {
503
            return Ok(invalid_count);
3,497✔
504
        }
9,098✔
505

506
        let count = <V::ValidityVTable as ValidityVTable<V>>::invalid_count(&self.0)?;
9,098✔
507
        assert!(count <= self.len(), "Invalid count exceeds array length");
9,098✔
508

509
        self.statistics()
9,098✔
510
            .set(Stat::NullCount, Precision::exact(count));
9,098✔
511

9,098✔
512
        Ok(count)
9,098✔
513
    }
12,595✔
514

515
    fn validity_mask(&self) -> VortexResult<Mask> {
241,925✔
516
        let mask = <V::ValidityVTable as ValidityVTable<V>>::validity_mask(&self.0)?;
241,925✔
517
        assert_eq!(mask.len(), self.len(), "Validity mask length mismatch");
241,925✔
518
        Ok(mask)
241,925✔
519
    }
241,925✔
520

521
    fn to_canonical(&self) -> VortexResult<Canonical> {
290,067✔
522
        let canonical = <V::CanonicalVTable as CanonicalVTable<V>>::canonicalize(&self.0)?;
290,067✔
523
        assert_eq!(
290,067✔
524
            self.len(),
290,067✔
525
            canonical.as_ref().len(),
290,067✔
UNCOV
526
            "Canonical length mismatch {}. Expected {} but encoded into {}.",
×
UNCOV
527
            self.encoding_id(),
×
UNCOV
528
            self.len(),
×
UNCOV
529
            canonical.as_ref().len()
×
530
        );
531
        assert_eq!(
290,067✔
532
            self.dtype(),
290,067✔
533
            canonical.as_ref().dtype(),
290,067✔
UNCOV
534
            "Canonical dtype mismatch {}. Expected {} but encoded into {}.",
×
UNCOV
535
            self.encoding_id(),
×
UNCOV
536
            self.dtype(),
×
537
            canonical.as_ref().dtype()
×
538
        );
539
        canonical.as_ref().statistics().inherit(self.statistics());
290,067✔
540
        Ok(canonical)
290,067✔
541
    }
290,067✔
542

543
    fn append_to_builder(&self, builder: &mut dyn ArrayBuilder) -> VortexResult<()> {
42,649✔
544
        if builder.dtype() != self.dtype() {
42,649✔
545
            vortex_bail!(
×
546
                "Builder dtype mismatch: expected {}, got {}",
×
547
                self.dtype(),
×
548
                builder.dtype(),
×
UNCOV
549
            );
×
550
        }
42,649✔
551
        let len = builder.len();
42,649✔
552

42,649✔
553
        <V::CanonicalVTable as CanonicalVTable<V>>::append_to_builder(&self.0, builder)?;
42,649✔
554
        assert_eq!(
42,649✔
555
            len + self.len(),
42,649✔
556
            builder.len(),
42,649✔
557
            "Builder length mismatch after writing array for encoding {}",
×
558
            self.encoding_id(),
×
559
        );
560
        Ok(())
42,649✔
561
    }
42,649✔
562

563
    fn statistics(&self) -> StatsSetRef<'_> {
1,753,784✔
564
        <V::ArrayVTable as ArrayVTable<V>>::stats(&self.0)
1,753,784✔
565
    }
1,753,784✔
566

UNCOV
567
    fn with_children(&self, children: &[ArrayRef]) -> VortexResult<ArrayRef> {
×
568
        struct ReplacementChildren<'a> {
569
            children: &'a [ArrayRef],
570
        }
571

572
        impl ArrayChildren for ReplacementChildren<'_> {
UNCOV
573
            fn get(&self, index: usize, dtype: &DType, len: usize) -> VortexResult<ArrayRef> {
×
UNCOV
574
                if index >= self.children.len() {
×
UNCOV
575
                    vortex_bail!(OutOfBounds: index, 0, self.children.len());
×
UNCOV
576
                }
×
UNCOV
577
                let child = &self.children[index];
×
578
                if child.len() != len {
×
UNCOV
579
                    vortex_bail!(
×
UNCOV
580
                        "Child length mismatch: expected {}, got {}",
×
UNCOV
581
                        len,
×
UNCOV
582
                        child.len()
×
UNCOV
583
                    );
×
584
                }
×
585
                if child.dtype() != dtype {
×
586
                    vortex_bail!(
×
587
                        "Child dtype mismatch: expected {}, got {}",
×
588
                        dtype,
×
589
                        child.dtype()
×
590
                    );
×
591
                }
×
592
                Ok(child.clone())
×
593
            }
×
594

595
            fn len(&self) -> usize {
×
596
                self.children.len()
×
597
            }
×
598
        }
599

600
        let metadata = self.metadata()?.ok_or_else(|| {
×
601
            vortex_err!("Cannot replace children for arrays that do not support serialization")
×
602
        })?;
×
603

604
        // Replace the children of the array by re-building the array from parts.
UNCOV
605
        self.encoding().build(
×
606
            self.dtype(),
×
607
            self.len(),
×
608
            &metadata,
×
UNCOV
609
            &self.buffers(),
×
UNCOV
610
            &ReplacementChildren { children },
×
611
        )
×
612
    }
×
613

614
    fn invoke(
36,959✔
615
        &self,
36,959✔
616
        compute_fn: &ComputeFn,
36,959✔
617
        args: &InvocationArgs,
36,959✔
618
    ) -> VortexResult<Option<Output>> {
36,959✔
619
        <V::ComputeVTable as ComputeVTable<V>>::invoke(&self.0, compute_fn, args)
36,959✔
620
    }
36,959✔
621
}
622

623
impl<V: VTable> ArrayVisitor for ArrayAdapter<V> {
624
    fn children(&self) -> Vec<ArrayRef> {
393,442✔
625
        struct ChildrenCollector {
626
            children: Vec<ArrayRef>,
627
        }
628

629
        impl ArrayChildVisitor for ChildrenCollector {
630
            fn visit_child(&mut self, _name: &str, array: &dyn Array) {
146,147✔
631
                self.children.push(array.to_array());
146,147✔
632
            }
146,147✔
633
        }
634

635
        let mut collector = ChildrenCollector {
393,442✔
636
            children: Vec::new(),
393,442✔
637
        };
393,442✔
638
        <V::VisitorVTable as VisitorVTable<V>>::visit_children(&self.0, &mut collector);
393,442✔
639
        collector.children
393,442✔
640
    }
393,442✔
641

UNCOV
642
    fn nchildren(&self) -> usize {
×
UNCOV
643
        <V::VisitorVTable as VisitorVTable<V>>::nchildren(&self.0)
×
UNCOV
644
    }
×
645

646
    fn children_names(&self) -> Vec<String> {
683✔
647
        struct ChildNameCollector {
648
            names: Vec<String>,
649
        }
650

651
        impl ArrayChildVisitor for ChildNameCollector {
652
            fn visit_child(&mut self, name: &str, _array: &dyn Array) {
469✔
653
                self.names.push(name.to_string());
469✔
654
            }
469✔
655
        }
656

657
        let mut collector = ChildNameCollector { names: Vec::new() };
683✔
658
        <V::VisitorVTable as VisitorVTable<V>>::visit_children(&self.0, &mut collector);
683✔
659
        collector.names
683✔
660
    }
683✔
661

UNCOV
662
    fn named_children(&self) -> Vec<(String, ArrayRef)> {
×
663
        struct NamedChildrenCollector {
664
            children: Vec<(String, ArrayRef)>,
665
        }
666

667
        impl ArrayChildVisitor for NamedChildrenCollector {
UNCOV
668
            fn visit_child(&mut self, name: &str, array: &dyn Array) {
×
UNCOV
669
                self.children.push((name.to_string(), array.to_array()));
×
UNCOV
670
            }
×
671
        }
672

673
        let mut collector = NamedChildrenCollector {
×
UNCOV
674
            children: Vec::new(),
×
UNCOV
675
        };
×
UNCOV
676

×
UNCOV
677
        <V::VisitorVTable as VisitorVTable<V>>::visit_children(&self.0, &mut collector);
×
UNCOV
678
        collector.children
×
679
    }
×
680

681
    fn buffers(&self) -> Vec<ByteBuffer> {
324,981✔
682
        struct BufferCollector {
683
            buffers: Vec<ByteBuffer>,
684
        }
685

686
        impl ArrayBufferVisitor for BufferCollector {
687
            fn visit_buffer(&mut self, buffer: &ByteBuffer) {
371,261✔
688
                self.buffers.push(buffer.clone());
371,261✔
689
            }
371,261✔
690
        }
691

692
        let mut collector = BufferCollector {
324,981✔
693
            buffers: Vec::new(),
324,981✔
694
        };
324,981✔
695
        <V::VisitorVTable as VisitorVTable<V>>::visit_buffers(&self.0, &mut collector);
324,981✔
696
        collector.buffers
324,981✔
697
    }
324,981✔
698

699
    fn nbuffers(&self) -> usize {
44,210✔
700
        <V::VisitorVTable as VisitorVTable<V>>::nbuffers(&self.0)
44,210✔
701
    }
44,210✔
702

703
    fn metadata(&self) -> VortexResult<Option<Vec<u8>>> {
48,302✔
704
        Ok(<V::SerdeVTable as SerdeVTable<V>>::metadata(&self.0)?.map(|m| m.serialize()))
48,302✔
705
    }
48,302✔
706

707
    fn metadata_fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
683✔
708
        match <V::SerdeVTable as SerdeVTable<V>>::metadata(&self.0) {
683✔
UNCOV
709
            Err(e) => write!(f, "<serde error: {e}>"),
×
UNCOV
710
            Ok(None) => write!(f, "<serde not supported>"),
×
711
            Ok(Some(metadata)) => Debug::fmt(&metadata, f),
683✔
712
        }
713
    }
683✔
714
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc