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

vortex-data / vortex / 16729505659

04 Aug 2025 05:07PM UTC coverage: 83.369% (-0.3%) from 83.639%
16729505659

push

github

web-flow
Revert "feat: implement Cast Kernel everywhere" (#4109)

Reverts vortex-data/vortex#4086

13 of 13 new or added lines in 1 file covered. (100.0%)

45 existing lines in 12 files now uncovered.

46613 of 55912 relevant lines covered (83.37%)

447773.58 hits per line

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

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

4
use std::fmt::{Debug, Display, Formatter};
5
use std::hash::Hash;
6
use std::ops::Index;
7
use std::sync::Arc;
8

9
use DType::*;
10
use itertools::Itertools;
11
use static_assertions::const_assert_eq;
12
use vortex_error::vortex_panic;
13

14
use crate::decimal::DecimalDType;
15
use crate::nullability::Nullability;
16
use crate::{ExtDType, FieldDType, PType, StructFields};
17

18
/// A name for a field in a struct
19
pub type FieldName = Arc<str>;
20

21
/// An ordered list of field names in a struct
22
#[derive(Clone, PartialEq, Eq, Debug, Default, Hash)]
23
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24
pub struct FieldNames(Arc<[FieldName]>);
25

26
impl FieldNames {
27
    /// Returns the number of elements.
28
    pub fn len(&self) -> usize {
1,009,766✔
29
        self.0.len()
1,009,766✔
30
    }
1,009,766✔
31

32
    /// Returns true if the number of elements is 0.
33
    pub fn is_empty(&self) -> bool {
×
34
        self.len() == 0
×
35
    }
×
36

37
    /// Returns a borrowed iterator over the field names.
38
    pub fn iter(&self) -> impl ExactSizeIterator<Item = &FieldName> {
116,298✔
39
        FieldNamesIter {
116,298✔
40
            inner: self,
116,298✔
41
            idx: 0,
116,298✔
42
        }
116,298✔
43
    }
116,298✔
44

45
    /// Returns a reference to a field name, or None if `index` is out of bounds.
46
    pub fn get(&self, index: usize) -> Option<&FieldName> {
546✔
47
        self.0.get(index)
546✔
48
    }
546✔
49
}
50

51
impl AsRef<[FieldName]> for FieldNames {
52
    fn as_ref(&self) -> &[FieldName] {
1,014✔
53
        &self.0
1,014✔
54
    }
1,014✔
55
}
56

57
impl Index<usize> for FieldNames {
58
    type Output = FieldName;
59

60
    fn index(&self, index: usize) -> &Self::Output {
21,497✔
61
        &self.0[index]
21,497✔
62
    }
21,497✔
63
}
64

65
/// Iterator of references to field names
66
pub struct FieldNamesIter<'a> {
67
    inner: &'a FieldNames,
68
    idx: usize,
69
}
70

71
impl<'a> Iterator for FieldNamesIter<'a> {
72
    type Item = &'a FieldName;
73

74
    fn next(&mut self) -> Option<Self::Item> {
379,291✔
75
        if self.idx >= self.inner.len() {
379,291✔
76
            return None;
31,267✔
77
        }
348,024✔
78

79
        let i = &self.inner.0[self.idx];
348,024✔
80
        self.idx += 1;
348,024✔
81
        Some(i)
348,024✔
82
    }
379,291✔
83

84
    fn size_hint(&self) -> (usize, Option<usize>) {
11,309✔
85
        let len = self.inner.len() - self.idx;
11,309✔
86
        (len, Some(len))
11,309✔
87
    }
11,309✔
88
}
89

90
impl ExactSizeIterator for FieldNamesIter<'_> {}
91

92
/// Owned iterator of field names.
93
pub struct FieldNamesIntoIter {
94
    inner: FieldNames,
95
    idx: usize,
96
}
97

