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

vortex-data / vortex / 16387130526

19 Jul 2025 09:05AM UTC coverage: 81.512% (-0.008%) from 81.52%
16387130526

push

github

web-flow
feat: duckdb workstealing (#3927)

Signed-off-by: Alexander Droste <alexander.droste@protonmail.com>

16 of 17 new or added lines in 1 file covered. (94.12%)

185 existing lines in 8 files now uncovered.

42000 of 51526 relevant lines covered (81.51%)

171508.11 hits per line

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

78.65
/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 {
219,361✔
48
        self.len() == 0
219,361✔
49
    }
219,361✔
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
    /// Returns whether the array is of the given encoding.
67
    fn is_encoding(&self, encoding: EncodingId) -> bool {
357,883✔
68
        self.encoding_id() == encoding
357,883✔
69
    }
357,883✔
70

71
    /// Returns whether this array is an arrow encoding.
72
    // TODO(ngates): this shouldn't live here.
73
    fn is_arrow(&self) -> bool {
8,813✔
74
        self.is_encoding(NullEncoding.id())
8,813✔
75
            || self.is_encoding(BoolEncoding.id())
8,813✔
76
            || self.is_encoding(PrimitiveEncoding.id())
7,662✔
77
            || self.is_encoding(VarBinEncoding.id())
5,688✔
78
            || self.is_encoding(VarBinViewEncoding.id())
5,688✔
79
    }
8,813✔
80

81
    /// Whether the array is of a canonical encoding.
82
    // TODO(ngates): this shouldn't live here.
83
    fn is_canonical(&self) -> bool {
51,608✔
84
        self.is_encoding(NullEncoding.id())
51,608✔
85
            || self.is_encoding(BoolEncoding.id())
51,608✔
86
            || self.is_encoding(PrimitiveEncoding.id())
50,068✔
87
            || self.is_encoding(DecimalEncoding.id())
34,378✔
88
            || self.is_encoding(StructEncoding.id())
33,065✔
89
            || self.is_encoding(ListEncoding.id())
31,788✔
90
            || self.is_encoding(VarBinViewEncoding.id())
31,786✔
91
            || self.is_encoding(ExtensionEncoding.id())
30,103✔
92
    }
51,608✔
93

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

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

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

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

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

113
    /// Returns the number of invalid elements in the array.
114
    fn invalid_count(&self) -> VortexResult<usize>;
115

116
    /// Returns the canonical validity mask for the array.
117
    fn validity_mask(&self) -> VortexResult<Mask>;
118

119
    /// Returns the canonical representation of the array.
120
    fn to_canonical(&self) -> VortexResult<Canonical>;
121

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

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

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

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

154
impl Array for Arc<dyn Array> {
155
    fn as_any(&self) -> &dyn Any {
565,714✔
156
        self.as_ref().as_any()
565,714✔
157
    }
565,714✔
158

159
    fn to_array(&self) -> ArrayRef {
131,208✔
160
        self.clone()
131,208✔
161
    }
131,208✔
162

163
    fn len(&self) -> usize {
1,076,654✔
164
        self.as_ref().len()
1,076,654✔
165
    }
1,076,654✔
166

167
    fn dtype(&self) -> &DType {
855,308✔
168
        self.as_ref().dtype()
855,308✔
169
    }
855,308✔
170

171
    fn encoding(&self) -> EncodingRef {
18,636✔
172
        self.as_ref().encoding()
18,636✔
173
    }
18,636✔
174

175
    fn encoding_id(&self) -> EncodingId {
317,136✔
176
        self.as_ref().encoding_id()
317,136✔
177
    }
317,136✔
178

179
    fn slice(&self, start: usize, end: usize) -> VortexResult<ArrayRef> {
35,767✔
180
        self.as_ref().slice(start, end)
35,767✔
181
    }
35,767✔
182

183
    fn scalar_at(&self, index: usize) -> VortexResult<Scalar> {
521,630✔
184
        self.as_ref().scalar_at(index)
521,630✔
185
    }
521,630✔
186

187
    fn is_valid(&self, index: usize) -> VortexResult<bool> {
31,957✔
188
        self.as_ref().is_valid(index)
31,957✔
189
    }
31,957✔
190

191
    fn is_invalid(&self, index: usize) -> VortexResult<bool> {
366✔
192
        self.as_ref().is_invalid(index)
366✔
193
    }
366✔
194

195
    fn all_valid(&self) -> VortexResult<bool> {
25,610✔
196
        self.as_ref().all_valid()
25,610✔
197
    }
25,610✔
198

199
    fn all_invalid(&self) -> VortexResult<bool> {
44,257✔
200
        self.as_ref().all_invalid()
44,257✔
201
    }
44,257✔
202

203
    fn valid_count(&self) -> VortexResult<usize> {
2,757✔
204
        self.as_ref().valid_count()
2,757✔
205
    }
2,757✔
206

207
    fn invalid_count(&self) -> VortexResult<usize> {
455✔
208
        self.as_ref().invalid_count()
455✔
209
    }
455✔
210

211
    fn validity_mask(&self) -> VortexResult<Mask> {
6,306✔
212
        self.as_ref().validity_mask()
6,306✔
213
    }
6,306✔
214

215
    fn to_canonical(&self) -> VortexResult<Canonical> {
228,934✔
216
        self.as_ref().to_canonical()
228,934✔
217
    }
228,934✔
218

219
    fn append_to_builder(&self, builder: &mut dyn ArrayBuilder) -> VortexResult<()> {
41,472✔
220
        self.as_ref().append_to_builder(builder)
41,472✔
221
    }
41,472✔
222

223
    fn statistics(&self) -> StatsSetRef<'_> {
400,342✔
224
        self.as_ref().statistics()
400,342✔
225
    }
400,342✔
226

UNCOV
227
    fn with_children(&self, children: &[ArrayRef]) -> VortexResult<ArrayRef> {
×
UNCOV
228
        self.as_ref().with_children(children)
×
UNCOV
229
    }
×
230

231
    fn invoke(
34,359✔
232
        &self,
34,359✔
233
        compute_fn: &ComputeFn,
34,359✔
234
        args: &InvocationArgs,
34,359✔
235
    ) -> VortexResult<Option<Output>> {
34,359✔
236
        self.as_ref().invoke(compute_fn, args)
34,359✔
237
    }
34,359✔
238
}
239

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

