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

vortex-data / vortex / 17045413678

18 Aug 2025 03:43PM UTC coverage: 86.065% (-1.8%) from 87.913%
17045413678

Pull #4215

github

web-flow
Merge 2657b4c8e into cb2220961
Pull Request #4215: Ji/vectors

136 of 1803 new or added lines in 42 files covered. (7.54%)

127 existing lines in 26 files now uncovered.

56918 of 66134 relevant lines covered (86.06%)

612050.14 hits per line

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

90.36
/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, Nullability};
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 {
531,490✔
45
        self.len() == 0
531,490✔
46
    }
531,490✔
47

316✔
48
    /// Returns the logical Vortex [`DType`] of the array.
316✔
49
    fn dtype(&self) -> &DType;
316✔
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,838,983✔
65
        self.encoding_id() == encoding
4,838,983✔
66
    }
4,838,983✔
67

8✔
68
    /// Returns whether this array is an arrow encoding.
8✔
69
    // TODO(ngates): this shouldn't live here.
8✔
70
    fn is_arrow(&self) -> bool {
48,212✔
71
        self.is_encoding(NullEncoding.id())
48,212✔
72
            || self.is_encoding(BoolEncoding.id())
48,212✔
73
            || self.is_encoding(PrimitiveEncoding.id())
38,879✔
74
            || self.is_encoding(VarBinEncoding.id())
25,449✔
75
            || self.is_encoding(VarBinViewEncoding.id())
25,449✔
76
    }
48,212✔
77

78
    /// Whether the array is of a canonical encoding.
79
    // TODO(ngates): this shouldn't live here.
80
    fn is_canonical(&self) -> bool {
763,692✔
81
        self.is_encoding(NullEncoding.id())
763,692✔
82
            || self.is_encoding(BoolEncoding.id())
763,692✔
83
            || self.is_encoding(PrimitiveEncoding.id())
748,522✔
84
            || self.is_encoding(DecimalEncoding.id())
477,696✔
85
            || self.is_encoding(StructEncoding.id())
475,697✔
86
            || self.is_encoding(ListEncoding.id())
473,710✔
87
            || self.is_encoding(VarBinViewEncoding.id())
473,388✔
88
            || self.is_encoding(ExtensionEncoding.id())
466,144✔
89
    }
763,692✔
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 {
4,069,011✔
153
        self.as_ref().as_any()
4,069,011✔
154
    }
4,069,011✔
155

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

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

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

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

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

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

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

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

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

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

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

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

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

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

212
    fn to_canonical(&self) -> VortexResult<Canonical> {
4,312,218✔
213
        self.as_ref().to_canonical()
4,312,218✔
214
    }
4,312,218✔
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,834,159✔
221
        self.as_ref().statistics()
4,834,159✔
222
    }
4,834,159✔
223

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

228
    fn invoke(
576,714✔
229
        &self,
576,714✔
230
        compute_fn: &ComputeFn,
576,714✔
231
        args: &InvocationArgs,
576,404✔
232
    ) -> VortexResult<Option<Output>> {
576,404✔
233
        self.as_ref().invoke(compute_fn, args)
576,404✔
234
    }
576,404✔
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 {
NEW
244
        self.to_array()
×
NEW
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 {
428✔
251
        self.as_opt::<V>().vortex_expect("Failed to downcast")
428✔
252
    }
428✔
253

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

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

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

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

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

290
    /// Total size of the array in bytes, including all children and buffers.
291
    pub fn nbytes(&self) -> u64 {
192,356✔
292
        let mut nbytes = 0;
192,356✔
293
        for array in self.depth_first_traversal() {
268,951✔
294
            for buffer in array.buffers() {
317,197✔
295
                nbytes += buffer.len() as u64;
316,924✔
296
            }
316,924✔
297
        }
298
        nbytes
192,356✔
299
    }
192,356✔
300
}
301

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

290✔
307
impl IntoArray for ArrayRef {
246✔
308
    fn into_array(self) -> ArrayRef {
5,344✔
309
        self
5,098✔
310
    }
5,306✔
311
}
208✔
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
}
12✔
321