98
impl Iterator for FieldNamesIntoIter {
99
    type Item = FieldName;
100

101
    fn next(&mut self) -> Option<Self::Item> {
3✔
102
        if self.idx >= self.inner.len() {
3✔
103
            return None;
1✔
104
        }
2✔
105

106
        let i = self.inner.0[self.idx].clone();
2✔
107
        self.idx += 1;
2✔
108
        Some(i)
2✔
109
    }
3✔
110

111
    fn size_hint(&self) -> (usize, Option<usize>) {
1✔
112
        let len = self.inner.len() - self.idx;
1✔
113
        (len, Some(len))
1✔
114
    }
1✔
115
}
116

117
impl ExactSizeIterator for FieldNamesIntoIter {}
118

119
impl IntoIterator for FieldNames {
120
    type Item = FieldName;
121

122
    type IntoIter = FieldNamesIntoIter;
123

124
    fn into_iter(self) -> Self::IntoIter {
2✔
125
        FieldNamesIntoIter {
2✔
126
            inner: self,
2✔
127
            idx: 0,
2✔
128
        }
2✔
129
    }
2✔
130
}
131

132
impl From<Vec<FieldName>> for FieldNames {
133
    fn from(value: Vec<FieldName>) -> Self {
36,063✔
134
        Self(value.into())
36,063✔
135
    }
36,063✔
136
}
137