243
impl ToOwned for dyn Array {
244
    type Owned = ArrayRef;
245

UNCOV
246
    fn to_owned(&self) -> Self::Owned {
×
UNCOV
247
        self.to_array()
×
UNCOV
248
    }
×
249
}
250

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

257
    /// Returns the array downcast to the given `A`.
258
    pub fn as_opt<V: VTable>(&self) -> Option<&V::Array> {
1,537,426✔
259
        self.as_any()
1,537,426✔
260
            .downcast_ref::<ArrayAdapter<V>>()
1,537,426✔
261
            .map(|array_adapter| &array_adapter.0)
1,537,426✔
262
    }
1,537,426✔
263

264
    /// Is self an array with encoding from vtable `V`.
265
    pub fn is<V: VTable>(&self) -> bool {
9,826✔
266
        self.as_opt::<V>().is_some()
9,826✔
267
    }
9,826✔
268
}
269

270
impl dyn Array + '_ {
271
    /// Total size of the array in bytes, including all children and buffers.
272
    pub fn nbytes(&self) -> u64 {
156,652✔
273
        let mut nbytes = 0;
156,652✔
274
        for array in self.depth_first_traversal() {
220,191✔
275
            for buffer in array.buffers() {
251,946✔
276
                nbytes += buffer.len() as u64;
251,946✔
277
            }
251,946✔
278
        }
279
        nbytes
156,652✔
280
    }
156,652✔
281
}
282

283
mod private {
284
    use super::*;
285

286
    pub trait Sealed {}
287

288
    impl<V: VTable> Sealed for ArrayAdapter<V> {}
289
    impl Sealed for Arc<dyn Array> {}
290
}
291

292
/// Adapter struct used to lift the [`VTable`] trait into an object-safe [`Array`]
293
/// implementation.
294
///
295
/// Since this is a unit struct with `repr(transparent)`, we are able to turn un-adapted array
296
/// structs into [`dyn Array`] using some cheeky casting inside [`std::ops::Deref`] and
297
/// [`AsRef`]. See the `vtable!` macro for more details.
298
#[repr(transparent)]
299
pub struct ArrayAdapter<V: VTable>(V::Array);
300

301
impl<V: VTable> Debug for ArrayAdapter<V> {
UNCOV
302
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
×
UNCOV
303
        self.0.fmt(f)
×
UNCOV
304
    }
×
305
}
306

