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

vortex-data / vortex / 16811137738

07 Aug 2025 05:13PM UTC coverage: 85.139% (+0.3%) from 84.847%
16811137738

Pull #4152

github

web-flow
Merge e081c672c into 30635faae
Pull Request #4152: ScalarValue operations must go via Scalar

375 of 392 new or added lines in 23 files covered. (95.66%)

22 existing lines in 9 files now uncovered.

50960 of 59855 relevant lines covered (85.14%)

565634.41 hits per line

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

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

4
pub mod display;
5
mod visitor;
6

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

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

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

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

37
    /// Returns the array as an [`ArrayRef`].
38
    fn to_array(&self) -> ArrayRef;
39

40
    /// Returns the length of the array.
41
    fn len(&self) -> usize;
42

43
    /// Returns whether the array is empty (has zero rows).
44
    fn is_empty(&self) -> bool {
495,509✔
45
        self.len() == 0
495,509✔
46
    }
495,509✔
47

48
    /// Returns the logical Vortex [`DType`] of the array.
49
    fn dtype(&self) -> &DType;
50

51
    /// Returns the encoding of the array.
52
    fn encoding(&self) -> EncodingRef;
53

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

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

60
    /// Fetch the scalar at the given index.
61
    fn scalar_at(&self, index: usize) -> VortexResult<Scalar>;
62

63
    /// Returns whether the array is of the given encoding.
64
    fn is_encoding(&self, encoding: EncodingId) -> bool {
4,791,271✔
65
        self.encoding_id() == encoding
4,791,271✔
66
    }
4,791,271✔
67

68
    /// Returns whether this array is an arrow encoding.
69
    // TODO(ngates): this shouldn't live here.
70
    fn is_arrow(&self) -> bool {
42,929✔
71
        self.is_encoding(NullEncoding.id())
42,929✔
72
            || self.is_encoding(BoolEncoding.id())
42,929✔
73
            || self.is_encoding(PrimitiveEncoding.id())
36,344✔
74
            || self.is_encoding(VarBinEncoding.id())
24,252✔
75
            || self.is_encoding(VarBinViewEncoding.id())
24,252✔
76
    }
42,929✔
77

78
    /// Whether the array is of a canonical encoding.
79
    // TODO(ngates): this shouldn't live here.
80
    fn is_canonical(&self) -> bool {
755,895✔
81
        self.is_encoding(NullEncoding.id())
755,895✔
82
            || self.is_encoding(BoolEncoding.id())
755,895✔
83
            || self.is_encoding(PrimitiveEncoding.id())
743,473✔
84
            || self.is_encoding(DecimalEncoding.id())
475,401✔
85
            || self.is_encoding(StructEncoding.id())
473,351✔
86
            || self.is_encoding(ListEncoding.id())
471,598✔
87
            || self.is_encoding(VarBinViewEncoding.id())
471,276✔
88
            || self.is_encoding(ExtensionEncoding.id())
463,942✔
89
    }
755,895✔
90

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

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

97
    /// Returns whether all items in the array are valid.
98
    ///
99
    /// This is usually cheaper than computing a precise `valid_count`.
100
    fn all_valid(&self) -> VortexResult<bool>;
101

102
    /// Returns whether the array is all invalid.
103
    ///
104
    /// This is usually cheaper than computing a precise `invalid_count`.
105
    fn all_invalid(&self) -> VortexResult<bool>;
106

107
    /// Returns the number of valid elements in the array.
108
    fn valid_count(&self) -> VortexResult<usize>;
109

110
    /// Returns the number of invalid elements in the array.
111
    fn invalid_count(&self) -> VortexResult<usize>;
112

113
    /// Returns the canonical validity mask for the array.
114
    fn validity_mask(&self) -> VortexResult<Mask>;
115

116
    /// Returns the canonical representation of the array.
117
    fn to_canonical(&self) -> VortexResult<Canonical>;
118

119
    /// Writes the array into the canonical builder.
120
    ///
121
    /// The [`DType`] of the builder must match that of the array.
122
    fn append_to_builder(&self, builder: &mut dyn ArrayBuilder) -> VortexResult<()>;