12✔
322
/// Adapter struct used to lift the [`VTable`] trait into an object-safe [`Array`]
12✔
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> ArrayAdapter<V> {
332
    /// Provide a reference to the underlying array held within the adapter.
333
    pub fn as_inner(&self) -> &V::Array {
334
        &self.0
335
    }
336

337
    /// Unwrap into the inner array type, consuming the adapter.
338
    pub fn into_inner(self) -> V::Array {
339
        self.0
340
    }
341
}
342

343
impl<V: VTable> Debug for ArrayAdapter<V> {
344
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
345
        self.0.fmt(f)
×
346
    }
×
347
}
348

349
impl<V: VTable> Array for ArrayAdapter<V> {
350
    fn as_any(&self) -> &dyn Any {
8,153,177✔
351
        self
8,153,177✔
352
    }
8,153,177✔
353

354
    fn to_array(&self) -> ArrayRef {
757,651✔
355
        Arc::new(ArrayAdapter::<V>(self.0.clone()))
757,651✔
356
    }
757,651✔
357

358
    fn len(&self) -> usize {
201,274,619✔
359
        <V::ArrayVTable as ArrayVTable<V>>::len(&self.0)
201,274,619✔
360
    }
201,274,619✔
361

362
    fn dtype(&self) -> &DType {
375,902,151✔
363
        <V::ArrayVTable as ArrayVTable<V>>::dtype(&self.0)
375,902,151✔
364
    }
375,902,151✔
365

366
    fn encoding(&self) -> EncodingRef {
30,994✔
367
        V::encoding(&self.0)
30,994✔
368
    }
30,994✔
369

370
    fn encoding_id(&self) -> EncodingId {
3,497,452✔
371
        V::encoding(&self.0).id()
3,497,452✔
372
    }
3,497,452✔
373

374
    fn slice(&self, start: usize, stop: usize) -> VortexResult<ArrayRef> {
2,865,230✔
375
        if start == 0 && stop == self.len() {
2,865,230✔
376
            return Ok(self.to_array());
144,860✔
377
        }
2,720,370✔
378

40✔
379
        if start > self.len() {
2,720,410✔
380
            vortex_bail!(OutOfBounds: start, 0, self.len());
40✔
381
        }
2,720,370✔
382
        if stop > self.len() {
2,720,388✔
383
            vortex_bail!(OutOfBounds: stop, 0, self.len());
18✔
384
        }
2,720,388✔
385
        if start > stop {
2,720,370✔
386
            vortex_bail!("start ({start}) must be <= stop ({stop})");
176✔
387
        }
2,720,546✔
388
        if start == stop {
2,720,386✔
389
            return Ok(Canonical::empty(self.dtype()).into_array());
614✔
390
        }
2,719,916✔
391

160✔
392
        let sliced = <V::OperationsVTable as OperationsVTable<V>>::slice(&self.0, start, stop)?;
2,719,916✔
393

160✔
394
        assert_eq!(
2,720,076✔
395
            sliced.len(),
2,719,916✔
396
            stop - start,
2,720,076✔
397
            "Slice length mismatch {}",
160✔
398
            self.encoding_id()
×
399
        );
160✔
400

160✔
401
        // Slightly more expensive, so only do this in debug builds.
402
        debug_assert_eq!(
2,720,076✔
403
            sliced.dtype(),
2,719,916✔
404
            self.dtype(),
2,720,076✔
405
            "Slice dtype mismatch {}",
406
            self.encoding_id()
160✔
407
        );
160✔
408

160✔
409
        // Propagate some stats from the original array to the sliced array.
410
        if !sliced.is::<ConstantVTable>() {
2,719,916✔
411
            self.statistics().with_iter(|iter| {
2,586,068✔
412
                sliced.statistics().inherit(iter.filter(|(stat, value)| {
2,641,658✔
413
                    matches!(
149,888✔
414
                        stat,
195,760✔
415
                        Stat::IsConstant | Stat::IsSorted | Stat::IsStrictSorted
160✔
416
                    ) && value.as_ref().as_exact().is_some_and(|v| {
45,872✔
417
                        Scalar::new(DType::Bool(Nullability::NonNullable), v.clone())
45,712✔
418
                            .as_bool()
45,712✔
419
                            .value()
45,712✔
420
                            .unwrap_or_default()
45,712✔
421
                    })
45,712✔
422
                }));
195,760✔
423
            });
2,586,228✔
424
        }
134,768✔
425

740✔
426
        Ok(sliced)
2,720,836✔
427
    }
2,856,142✔
428

180✔
429
    fn scalar_at(&self, index: usize) -> VortexResult<Scalar> {
64,239,444✔
430
        if index >= self.len() {
64,239,444✔
431
            vortex_bail!(OutOfBounds: index, 0, self.len());
188✔
432
        }
64,239,436✔
433
        if self.is_invalid(index)? {
64,239,436✔
434
            return Ok(Scalar::null(self.dtype().clone()));
3,900,675✔
435
        }
60,339,661✔
436
        let scalar = <V::OperationsVTable as OperationsVTable<V>>::scalar_at(&self.0, index)?;
60,339,501✔
437
        assert_eq!(self.dtype(), scalar.dtype(), "Scalar dtype mismatch");
60,339,501✔
438
        Ok(scalar)
60,339,661✔
439
    }
64,239,440✔
440

441
    fn is_valid(&self, index: usize) -> VortexResult<bool> {
76,839,760✔
442
        if index >= self.len() {
76,839,760✔
UNCOV
443
            vortex_bail!(OutOfBounds: index, 0, self.len());
×
444
        }
76,839,760✔
445
        <V::ValidityVTable as ValidityVTable<V>>::is_valid(&self.0, index)
76,839,760✔
446
    }
76,839,750✔
447

10✔
448
    fn is_invalid(&self, index: usize) -> VortexResult<bool> {
64,242,642✔
449
        self.is_valid(index).map(|valid| !valid)
64,242,642✔
450
    }
64,242,642✔
451

10✔
452
    fn all_valid(&self) -> VortexResult<bool> {
19,348,676✔
453
        <V::ValidityVTable as ValidityVTable<V>>::all_valid(&self.0)
19,348,686✔
454
    }
19,348,686✔
455

456
    fn all_invalid(&self) -> VortexResult<bool> {
474,033✔
457
        <V::ValidityVTable as ValidityVTable<V>>::all_invalid(&self.0)
474,033✔
458
    }
474,033✔
459

460
    fn valid_count(&self) -> VortexResult<usize> {
87,563✔
461
        if let Some(Precision::Exact(invalid_count)) =
12,402✔
462
            self.statistics().get_as::<usize>(Stat::NullCount)
87,563✔
463
        {
464
            return Ok(self.len() - invalid_count);
12,440✔
465
        }
75,209✔
466

48✔
467
        let count = <V::ValidityVTable as ValidityVTable<V>>::valid_count(&self.0)?;
75,161✔
468
        assert!(count <= self.len(), "Valid count exceeds array length");
75,319✔
469

158✔
470
        self.statistics()
75,319✔
471
            .set(Stat::NullCount, Precision::exact(self.len() - count));
75,161✔
472

88✔
473
        Ok(count)
75,179✔
474
    }
87,641✔
475

476
    fn invalid_count(&self) -> VortexResult<usize> {
13,752✔
477
        if let Some(Precision::Exact(invalid_count)) =
376✔
478
            self.statistics().get_as::<usize>(Stat::NullCount)
13,734✔
479
        {
70✔
480
            return Ok(invalid_count);
376✔
481
        }
13,428✔
482

70✔
483
        let count = <V::ValidityVTable as ValidityVTable<V>>::invalid_count(&self.0)?;
13,498✔
484
        assert!(count <= self.len(), "Invalid count exceeds array length");
13,428✔
485

70✔
486
        self.statistics()
13,516✔
487
            .set(Stat::NullCount, Precision::exact(count));
13,428✔
488

18✔
489
        Ok(count)
13,428✔
490
    }
13,752✔
491

492
    fn validity_mask(&self) -> VortexResult<Mask> {
869,125✔
493
        let mask = <V::ValidityVTable as ValidityVTable<V>>::validity_mask(&self.0)?;
869,143✔
494
        assert_eq!(mask.len(), self.len(), "Validity mask length mismatch");
869,125✔
495
        Ok(mask)
869,143✔
496
    }
869,143✔
497

498
    fn to_canonical(&self) -> VortexResult<Canonical> {
3,724,514✔
499
        let canonical = <V::CanonicalVTable as CanonicalVTable<V>>::canonicalize(&self.0)?;
3,724,514✔
500
        assert_eq!(
3,724,496✔
501
            self.len(),
3,724,514✔
502
            canonical.as_ref().len(),
3,724,514✔
503
            "Canonical length mismatch {}. Expected {} but encoded into {}.",
504
            self.encoding_id(),
426✔
505
            self.len(),
426✔
506
            canonical.as_ref().len()
426✔
507
        );
426✔
508
        assert_eq!(
3,724,922✔
509
            self.dtype(),
3,724,496✔
510
            canonical.as_ref().dtype(),
3,724,858✔
511
            "Canonical dtype mismatch {}. Expected {} but encoded into {}.",
362✔
512
            self.encoding_id(),
362✔
513
            self.dtype(),
362✔
514
            canonical.as_ref().dtype()
362✔
515
        );
516
        canonical
3,724,496✔
517
            .as_ref()
3,724,496✔
518
            .statistics()
3,724,496✔
519
            .replace(self.statistics().to_owned());
3,724,496✔
520
        Ok(canonical)
3,724,858✔
521
    }
3,724,858✔
522

362✔
523
    fn append_to_builder(&self, builder: &mut dyn ArrayBuilder) -> VortexResult<()> {
54,426✔
524
        if builder.dtype() != self.dtype() {
54,426✔
525
            vortex_bail!(
×
526
                "Builder dtype mismatch: expected {}, got {}",
×
527
                self.dtype(),
528
                builder.dtype(),
362✔
529
            );
362✔
530
        }
54,788✔
531
        let len = builder.len();
54,788✔
532

362✔
533
        <V::CanonicalVTable as CanonicalVTable<V>>::append_to_builder(&self.0, builder)?;
54,788✔
534
        assert_eq!(
54,426✔
535
            len + self.len(),
54,618✔
536
            builder.len(),
54,618✔
537
            "Builder length mismatch after writing array for encoding {}",
×
538
            self.encoding_id(),
×
539
        );
540
        Ok(())
54,426✔
541
    }
54,426✔
542

192✔
543
    fn statistics(&self) -> StatsSetRef<'_> {
16,203,680✔
544
        <V::ArrayVTable as ArrayVTable<V>>::stats(&self.0)
16,203,488✔
545
    }