307
impl<V: VTable> Array for ArrayAdapter<V> {
308
    fn as_any(&self) -> &dyn Any {
1,451,706✔
309
        self
1,451,706✔
310
    }
1,451,706✔
311

312
    fn to_array(&self) -> ArrayRef {
319,328✔
313
        Arc::new(ArrayAdapter::<V>(self.0.clone()))
319,328✔
314
    }
319,328✔
315

316
    fn len(&self) -> usize {
13,678,302✔
317
        <V::ArrayVTable as ArrayVTable<V>>::len(&self.0)
13,678,302✔
318
    }
13,678,302✔
319

320
    fn dtype(&self) -> &DType {
28,318,719✔
321
        <V::ArrayVTable as ArrayVTable<V>>::dtype(&self.0)
28,318,719✔
322
    }
28,318,719✔
323

324
    fn encoding(&self) -> EncodingRef {
25,185✔
325
        V::encoding(&self.0)
25,185✔
326
    }
25,185✔
327

328
    fn encoding_id(&self) -> EncodingId {
351,339✔
329
        V::encoding(&self.0).id()
351,339✔
330
    }
351,339✔
331

332
    fn slice(&self, start: usize, stop: usize) -> VortexResult<ArrayRef> {
70,485✔
333
        if start == 0 && stop == self.len() {
70,485✔
334
            return Ok(self.to_array());
10,083✔
335
        }
60,402✔
336

337
        if start > self.len() {
60,402✔
UNCOV
338
            vortex_bail!(OutOfBounds: start, 0, self.len());
×
339
        }
60,402✔
340
        if stop > self.len() {
60,402✔
UNCOV
341
            vortex_bail!(OutOfBounds: stop, 0, self.len());
×
342
        }
60,402✔
343
        if start > stop {
60,402✔
UNCOV
344
            vortex_bail!("start ({start}) must be <= stop ({stop})");
×
345
        }
60,402✔
346

347
        if start == stop {
60,402✔
348
            return Ok(Canonical::empty(self.dtype()).into_array());
15✔
349
        }
60,387✔
350

351
        // We know that constant array don't need stats propagation, so we can avoid the overhead of
352
        // computing derived stats and merging them in.
353
        // TODO(ngates): skip the is_constant check here, it can force an expensive compute.
354
        // TODO(ngates): provide a means to slice an array _without_ propagating stats.
355
        let derived_stats = (!self.0.is_constant_opts(Cost::Negligible)).then(|| {
60,387✔
356
            let stats = self.statistics().to_owned();
51,004✔
357

358
            // an array that is not constant can become constant after slicing
359
            let is_constant = stats.get_as::<bool>(Stat::IsConstant);
51,004✔
360
            let is_sorted = stats.get_as::<bool>(Stat::IsSorted);
51,004✔
361
            let is_strict_sorted = stats.get_as::<bool>(Stat::IsStrictSorted);
51,004✔
362

363
            let mut stats = stats.keep_inexact_stats(&[
51,004✔
364
                Stat::Max,
51,004✔
365
                Stat::Min,
51,004✔
366
                Stat::NullCount,
51,004✔
367
                Stat::UncompressedSizeInBytes,
51,004✔
368
            ]);
51,004✔
369

370
            if is_constant == Some(Precision::Exact(true)) {
51,004✔
UNCOV
371
                stats.set(Stat::IsConstant, Precision::exact(true));
×
372
            }
51,004✔
373
            if is_sorted == Some(Precision::Exact(true)) {
51,004✔
374
                stats.set(Stat::IsSorted, Precision::exact(true));
1,165✔
375
            }
49,839✔
376
            if is_strict_sorted == Some(Precision::Exact(true)) {
51,004✔
377
                stats.set(Stat::IsStrictSorted, Precision::exact(true));
855✔
378
            }
50,149✔
379

380
            stats
51,004✔
381
        });
51,004✔
382

383
        let sliced = <V::OperationsVTable as OperationsVTable<V>>::slice(&self.0, start, stop)?;
60,387✔
384

385
        assert_eq!(
60,387✔
386
            sliced.len(),
60,387✔
387
            stop - start,
60,387✔
UNCOV
388
            "Slice length mismatch {}",
×
UNCOV
389
            self.encoding_id()
×
390
        );
391
        assert_eq!(
60,387✔
392
            sliced.dtype(),
60,387✔
393
            self.dtype(),
60,387✔
UNCOV
394
            "Slice dtype mismatch {}",
×
UNCOV
395
            self.encoding_id()
×
396
        );
397

398
        if let Some(derived_stats) = derived_stats {
60,387✔
399
            let mut stats = sliced.statistics().to_owned();
51,004✔
400
            stats.combine_sets(&derived_stats, self.dtype())?;
51,004✔
401
            for (stat, val) in stats.into_iter() {
96,217✔
402
                sliced.statistics().set(stat, val)
95,879✔
403
            }
404
        }
9,383✔
405

406
        Ok(sliced)
60,387✔
407
    }
70,485✔
408

409
    fn scalar_at(&self, index: usize) -> VortexResult<Scalar> {
3,642,195✔
410
        if index >= self.len() {
3,642,195✔
411
            vortex_bail!(OutOfBounds: index, 0, self.len());
8✔
412
        }
3,642,187✔
413
        if self.is_invalid(index)? {
3,642,187✔
414
            return Ok(Scalar::null(self.dtype().clone()));
2,807✔
415
        }
3,639,380✔
416
        let scalar = <V::OperationsVTable as OperationsVTable<V>>::scalar_at(&self.0, index)?;
3,639,380✔
417
        assert_eq!(self.dtype(), scalar.dtype(), "Scalar dtype mismatch");
3,639,380✔
418
        Ok(scalar)
3,639,380✔
419
    }
3,642,195✔
420

421
    fn is_valid(&self, index: usize) -> VortexResult<bool> {
6,102,786✔
422
        if index >= self.len() {
6,102,786✔
UNCOV
423
            vortex_bail!(OutOfBounds: index, 0, self.len());
×
424
        }
6,102,786✔
425
        <V::ValidityVTable as ValidityVTable<V>>::is_valid(&self.0, index)
6,102,786✔
426
    }
6,102,786✔
427

428
    fn is_invalid(&self, index: usize) -> VortexResult<bool> {
3,642,945✔
429
        self.is_valid(index).map(|valid| !valid)
3,642,945✔
430
    }
3,642,945✔
431

432
    fn all_valid(&self) -> VortexResult<bool> {
3,245,850✔
433
        <V::ValidityVTable as ValidityVTable<V>>::all_valid(&self.0)
3,245,850✔
434
    }
3,245,850✔
435

436
    fn all_invalid(&self) -> VortexResult<bool> {
166,433✔
437
        <V::ValidityVTable as ValidityVTable<V>>::all_invalid(&self.0)
166,433✔
438
    }
166,433✔
439

440
    fn valid_count(&self) -> VortexResult<usize> {
56,874✔
441
        if let Some(Precision::Exact(invalid_count)) =
4,541✔
442
            self.statistics().get_as::<usize>(Stat::NullCount)
56,874✔
443
        {
444
            return Ok(self.len() - invalid_count);
4,541✔
445
        }
52,333✔
446

447
        let count = <V::ValidityVTable as ValidityVTable<V>>::valid_count(&self.0)?;
52,333✔
448
        assert!(count <= self.len(), "Valid count exceeds array length");
52,333✔
449

450
        self.statistics()
52,333✔
451
            .set(Stat::NullCount, Precision::exact(self.len() - count));
52,333✔
452

453
        Ok(count)
52,333✔
454
    }
56,874✔
455

456
    fn invalid_count(&self) -> VortexResult<usize> {
13,100✔
457
        if let Some(Precision::Exact(invalid_count)) =
3,654✔
458
            self.statistics().get_as::<usize>(Stat::NullCount)
13,100✔
459
        {
460
            return Ok(invalid_count);
3,654✔
461
        }
9,446✔
462

463
        let count = <V::ValidityVTable as ValidityVTable<V>>::invalid_count(&self.0)?;
9,446✔
464
        assert!(count <= self.len(), "Invalid count exceeds array length");
9,446✔
465

466
        self.statistics()
9,446✔
467
            .set(Stat::NullCount, Precision::exact(count));
9,446✔
468

469
        Ok(count)
9,446✔
470
    }
13,100✔
471

472
    fn validity_mask(&self) -> VortexResult<Mask> {
251,252✔
473
        let mask = <V::ValidityVTable as ValidityVTable<V>>::validity_mask(&self.0)?;
251,252✔
474
        assert_eq!(mask.len(), self.len(), "Validity mask length mismatch");
251,252✔
475
        Ok(mask)
251,252✔
476
    }
251,252✔
477

478
    fn to_canonical(&self) -> VortexResult<Canonical> {
299,887✔
479
        let canonical = <V::CanonicalVTable as CanonicalVTable<V>>::canonicalize(&self.0)?;
299,887✔
480
        assert_eq!(
299,887✔
481
            self.len(),
299,887✔
482
            canonical.as_ref().len(),
299,887✔
UNCOV
483
            "Canonical length mismatch {}. Expected {} but encoded into {}.",
×
UNCOV
484
            self.encoding_id(),
×
UNCOV
485
            self.len(),
×
UNCOV
486
            canonical.as_ref().len()
×
487
        );
488
        assert_eq!(
299,887✔
489
            self.dtype(),
299,887✔
490
            canonical.as_ref().dtype(),
299,887✔
UNCOV
491
            "Canonical dtype mismatch {}. Expected {} but encoded into {}.",
×
UNCOV
492
            self.encoding_id(),
×
UNCOV
493
            self.dtype(),
×
UNCOV
494
            canonical.as_ref().dtype()
×
495
        );
496
        canonical.as_ref().statistics().inherit(self.statistics());
299,887✔
497
        Ok(canonical)
299,887✔
498
    }
299,887✔
499

500
    fn append_to_builder(&self, builder: &mut dyn ArrayBuilder) -> VortexResult<()> {
43,271✔
501
        if builder.dtype() != self.dtype() {
43,271✔
UNCOV
502
            vortex_bail!(
×
UNCOV
503
                "Builder dtype mismatch: expected {}, got {}",
×
UNCOV
504
                self.dtype(),
×
UNCOV
505
                builder.dtype(),
×
506
            );
507
        }
43,271✔
508
        let len = builder.len();
43,271✔
509

510
        <V::CanonicalVTable as CanonicalVTable<V>>::append_to_builder(&self.0, builder)?;
43,271✔
511
        assert_eq!(
43,271✔
512
            len + self.len(),
43,271✔
513
            builder.len(),
43,271✔
UNCOV
514
            "Builder length mismatch after writing array for encoding {}",
×
UNCOV
515
            self.encoding_id(),
×
516
        );
517
        Ok(())
43,271✔
518
    }
43,271✔
519

520
    fn statistics(&self) -> StatsSetRef<'_> {
1,810,269✔
521
        <V::ArrayVTable as ArrayVTable<V>>::stats(&self.0)
1,810,269✔
522
    }