123

124
    /// Returns the statistics of the array.
125
    // TODO(ngates): change how this works. It's weird.
126
    fn statistics(&self) -> StatsSetRef<'_>;
127

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

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

151
impl Array for Arc<dyn Array> {
152
    fn as_any(&self) -> &dyn Any {
3,934,784✔
153
        self.as_ref().as_any()
3,934,784✔
154
    }
3,934,784✔
155

156
    fn to_array(&self) -> ArrayRef {
285,728✔
157
        self.clone()
285,728✔
158
    }
285,728✔
159

160
    fn len(&self) -> usize {
36,481,134✔
161
        self.as_ref().len()
36,481,134✔
162
    }
36,481,134✔
163

164
    fn dtype(&self) -> &DType {
12,291,877✔
165
        self.as_ref().dtype()
12,291,877✔
166
    }
12,291,877✔
167

168
    fn encoding(&self) -> EncodingRef {
23,355✔
169
        self.as_ref().encoding()
23,355✔
170
    }
23,355✔
171

172
    fn encoding_id(&self) -> EncodingId {
4,065,130✔
173
        self.as_ref().encoding_id()
4,065,130✔
174
    }
4,065,130✔
175

176
    fn slice(&self, start: usize, end: usize) -> VortexResult<ArrayRef> {
1,888,336✔
177
        self.as_ref().slice(start, end)
1,888,336✔
178
    }
1,888,336✔
179

180
    fn scalar_at(&self, index: usize) -> VortexResult<Scalar> {
50,289,735✔
181
        self.as_ref().scalar_at(index)
50,289,735✔
182
    }
50,289,735✔
183

184
    fn is_valid(&self, index: usize) -> VortexResult<bool> {
4,939,405✔
185
        self.as_ref().is_valid(index)
4,939,405✔
186
    }
4,939,405✔
187

188
    fn is_invalid(&self, index: usize) -> VortexResult<bool> {
516✔
189
        self.as_ref().is_invalid(index)
516✔
190
    }
516✔
191

192
    fn all_valid(&self) -> VortexResult<bool> {
209,839✔
193
        self.as_ref().all_valid()
209,839✔
194
    }
209,839✔
195

196
    fn all_invalid(&self) -> VortexResult<bool> {
283,463✔
197
        self.as_ref().all_invalid()
283,463✔
198
    }
283,463✔
199

200
    fn valid_count(&self) -> VortexResult<usize> {
11,895✔
201
        self.as_ref().valid_count()
11,895✔
202
    }
11,895✔
203

204
    fn invalid_count(&self) -> VortexResult<usize> {
8,458✔
205
        self.as_ref().invalid_count()
8,458✔
206
    }
8,458✔
207

208
    fn validity_mask(&self) -> VortexResult<Mask> {
36,877✔
209
        self.as_ref().validity_mask()
36,877✔
210
    }
36,877✔
211

212
    fn to_canonical(&self) -> VortexResult<Canonical> {
4,346,681✔
213
        self.as_ref().to_canonical()
4,346,681✔
214
    }
4,346,681✔
215

216
    fn append_to_builder(&self, builder: &mut dyn ArrayBuilder) -> VortexResult<()> {
51,734✔
217
        self.as_ref().append_to_builder(builder)
51,734✔
218
    }
51,734✔
219

220
    fn statistics(&self) -> StatsSetRef<'_> {
4,699,072✔
221
        self.as_ref().statistics()
4,699,072✔
222
    }
4,699,072✔
223

224
    fn with_children(&self, children: &[ArrayRef]) -> VortexResult<ArrayRef> {
×
225
        self.as_ref().with_children(children)
×
226
    }
×
227

228
    fn invoke(
572,783✔
229
        &self,
572,783✔
230
        compute_fn: &ComputeFn,
572,783✔
231
        args: &InvocationArgs,
572,783✔
232
    ) -> VortexResult<Option<Output>> {
572,783✔
233
        self.as_ref().invoke(compute_fn, args)
572,783✔
234
    }
572,783✔
235
}
236

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