16,203,680✔
546

192✔
547
    fn with_children(&self, children: &[ArrayRef]) -> VortexResult<ArrayRef> {
192✔
548
        struct ReplacementChildren<'a> {
192✔
549
            children: &'a [ArrayRef],
550
        }
551

552
        impl ArrayChildren for ReplacementChildren<'_> {
192✔
553
            fn get(&self, index: usize, dtype: &DType, len: usize) -> VortexResult<ArrayRef> {
192✔
554
                if index >= self.children.len() {
555
                    vortex_bail!(OutOfBounds: index, 0, self.children.len());
1,994✔
556
                }
1,994✔
557
                let child = &self.children[index];
1,994✔
558
                if child.len() != len {
559
                    vortex_bail!(
×
560
                        "Child length mismatch: expected {}, got {}",
561
                        len,
562
                        child.len()
563
                    );
564
                }
565
                if child.dtype() != dtype {
×
566
                    vortex_bail!(
×
567
                        "Child dtype mismatch: expected {}, got {}",
×
568
                        dtype,
569
                        child.dtype()
×
570
                    );
571
                }
×
572
                Ok(child.clone())
×
573
            }
574

575
            fn len(&self) -> usize {
576
                self.children.len()
×
577
            }
×
578
        }
579

580
        let metadata = self.metadata()?.ok_or_else(|| {
581
            vortex_err!("Cannot replace children for arrays that do not support serialization")
×
582
        })?;