1,810,269✔
523

524
    fn with_children(&self, children: &[ArrayRef]) -> VortexResult<ArrayRef> {
×
525
        struct ReplacementChildren<'a> {
526
            children: &'a [ArrayRef],
527
        }
528

529
        impl ArrayChildren for ReplacementChildren<'_> {
UNCOV
530
            fn get(&self, index: usize, dtype: &DType, len: usize) -> VortexResult<ArrayRef> {
×
531
                if index >= self.children.len() {
×
532
                    vortex_bail!(OutOfBounds: index, 0, self.children.len());
×
533
                }
×
534
                let child = &self.children[index];
×
UNCOV
535
                if child.len() != len {
×
UNCOV
536
                    vortex_bail!(
×
UNCOV
537
                        "Child length mismatch: expected {}, got {}",
×
538
                        len,
UNCOV
539
                        child.len()
×
540
                    );
UNCOV
541
                }
×
542
                if child.dtype() != dtype {
×
543
                    vortex_bail!(
×
544
                        "Child dtype mismatch: expected {}, got {}",
×
545
                        dtype,
UNCOV
546
                        child.dtype()
×
547
                    );
UNCOV
548
                }
×
UNCOV
549
                Ok(child.clone())
×
UNCOV
550
            }
×
551

UNCOV
552
            fn len(&self) -> usize {
×
UNCOV
553
                self.children.len()
×
554
            }