240
impl ToOwned for dyn Array {
241
    type Owned = ArrayRef;
242

243
    fn to_owned(&self) -> Self::Owned {
×
244
        self.to_array()
×
245
    }
×
246
}
247

248
impl dyn Array + '_ {
249
    /// Returns the array downcast to the given `A`.
250
    pub fn as_<V: VTable>(&self) -> &V::Array {
425✔
251
        self.as_opt::<V>().vortex_expect("Failed to downcast")
425✔
252
    }
425✔
253

254
    /// Returns the array downcast to the given `A`.
255
    pub fn as_opt<V: VTable>(&self) -> Option<&V::Array> {
12,671,413✔
256
        self.as_any()
12,671,413✔
257
            .downcast_ref::<ArrayAdapter<V>>()
12,671,413✔
258
            .map(|array_adapter| &array_adapter.0)
12,671,413✔
259
    }
12,671,413✔
260

261
    /// Is self an array with encoding from vtable `V`.
262
    pub fn is<V: VTable>(&self) -> bool {
4,360,569✔
263
        self.as_opt::<V>().is_some()
4,360,569✔
264
    }
4,360,569✔
265

266
    pub fn is_constant(&self) -> bool {
1,127,125✔
267
        let opts = IsConstantOpts {
1,127,125✔
268
            cost: Cost::Specialized,
1,127,125✔
269
        };
1,127,125✔
270
        is_constant_opts(self, &opts)
1,127,125✔
271
            .inspect_err(|e| log::warn!("Failed to compute IsConstant: {e}"))
1,127,125✔
272
            .ok()
1,127,125✔
273
            .flatten()
1,127,125✔
274
            .unwrap_or_default()
1,127,125✔
275
    }
1,127,125✔
276

277
    pub fn is_constant_opts(&self, cost: Cost) -> bool {
×
278
        let opts = IsConstantOpts { cost };
×
279
        is_constant_opts(self, &opts)
×
280
            .inspect_err(|e| log::warn!("Failed to compute IsConstant: {e}"))
×
281
            .ok()
×
282
            .flatten()
×
283
            .unwrap_or_default()
×
284
    }
×
285

286
    pub fn as_constant(&self) -> Option<Scalar> {
540,367✔
287
        self.is_constant().then(|| self.scalar_at(0).ok()).flatten()
540,367✔
288
    }
540,367✔
289

290
    /// Total size of the array in bytes, including all children and buffers.
291
    pub fn nbytes(&self) -> u64 {
185,141✔
292
        let mut nbytes = 0;
185,141✔
293
        for array in self.depth_first_traversal() {
259,669✔
294
            for buffer in array.buffers() {
308,656✔
295
                nbytes += buffer.len() as u64;
308,656✔
296
            }
308,656✔
297
        }
298
        nbytes
185,141✔
299
    }
185,141✔
300
}
301

302
/// Trait for converting a type into a Vortex [`ArrayRef`].
303
pub trait IntoArray {
304
    fn into_array(self) -> ArrayRef;
305
}
306

307
impl IntoArray for ArrayRef {
308
    fn into_array(self) -> ArrayRef {
5,059✔
309
        self
5,059✔
310
    }
5,059✔
311
}
312

313
mod private {
314
    use super::*;
315

316
    pub trait Sealed {}
317

318
    impl<V: VTable> Sealed for ArrayAdapter<V> {}
319
    impl Sealed for Arc<dyn Array> {}
320
}
321

322
/// Adapter struct used to lift the [`VTable`] trait into an object-safe [`Array`]
323
/// implementation.
324
///
325
/// Since this is a unit struct with `repr(transparent)`, we are able to turn un-adapted array
326
/// structs into [`dyn Array`] using some cheeky casting inside [`std::ops::Deref`] and
327
/// [`AsRef`]. See the `vtable!` macro for more details.
328
#[repr(transparent)]
329
pub struct ArrayAdapter<V: VTable>(V::Array);
330

331
impl<V: VTable> Debug for ArrayAdapter<V> {
332
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
×
333
        self.0.fmt(f)
×
334
    }
×
335
}
336