138
impl From<&[&'static str]> for FieldNames {
139
    fn from(value: &[&'static str]) -> Self {
×
140
        Self(value.iter().cloned().map(Arc::from).collect())
×
141
    }
×
142
}
143

144
impl From<&[FieldName]> for FieldNames {
145
    fn from(value: &[FieldName]) -> Self {
117✔
146
        Self(Arc::from(value))
117✔
147
    }
117✔
148
}
149

150
impl<const N: usize> From<[&'static str; N]> for FieldNames {
151
    fn from(value: [&'static str; N]) -> Self {
204,453✔
152
        Self(value.into_iter().map(Arc::from).collect())
204,453✔
153
    }
204,453✔
154
}
155

156
impl<const N: usize> From<[FieldName; N]> for FieldNames {
157
    fn from(value: [FieldName; N]) -> Self {
13✔
158
        Self(value.into())
13✔
159
    }
13✔
160
}
161

162
impl<F: Into<FieldName>> FromIterator<F> for FieldNames {
163
    fn from_iter<T: IntoIterator<Item = F>>(iter: T) -> Self {
7,680✔
164
        Self(iter.into_iter().map(|v| v.into()).collect())
12,852✔
165
    }
7,680✔
166
}
167

168
/// The logical types of elements in Vortex arrays.
169
///
170
/// Vortex arrays preserve a single logical type, while the encodings allow for multiple
171
/// physical ways to encode that type.
172
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
173
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
174
pub enum DType {
175
    /// The logical null type (only has a single value, `null`)
176
    Null,
177
    /// The logical boolean type (`true` or `false` if non-nullable; `true`, `false`, or `null` if nullable)
178
    Bool(Nullability),
179
    /// Primitive, fixed-width numeric types (e.g., `u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64`, `f32`, `f64`)
180
    Primitive(PType, Nullability),
181
    /// Real numbers with fixed exact precision and scale.
182
    Decimal(DecimalDType, Nullability),
183
    /// UTF-8 strings
184
    Utf8(Nullability),
185
    /// Binary data
186
    Binary(Nullability),
187
    /// A struct is composed of an ordered list of fields, each with a corresponding name and DType
188
    Struct(StructFields, Nullability),
189
    /// A variable-length list type, parameterized by a single element DType
190
    List(Arc<DType>, Nullability),
191
    /// User-defined extension types
192
    Extension(Arc<ExtDType>),
193
}
194

195
#[cfg(not(target_arch = "wasm32"))]
196
const_assert_eq!(size_of::<DType>(), 16);
197

198
#[cfg(target_arch = "wasm32")]
199
const_assert_eq!(size_of::<DType>(), 8);
200

201
impl DType {
202
    /// The default DType for bytes
203
    pub const BYTES: Self = Primitive(PType::U8, Nullability::NonNullable);
204

205
    /// Get the nullability of the DType
206
    pub fn nullability(&self) -> Nullability {
55,518,594✔
207
        self.is_nullable().into()
55,518,594✔
208
    }
55,518,594✔
209

210
    /// Check if the DType is nullable
211
    pub fn is_nullable(&self) -> bool {
66,384,612✔
212
        use crate::nullability::Nullability::*;
213

214
        match self {
66,384,612✔
215
            Null => true,
473,304✔
216
            Extension(ext_dtype) => ext_dtype.storage_dtype().is_nullable(),
129,598✔
217
            Bool(n)
11,929,525✔
218
            | Primitive(_, n)
51,769,577✔
219
            | Decimal(_, n)
399,186✔
220
            | Utf8(n)
1,052,237✔
221
            | Binary(n)
501,787✔
222
            | Struct(_, n)
31,828✔
223
            | List(_, n) => matches!(n, Nullable),
65,781,710✔
224
        }
225
    }
66,384,612✔
226

227
    /// Get a new DType with `Nullability::NonNullable` (but otherwise the same as `self`)
228
    pub fn as_nonnullable(&self) -> Self {
197✔
229
        self.with_nullability(Nullability::NonNullable)
197✔
230
    }
197✔
231

232
    /// Get a new DType with `Nullability::Nullable` (but otherwise the same as `self`)
233
    pub fn as_nullable(&self) -> Self {
3,611,308✔
234
        self.with_nullability(Nullability::Nullable)
3,611,308✔
235
    }
3,611,308✔
236

237
    /// Get a new DType with the given nullability (but otherwise the same as `self`)
238
    pub fn with_nullability(&self, nullability: Nullability) -> Self {
4,153,722✔
239
        match self {
4,153,722✔
240
            Null => Null,
47,853✔
241
            Bool(_) => Bool(nullability),
1,379,952✔
242
            Primitive(p, _) => Primitive(*p, nullability),
2,310,852✔
243
            Decimal(d, _) => Decimal(*d, nullability),
152,979✔
244
            Utf8(_) => Utf8(nullability),
151,626✔
245
            Binary(_) => Binary(nullability),
10,023✔
246
            Struct(st, _) => Struct(st.clone(), nullability),
13,221✔
247
            List(c, _) => List(c.clone(), nullability),
11,583✔
248
            Extension(ext) => Extension(Arc::new(ext.with_nullability(nullability))),
75,633✔
249
        }
250
    }
4,153,722✔
251

252
    /// Union the nullability of this dtype with the other nullability, returning a new dtype.
253
    pub fn union_nullability(&self, other: Nullability) -> Self {
408,339✔
254
        let nullability = self.nullability() | other;
408,339✔
255
        self.with_nullability(nullability)
408,339✔
256
    }
408,339✔
257

258
    /// Check if `self` and `other` are equal, ignoring nullability
259
    pub fn eq_ignore_nullability(&self, other: &Self) -> bool {
44,720,995✔
260
        match (self, other) {
44,720,995✔
261
            (Null, Null) => true,
235,014✔
262
            (Bool(_), Bool(_)) => true,
2,873,465✔
263
            (Primitive(lhs_ptype, _), Primitive(rhs_ptype, _)) => lhs_ptype == rhs_ptype,
38,185,814✔
264
            (Decimal(lhs, _), Decimal(rhs, _)) => lhs == rhs,
1,518,346✔
265
            (Utf8(_), Utf8(_)) => true,
1,315,559✔
266
            (Binary(_), Binary(_)) => true,
15,952✔
267
            (List(lhs_dtype, _), List(rhs_dtype, _)) => lhs_dtype.eq_ignore_nullability(rhs_dtype),
98,720✔
268
            (Struct(lhs_dtype, _), Struct(rhs_dtype, _)) => {
104,052✔
269
                (lhs_dtype.names() == rhs_dtype.names())
104,052✔
270
                    && (lhs_dtype
104,052✔
271
                        .fields()
104,052✔
272
                        .zip_eq(rhs_dtype.fields())
104,052✔
273
                        .all(|(l, r)| l.eq_ignore_nullability(&r)))
215,670✔
274
            }
275
            (Extension(lhs_extdtype), Extension(rhs_extdtype)) => {
373,718✔
276
                lhs_extdtype.as_ref().eq_ignore_nullability(rhs_extdtype)
373,718✔
277
            }
278
            _ => false,
355✔
279
        }
280
    }
44,720,995✔
281

282
    /// Check if `self` is a `StructDType`
283
    pub fn is_struct(&self) -> bool {
55,948✔
284
        matches!(self, Struct(_, _))
55,948✔
285
    }
55,948✔
286

287
    /// Check if `self` is a `ListDType`
288
    pub fn is_list(&self) -> bool {
×
289
        matches!(self, List(_, _))
×
290
    }
×
291

292
    /// Check if `self` is a primitive tpye
293
    pub fn is_primitive(&self) -> bool {
1,326✔
294
        matches!(self, Primitive(_, _))
1,326✔
295
    }
1,326✔
296

297
    /// Returns this DType's `PType` if it is a primitive type, otherwise panics.
298
    pub fn as_ptype(&self) -> PType {
227,296,350✔
299
        match self {
227,296,350✔
300
            Primitive(ptype, _) => *ptype,
227,296,350✔
301
            _ => vortex_panic!("DType is not a primitive type"),
×
302
        }
303
    }
227,296,350✔
304

305
    /// Check if `self` is an unsigned integer
306
    pub fn is_unsigned_int(&self) -> bool {
102,065✔
307
        if let Primitive(ptype, _) = self {
102,065✔
308
            return ptype.is_unsigned_int();
102,065✔
309
        }
×
310
        false
×
311
    }
102,065✔
312

313
    /// Check if `self` is a signed integer
314
    pub fn is_signed_int(&self) -> bool {
11,770✔
315
        if let Primitive(ptype, _) = self {
11,770✔
316
            return ptype.is_signed_int();
11,770✔
317
        }
×
318
        false
×
319
    }
11,770✔
320

321
    /// Check if `self` is an integer (signed or unsigned)
322
    pub fn is_int(&self) -> bool {
1,000,828✔
323
        if let Primitive(ptype, _) = self {
1,000,828✔
324
            return ptype.is_int();
1,000,828✔
325
        }
×
326
        false
×
327
    }
1,000,828✔
328

329
    /// Check if `self` is a floating point number
330
    pub fn is_float(&self) -> bool {
9,906✔
331
        if let Primitive(ptype, _) = self {
9,906✔
332
            return ptype.is_float();
9,906✔
333
        }
×
334
        false
×
335
    }
9,906✔
336

337
    /// Check if `self` is a boolean
338
    pub fn is_boolean(&self) -> bool {
11,922✔
339
        matches!(self, Bool(_))
11,922✔
340
    }
11,922✔
341

342
    /// Check if `self` is a binary
343
    pub fn is_binary(&self) -> bool {
585✔
344
        matches!(self, Binary(_))
585✔
345
    }
585✔
346

347
    /// Check if `self` is a utf8
348
    pub fn is_utf8(&self) -> bool {
5,343✔
349
        matches!(self, Utf8(_))
5,343✔
350
    }
5,343✔
351

352
    /// Check if `self` is an extension type
353
    pub fn is_extension(&self) -> bool {
×
354
        matches!(self, Extension(_))
×
355
    }
×
356

357
    /// Check if `self` is a decimal type
358
    pub fn is_decimal(&self) -> bool {
×
359
        matches!(self, Decimal(..))
×
360
    }
×
361

362
    /// Check returns the inner decimal type if the dtype is a decimal
363
    pub fn as_decimal(&self) -> Option<&DecimalDType> {
12,709✔
364
        match self {
12,709✔
365
            Decimal(decimal, _) => Some(decimal),
12,709✔
366
            _ => None,
×
367
        }
368
    }
12,709✔
369

370
    /// Get the `StructDType` if `self` is a `StructDType`, otherwise `None`
371
    pub fn as_struct(&self) -> Option<&StructFields> {
550,278✔
372
        match self {
550,278✔
373
            Struct(s, _) => Some(s),
549,614✔
374
            _ => None,
664✔
375
        }
376
    }
550,278✔
377

378
    /// Get the inner dtype if `self` is a `ListDType`, otherwise `None`
379
    pub fn as_list_element(&self) -> Option<&Arc<DType>> {
624✔
380
        match self {
624✔
381
            List(s, _) => Some(s),
585✔
382
            _ => None,
39✔
383
        }
384
    }
624✔
385

386
    /// Convenience method for creating a struct dtype
387
    pub fn struct_<I: IntoIterator<Item = (impl Into<FieldName>, impl Into<FieldDType>)>>(
17✔
388
        iter: I,
17✔
389
        nullability: Nullability,
17✔
390
    ) -> Self {
17✔
391
        Struct(StructFields::from_iter(iter), nullability)
17✔
392
    }
17✔
393

394
    /// Convenience method for creating a list dtype
395
    pub fn list(dtype: impl Into<DType>, nullability: Nullability) -> Self {
2✔
396
        List(Arc::new(dtype.into()), nullability)
2✔
397
    }
2✔
398
}
399

400
impl Display for DType {
401
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2,847✔
402
        match self {
2,847✔
403
            Null => write!(f, "null"),
×
404
            Bool(n) => write!(f, "bool{n}"),
117✔
405
            Primitive(pt, n) => write!(f, "{pt}{n}"),
2,184✔
406
            Decimal(dt, n) => write!(f, "{dt}{n}"),
39✔
407
            Utf8(n) => write!(f, "utf8{n}"),
195✔
UNCOV
408
            Binary(n) => write!(f, "binary{n}"),
×
409
            Struct(sdt, n) => write!(
117✔
410
                f,
117✔
411
                "{{{}}}{}",
117✔
412
                sdt.names()
117✔
413
                    .iter()
117✔
414
                    .zip(sdt.fields())
117✔
415
                    .map(|(n, dt)| format!("{n}={dt}"))
273✔
416
                    .join(", "),
117✔
417
                n
418
            ),
419
            List(edt, n) => write!(f, "list({edt}){n}"),
39✔
420
            Extension(ext) => write!(
156✔
421
                f,
156✔
422
                "ext({}, {}{}){}",
156✔
423
                ext.id(),
156✔
424
                ext.storage_dtype()
156✔
425
                    .with_nullability(Nullability::NonNullable),
156✔
426
                ext.metadata()
156✔
427
                    .map(|m| format!(", {m:?}"))
156✔
428
                    .unwrap_or_else(|| "".to_string()),
156✔
429
                ext.storage_dtype().nullability(),
156✔
430
            ),
431
        }
432
    }
2,847✔
433
}
434

435
#[cfg(test)]
436
mod tests {
437
    use super::*;
438

439
    #[test]
440
    fn test_field_names_iter() {
1✔
441
        let names = ["a", "b"];
1✔
442
        let field_names = FieldNames::from(names);
1✔
443
        assert_eq!(field_names.iter().len(), names.len());
1✔
444
        let mut iter = field_names.iter();
1✔
445
        assert_eq!(iter.next(), Some(&"a".into()));
1✔
446
        assert_eq!(iter.next(), Some(&"b".into()));
1✔
447
        assert_eq!(iter.next(), None);
1✔
448
    }
1✔
449

450
    #[test]
451
    fn test_field_names_owned_iter() {
1✔
452
        let names = ["a", "b"];
1✔
453
        let field_names = FieldNames::from(names);
1✔
454
        assert_eq!(field_names.clone().into_iter().len(), names.len());
1✔
455
        let mut iter = field_names.into_iter();
1✔
456
        assert_eq!(iter.next(), Some("a".into()));
1✔
457
        assert_eq!(iter.next(), Some("b".into()));
1✔
458
        assert_eq!(iter.next(), None);
1✔
459
    }
1✔
460
}
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