×
555
        }
556

UNCOV
557
        let metadata = self.metadata()?.ok_or_else(|| {
×
UNCOV
558
            vortex_err!("Cannot replace children for arrays that do not support serialization")
×
UNCOV
559
        })?;
×
560

561
        // Replace the children of the array by re-building the array from parts.
UNCOV
562
        self.encoding().build(
×
UNCOV
563
            self.dtype(),
×
564
            self.len(),
×
UNCOV
565
            &metadata,
×
UNCOV
566
            &self.buffers(),
×
UNCOV
567
            &ReplacementChildren { children },
×
UNCOV
568
        )
×
UNCOV
569
    }
×
570

571
    fn invoke(
37,640✔
572
        &self,
37,640✔
573
        compute_fn: &ComputeFn,
37,640✔
574
        args: &InvocationArgs,
37,640✔
575
    ) -> VortexResult<Option<Output>> {
37,640✔
576
        <V::ComputeVTable as ComputeVTable<V>>::invoke(&self.0, compute_fn, args)
37,640✔
577
    }
37,640✔
578
}
579

580
impl<V: VTable> ArrayVisitor for ArrayAdapter<V> {
581
    fn children(&self) -> Vec<ArrayRef> {
301,730✔
582
        struct ChildrenCollector {
583
            children: Vec<ArrayRef>,
584
        }
585

586
        impl ArrayChildVisitor for ChildrenCollector {
587
            fn visit_child(&mut self, _name: &str, array: &dyn Array) {
122,806✔
588
                self.children.push(array.to_array());
122,806✔
589
            }
122,806✔
590
        }
591

592
        let mut collector = ChildrenCollector {
301,730✔
593
            children: Vec::new(),
301,730✔
594
        };
301,730✔
595
        <V::VisitorVTable as VisitorVTable<V>>::visit_children(&self.0, &mut collector);
301,730✔
596
        collector.children
301,730✔
597
    }
301,730✔
598

599
    fn nchildren(&self) -> usize {
×
UNCOV
600
        <V::VisitorVTable as VisitorVTable<V>>::nchildren(&self.0)
×
UNCOV
601
    }
×
602

603
    fn children_names(&self) -> Vec<String> {
706✔
604
        struct ChildNameCollector {
605
            names: Vec<String>,
606
        }
607

608
        impl ArrayChildVisitor for ChildNameCollector {
609
            fn visit_child(&mut self, name: &str, _array: &dyn Array) {
482✔
610
                self.names.push(name.to_string());
482✔
611
            }
482✔
612
        }
613

614
        let mut collector = ChildNameCollector { names: Vec::new() };
706✔
615
        <V::VisitorVTable as VisitorVTable<V>>::visit_children(&self.0, &mut collector);
706✔
616
        collector.names
706✔
617
    }
706✔
618

UNCOV
619
    fn named_children(&self) -> Vec<(String, ArrayRef)> {
×
620
        struct NamedChildrenCollector {
621
            children: Vec<(String, ArrayRef)>,
622
        }
623

624
        impl ArrayChildVisitor for NamedChildrenCollector {
UNCOV
625
            fn visit_child(&mut self, name: &str, array: &dyn Array) {
×
UNCOV
626
                self.children.push((name.to_string(), array.to_array()));
×
UNCOV
627
            }
×
628
        }
629

UNCOV
630
        let mut collector = NamedChildrenCollector {
×
UNCOV
631
            children: Vec::new(),
×
UNCOV
632
        };
×
633

UNCOV
634
        <V::VisitorVTable as VisitorVTable<V>>::visit_children(&self.0, &mut collector);
×
UNCOV
635
        collector.children
×
UNCOV
636
    }
×
637

638
    fn buffers(&self) -> Vec<ByteBuffer> {
230,475✔
639
        struct BufferCollector {
640
            buffers: Vec<ByteBuffer>,
641
        }
642

643
        impl ArrayBufferVisitor for BufferCollector {
644
            fn visit_buffer(&mut self, buffer: &ByteBuffer) {
275,539✔
645
                self.buffers.push(buffer.clone());
275,539✔
646
            }
275,539✔
647
        }
648

649
        let mut collector = BufferCollector {
230,475✔
650
            buffers: Vec::new(),
230,475✔
651
        };
230,475✔
652
        <V::VisitorVTable as VisitorVTable<V>>::visit_buffers(&self.0, &mut collector);
230,475✔
653
        collector.buffers
230,475✔
654
    }
230,475✔
655

656
    fn nbuffers(&self) -> usize {
45,971✔
657
        <V::VisitorVTable as VisitorVTable<V>>::nbuffers(&self.0)
45,971✔
658
    }
45,971✔
659

660
    fn metadata(&self) -> VortexResult<Option<Vec<u8>>> {
50,370✔
661
        Ok(<V::SerdeVTable as SerdeVTable<V>>::metadata(&self.0)?.map(|m| m.serialize()))
50,370✔
662
    }
50,370✔
663

664
    fn metadata_fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
706✔
665
        match <V::SerdeVTable as SerdeVTable<V>>::metadata(&self.0) {
706✔
666
            Err(e) => write!(f, "<serde error: {e}>"),
×
667
            Ok(None) => write!(f, "<serde not supported>"),
×
668
            Ok(Some(metadata)) => Debug::fmt(&metadata, f),
706✔
669
        }
670
    }
706✔
671
}
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

© 2025 Coveralls, Inc