337
impl<V: VTable> Array for ArrayAdapter<V> {
338
    fn as_any(&self) -> &dyn Any {
7,838,235✔
339
        self
7,838,235✔
340
    }
7,838,235✔
341

342
    fn to_array(&self) -> ArrayRef {
743,524✔
343
        Arc::new(ArrayAdapter::<V>(self.0.clone()))
743,524✔
344
    }
743,524✔
345

346
    fn len(&self) -> usize {
199,651,478✔
347
        <V::ArrayVTable as ArrayVTable<V>>::len(&self.0)
199,651,478✔
348
    }
199,651,478✔
349

350
    fn dtype(&self) -> &DType {
372,918,010✔
351
        <V::ArrayVTable as ArrayVTable<V>>::dtype(&self.0)
372,918,010✔
352
    }
372,918,010✔
353

354
    fn encoding(&self) -> EncodingRef {
28,754✔
355
        V::encoding(&self.0)
28,754✔
356
    }
28,754✔
357

358
    fn encoding_id(&self) -> EncodingId {
3,445,625✔
359
        V::encoding(&self.0).id()
3,445,625✔
360
    }
3,445,625✔
361

362
    fn slice(&self, start: usize, stop: usize) -> VortexResult<ArrayRef> {
2,856,586✔
363
        if start == 0 && stop == self.len() {
2,856,586✔
364
            return Ok(self.to_array());
135,442✔
365
        }
2,721,144✔
366

367
        if start > self.len() {
2,721,144✔
368
            vortex_bail!(OutOfBounds: start, 0, self.len());
×
369
        }
2,721,144✔
370
        if stop > self.len() {
2,721,144✔
371
            vortex_bail!(OutOfBounds: stop, 0, self.len());
×
372
        }
2,721,144✔
373
        if start > stop {
2,721,144✔
374
            vortex_bail!("start ({start}) must be <= stop ({stop})");
×
375
        }
2,721,144✔
376
        if start == stop {
2,721,144✔
377
            return Ok(Canonical::empty(self.dtype()).into_array());
454✔
378
        }
2,720,690✔
379

380
        let sliced = <V::OperationsVTable as OperationsVTable<V>>::slice(&self.0, start, stop)?;
2,720,690✔
381

382
        assert_eq!(
2,720,690✔
383
            sliced.len(),
2,720,690✔
384
            stop - start,
2,720,690✔
385
            "Slice length mismatch {}",
×
386
            self.encoding_id()
×
387
        );
388

389
        // Slightly more expensive, so only do this in debug builds.
390
        debug_assert_eq!(
2,720,690✔
391
            sliced.dtype(),
2,720,690✔
392
            self.dtype(),
2,720,690✔
393
            "Slice dtype mismatch {}",
×
394
            self.encoding_id()
×
395
        );
396

397
        // Propagate some stats from the original array to the sliced array.
398
        if !sliced.is::<ConstantVTable>() {
2,720,690✔
399
            self.statistics().with_iter(|iter| {
2,588,057✔
400
                sliced.statistics().inherit(iter.filter(|(stat, value)| {
2,641,220✔
401
                    matches!(
142,872✔
402
                        stat,
188,584✔
403
                        Stat::IsConstant | Stat::IsSorted | Stat::IsStrictSorted
404
                    ) && value.as_ref().as_exact().is_some_and(|v| {
45,712✔
405
                        v.as_bool()
45,712✔
406
                            .vortex_expect("must be a bool")
45,712✔
407
                            .unwrap_or_default()
45,712✔
408
                    })
45,712✔
409
                }));
103,942✔
410
            });
2,641,220✔
411
        }
173,004✔
412

5,424✔
413
        Ok(sliced)
2,669,471✔
414
    }
2,851,798✔
415

56,007✔
416
    fn scalar_at(&self, index: usize) -> VortexResult<Scalar> {
63,447,131✔
417
        if index >= self.len() {
63,505,634✔
418
            vortex_bail!(OutOfBounds: index, 0, self.len());
58,511✔
419
        }
63,447,123✔
420
        if self.is_invalid(index)? {
63,505,626✔
421
            return Ok(Scalar::null(self.dtype().clone()));
3,957,630✔
422
        }
59,547,996✔
423
        let scalar = <V::OperationsVTable as OperationsVTable<V>>::scalar_at(&self.0, index)?;
59,606,499✔
424
        assert_eq!(self.dtype(), scalar.dtype(), "Scalar dtype mismatch");
59,606,499✔
425
        Ok(scalar)
59,606,499✔
426
    }
63,505,634✔
427

58,503✔
428
    fn is_valid(&self, index: usize) -> VortexResult<bool> {
72,430,916✔
429
        if index >= self.len() {
76,102,511✔
430
            vortex_bail!(OutOfBounds: index, 0, self.len());
3,671,595✔
431
        }
72,430,916✔
432
        <V::ValidityVTable as ValidityVTable<V>>::is_valid(&self.0, index)
76,102,511✔
433
    }
76,102,511✔
434

3,671,595✔
435
    fn is_invalid(&self, index: usize) -> VortexResult<bool> {
63,447,613✔
436
        self.is_valid(index).map(|valid| !valid)
63,506,554✔
437
    }
63,506,554✔
438

58,941✔
439
    fn all_valid(&self) -> VortexResult<bool> {
19,281,665✔
440
        <V::ValidityVTable as ValidityVTable<V>>::all_valid(&self.0)
19,342,616✔
441
    }
19,342,616✔
442

60,951✔
443
    fn all_invalid(&self) -> VortexResult<bool> {
406,380✔
444
        <V::ValidityVTable as ValidityVTable<V>>::all_invalid(&self.0)
449,964✔
445
    }
449,964✔
446

43,584✔
447
    fn valid_count(&self) -> VortexResult<usize> {
65,725✔
448
        if let Some(Precision::Exact(invalid_count)) =
29,777✔
449
            self.statistics().get_as::<usize>(Stat::NullCount)
66,226✔
450
        {
18,279✔
451
            return Ok(self.len() - invalid_count);
11,498✔
452
        }
54,728✔
453

17,778✔
454
        let count = <V::ValidityVTable as ValidityVTable<V>>::valid_count(&self.0)?;
54,227✔
455
        assert!(count <= self.len(), "Valid count exceeds array length");
72,005✔
456

17,778✔
457
        self.statistics()
54,227✔
458
            .set(Stat::NullCount, Precision::exact(self.len() - count));
72,005✔
459

17,778✔
460
        Ok(count)
54,227✔
461
    }
83,503✔
462

18,279✔
463
    fn invalid_count(&self) -> VortexResult<usize> {
11,787✔
464
        if let Some(Precision::Exact(invalid_count)) =
1,908✔
465
            self.statistics().get_as::<usize>(Stat::NullCount)
11,820✔
466
        {
1,635✔
467
            return Ok(invalid_count);
273✔
468
        }
11,547✔
469

1,602✔
470
        let count = <V::ValidityVTable as ValidityVTable<V>>::invalid_count(&self.0)?;
11,514✔
471
        assert!(count <= self.len(), "Invalid count exceeds array length");
13,116✔
472

1,602✔
473
        self.statistics()
11,514✔
474
            .set(Stat::NullCount, Precision::exact(count));
13,116✔
475

1,602✔
476
        Ok(count)
11,514✔
477
    }
13,389✔
478

1,635✔
479
    fn validity_mask(&self) -> VortexResult<Mask> {
730,904✔
480
        let mask = <V::ValidityVTable as ValidityVTable<V>>::validity_mask(&self.0)?;
834,590✔
481
        assert_eq!(mask.len(), self.len(), "Validity mask length mismatch");
834,590✔
482
        Ok(mask)
834,590✔
483
    }
834,590✔
484

103,686✔
485
    fn to_canonical(&self) -> VortexResult<Canonical> {
3,612,238✔
486
        let canonical = <V::CanonicalVTable as CanonicalVTable<V>>::canonicalize(&self.0)?;
3,757,069✔
487
        assert_eq!(
3,757,069✔
488
            self.len(),
3,757,069✔
489
            canonical.as_ref().len(),
3,757,069✔
490
            "Canonical length mismatch {}. Expected {} but encoded into {}.",
144,831✔
491
            self.encoding_id(),
×
492
            self.len(),
×
493
            canonical.as_ref().len()
×
494
        );
495
        assert_eq!(
3,612,238✔
496
            self.dtype(),
3,757,069✔
497
            canonical.as_ref().dtype(),
3,757,069✔
498
            "Canonical dtype mismatch {}. Expected {} but encoded into {}.",
144,831✔
499
            self.encoding_id(),
×
500
            self.dtype(),
×
501
            canonical.as_ref().dtype()
×
502
        );
503
        canonical
3,612,238✔
504
            .as_ref()
3,757,069✔
505
            .statistics()
3,757,069✔
506
            .replace(self.statistics().to_owned());
3,757,069✔
507
        Ok(canonical)
3,757,069✔
508
    }
3,757,069✔
509

144,831✔
510
    fn append_to_builder(&self, builder: &mut dyn ArrayBuilder) -> VortexResult<()> {
24,882✔
511
        if builder.dtype() != self.dtype() {
54,426✔
512
            vortex_bail!(
29,544✔
513
                "Builder dtype mismatch: expected {}, got {}",
×
514
                self.dtype(),
×
515
                builder.dtype(),
×
516
            );
517
        }
24,882✔
518
        let len = builder.len();
54,426✔
519

29,544✔
520
        <V::CanonicalVTable as CanonicalVTable<V>>::append_to_builder(&self.0, builder)?;
24,882✔
521
        assert_eq!(
54,426✔
522
            len + self.len(),
54,426✔
523
            builder.len(),
54,426✔
524
            "Builder length mismatch after writing array for encoding {}",
29,544✔
525
            self.encoding_id(),
×
526
        );
527
        Ok(())
24,882✔
528
    }
54,426✔
529

29,544✔
530
    fn statistics(&self) -> StatsSetRef<'_> {
15,318,195✔
531
        <V::ArrayVTable as ArrayVTable<V>>::stats(&self.0)
16,083,219✔
532
    }