583

584
        // Replace the children of the array by re-building the array from parts.
585
        self.encoding().build(
×
586
            self.dtype(),
587
            self.len(),
×
588
            &metadata,
×
589
            &self.buffers(),
×
590
            &ReplacementChildren { children },
591
        )
592
    }
×
593

594
    fn invoke(
485,769✔
595
        &self,
485,769✔
596
        compute_fn: &ComputeFn,
485,769✔
597
        args: &InvocationArgs,
485,769✔
598
    ) -> VortexResult<Option<Output>> {
485,769✔
599
        <V::ComputeVTable as ComputeVTable<V>>::invoke(&self.0, compute_fn, args)
485,769✔
600
    }
485,769✔
601
}
602

603
impl<V: VTable> ArrayVisitor for ArrayAdapter<V> {
604
    fn children(&self) -> Vec<ArrayRef> {
368,319✔
605
        struct ChildrenCollector {
606
            children: Vec<ArrayRef>,
607
        }
608

609
        impl ArrayChildVisitor for ChildrenCollector {
610
            fn visit_child(&mut self, _name: &str, array: &dyn Array) {
149,299✔
611
                self.children.push(array.to_array());
149,299✔
612
            }
149,299✔
613
        }
614

615
        let mut collector = ChildrenCollector {
368,319✔
616
            children: Vec::new(),
368,319✔
617
        };
368,319✔
618
        <V::VisitorVTable as VisitorVTable<V>>::visit_children(&self.0, &mut collector);
368,319✔
619
        collector.children
368,319✔
620
    }
368,761✔
621

622
    fn nchildren(&self) -> usize {
623
        <V::VisitorVTable as VisitorVTable<V>>::nchildren(&self.0)
624
    }
625

626
    fn children_names(&self) -> Vec<String> {
919✔
627
        struct ChildNameCollector {
178✔
628
            names: Vec<String>,
178✔
629
        }
630

631
        impl ArrayChildVisitor for ChildNameCollector {
442✔
632
            fn visit_child(&mut self, name: &str, _array: &dyn Array) {
950✔
633
                self.names.push(name.to_string());
950✔
634
            }
950✔
635
        }
442✔
636

442✔
637
        let mut collector = ChildNameCollector { names: Vec::new() };
741✔
638
        <V::VisitorVTable as VisitorVTable<V>>::visit_children(&self.0, &mut collector);
741✔
639
        collector.names
741✔
640
    }
741✔
641

UNCOV
642
    fn named_children(&self) -> Vec<(String, ArrayRef)> {
×
643
        struct NamedChildrenCollector {
644
            children: Vec<(String, ArrayRef)>,
645
        }
646

647
        impl ArrayChildVisitor for NamedChildrenCollector {
UNCOV
648
            fn visit_child(&mut self, name: &str, array: &dyn Array) {
×
UNCOV
649
                self.children.push((name.to_string(), array.to_array()));
×
UNCOV
650
            }
×
651
        }
652

UNCOV
653
        let mut collector = NamedChildrenCollector {
×
UNCOV
654
            children: Vec::new(),
×
UNCOV
655
        };
×
656

657
        <V::VisitorVTable as VisitorVTable<V>>::visit_children(&self.0, &mut collector);
658
        collector.children
×
659
    }
660

661
    fn buffers(&self) -> Vec<ByteBuffer> {
281,605✔
662
        struct BufferCollector {
663
            buffers: Vec<ByteBuffer>,
664
        }
665

666
        impl ArrayBufferVisitor for BufferCollector {
667
            fn visit_buffer(&mut self, buffer: &ByteBuffer) {
345,289✔
668
                self.buffers.push(buffer.clone());
345,289✔
669
            }
345,289✔
670
        }
671

672
        let mut collector = BufferCollector {
281,605✔
673
            buffers: Vec::new(),
281,605✔
674
        };
281,605✔
675
        <V::VisitorVTable as VisitorVTable<V>>::visit_buffers(&self.0, &mut collector);
281,605✔
676
        collector.buffers
281,605✔
677
    }
281,935✔
678

679
    fn nbuffers(&self) -> usize {
56,133✔
680
        <V::VisitorVTable as VisitorVTable<V>>::nbuffers(&self.0)
56,133✔
681
    }
56,133✔
682

683
    fn metadata(&self) -> VortexResult<Option<Vec<u8>>> {
61,128✔
684
        Ok(<V::SerdeVTable as SerdeVTable<V>>::metadata(&self.0)?.map(|m| m.serialize()))
61,128✔
685
    }
61,128✔
686

687
    fn metadata_fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
741✔
688
        match <V::SerdeVTable as SerdeVTable<V>>::metadata(&self.0) {
1,071✔
689
            Err(e) => write!(f, "<serde error: {e}>"),
330✔
690
            Ok(None) => write!(f, "<serde not supported>"),
330✔
691
            Ok(Some(metadata)) => Debug::fmt(&metadata, f),
1,071✔
692
        }
330✔
693
    }
1,071✔
694
}
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