16,083,219✔
533

765,024✔
534
    fn with_children(&self, children: &[ArrayRef]) -> VortexResult<ArrayRef> {
535
        struct ReplacementChildren<'a> {
536
            children: &'a [ArrayRef],
537
        }
538

539
        impl ArrayChildren for ReplacementChildren<'_> {
540
            fn get(&self, index: usize, dtype: &DType, len: usize) -> VortexResult<ArrayRef> {
541
                if index >= self.children.len() {
×
542
                    vortex_bail!(OutOfBounds: index, 0, self.children.len());
×
543
                }
×
544
                let child = &self.children[index];
×
545
                if child.len() != len {
×
546
                    vortex_bail!(
×
547
                        "Child length mismatch: expected {}, got {}",
×
548
                        len,
549
                        child.len()
550
                    );
551
                }
552
                if child.dtype() != dtype {
×
553
                    vortex_bail!(
×
554
                        "Child dtype mismatch: expected {}, got {}",
×
555
                        dtype,
556
                        child.dtype()
557
                    );
558
                }
559
                Ok(child.clone())
×
560
            }
×
561

562
            fn len(&self) -> usize {
563
                self.children.len()
×
564
            }
×
565
        }
566

567
        let metadata = self.metadata()?.ok_or_else(|| {
568
            vortex_err!("Cannot replace children for arrays that do not support serialization")
×
569
        })?;
×
570

571
        // Replace the children of the array by re-building the array from parts.
572
        self.encoding().build(
573
            self.dtype(),
×
574
            self.len(),
×
575
            &metadata,
×
576
            &self.buffers(),
×
577
            &ReplacementChildren { children },
×
578
        )
×
579
    }
×
580

581
    fn invoke(
453,063✔
582
        &self,
481,113✔
583
        compute_fn: &ComputeFn,
481,113✔
584
        args: &InvocationArgs,
481,113✔
585
    ) -> VortexResult<Option<Output>> {
481,113✔
586
        <V::ComputeVTable as ComputeVTable<V>>::invoke(&self.0, compute_fn, args)
481,113✔
587
    }
481,113✔
588
}
28,050✔
589

590
impl<V: VTable> ArrayVisitor for ArrayAdapter<V> {
591
    fn children(&self) -> Vec<ArrayRef> {
265,412✔
592
        struct ChildrenCollector {
87,162✔
593
            children: Vec<ArrayRef>,
594
        }
595

596
        impl ArrayChildVisitor for ChildrenCollector {
597
            fn visit_child(&mut self, _name: &str, array: &dyn Array) {
110,587✔
598
                self.children.push(array.to_array());
142,435✔
599
            }
142,435✔
600
        }
31,848✔
601

602
        let mut collector = ChildrenCollector {
265,412✔
603
            children: Vec::new(),
352,574✔
604
        };
352,574✔
605
        <V::VisitorVTable as VisitorVTable<V>>::visit_children(&self.0, &mut collector);
352,574✔
606
        collector.children
352,574✔
607
    }
352,574✔
608

87,162✔
609
    fn nchildren(&self) -> usize {
610
        <V::VisitorVTable as VisitorVTable<V>>::nchildren(&self.0)
×
611
    }
×
612

613
    fn children_names(&self) -> Vec<String> {
741✔
614
        struct ChildNameCollector {
615
            names: Vec<String>,
616
        }
617

618
        impl ArrayChildVisitor for ChildNameCollector {
619
            fn visit_child(&mut self, name: &str, _array: &dyn Array) {
508✔
620
                self.names.push(name.to_string());
508✔
621
            }
508✔
622
        }
623

624
        let mut collector = ChildNameCollector { names: Vec::new() };
741✔
625
        <V::VisitorVTable as VisitorVTable<V>>::visit_children(&self.0, &mut collector);
741✔
626
        collector.names
741✔
627
    }
741✔
628

629
    fn named_children(&self) -> Vec<(String, ArrayRef)> {
630
        struct NamedChildrenCollector {
631
            children: Vec<(String, ArrayRef)>,
632
        }
633

634
        impl ArrayChildVisitor for NamedChildrenCollector {
635
            fn visit_child(&mut self, name: &str, array: &dyn Array) {
636
                self.children.push((name.to_string(), array.to_array()));
×
637
            }
×
638
        }
639

640
        let mut collector = NamedChildrenCollector {
641
            children: Vec::new(),
×
642
        };
×
643

644
        <V::VisitorVTable as VisitorVTable<V>>::visit_children(&self.0, &mut collector);
645
        collector.children
×
646
    }
×
647

648
    fn buffers(&self) -> Vec<ByteBuffer> {
198,465✔
649
        struct BufferCollector {
72,852✔
650
            buffers: Vec<ByteBuffer>,
651
        }
652

653
        impl ArrayBufferVisitor for BufferCollector {
654
            fn visit_buffer(&mut self, buffer: &ByteBuffer) {
214,792✔
655
                self.buffers.push(buffer.clone());
335,422✔
656
            }
335,422✔
657
        }
120,630✔
658

659
        let mut collector = BufferCollector {
198,465✔
660
            buffers: Vec::new(),
271,317✔
661
        };
271,317✔
662
        <V::VisitorVTable as VisitorVTable<V>>::visit_buffers(&self.0, &mut collector);
271,317✔
663
        collector.buffers
271,317✔
664
    }
271,317✔
665

72,852✔
666
    fn nbuffers(&self) -> usize {
42,828✔
667
        <V::VisitorVTable as VisitorVTable<V>>::nbuffers(&self.0)
52,542✔
668
    }
52,542✔
669

9,714✔
670
    fn metadata(&self) -> VortexResult<Option<Vec<u8>>> {
48,208✔
671
        Ok(<V::SerdeVTable as SerdeVTable<V>>::metadata(&self.0)?.map(|m| m.serialize()))
57,118✔
672
    }
57,118✔
673

8,910✔
674
    fn metadata_fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
741✔
675
        match <V::SerdeVTable as SerdeVTable<V>>::metadata(&self.0) {
741✔
UNCOV
676
            Err(e) => write!(f, "<serde error: {e}>"),
×
677
            Ok(None) => write!(f, "<serde not supported>"),
×
678
            Ok(Some(metadata)) => Debug::fmt(&metadata, f),
741✔
679
        }
680
    }
741✔
681
}
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