vortex_array/scalar/
validate.rs1use vortex_error::VortexResult;
5use vortex_error::vortex_bail;
6use vortex_error::vortex_ensure;
7use vortex_error::vortex_ensure_eq;
8
9use crate::dtype::DType;
10use crate::dtype::PType;
11use crate::scalar::PValue;
12use crate::scalar::Scalar;
13use crate::scalar::ScalarValue;
14
15impl Scalar {
16 pub fn validate(dtype: &DType, value: Option<&ScalarValue>) -> VortexResult<()> {
18 let Some(value) = value else {
19 vortex_ensure!(
20 dtype.is_nullable(),
21 "non-nullable dtype {dtype} cannot hold a null value",
22 );
23 return Ok(());
24 };
25
26 match dtype {
28 DType::Null => {
29 vortex_bail!("null dtype cannot hold a non-null value {value}");
30 }
31 DType::Bool(_) => {
32 vortex_ensure!(
33 matches!(value, ScalarValue::Bool(_)),
34 "bool dtype expected Bool value, got {value}",
35 );
36 }
37 DType::Primitive(ptype, _) => {
38 let ScalarValue::Primitive(pvalue) = value else {
39 vortex_bail!("primitive dtype {ptype} expected Primitive value, got {value}",);
40 };
41
42 let f16_backcompat_still_works =
47 matches!(ptype, &PType::F16) && matches!(pvalue, PValue::U64(_));
48
49 vortex_ensure!(
50 f16_backcompat_still_works || pvalue.ptype() == *ptype,
51 "primitive dtype {ptype} is not compatible with value {pvalue}",
52 );
53 }
54 DType::Decimal(dec_dtype, _) => {
55 let ScalarValue::Decimal(dvalue) = value else {
56 vortex_bail!("decimal dtype expected Decimal value, got {value}");
57 };
58
59 vortex_ensure!(
60 dvalue.fits_in_precision(*dec_dtype),
61 "decimal value {dvalue} does not fit in precision of {dec_dtype}",
62 );
63 }
64 DType::Utf8(_) => {
65 vortex_ensure!(
66 matches!(value, ScalarValue::Utf8(_)),
67 "utf8 dtype expected Utf8 value, got {value}",
68 );
69 }
70 DType::Binary(_) => {
71 vortex_ensure!(
72 matches!(value, ScalarValue::Binary(_)),
73 "binary dtype expected Binary value, got {value}",
74 );
75 }
76 DType::List(elem_dtype, _) => {
77 let ScalarValue::List(elements) = value else {
78 vortex_bail!("list dtype expected List value, got {value}");
79 };
80
81 for (i, element) in elements.iter().enumerate() {
82 Self::validate(elem_dtype.as_ref(), element.as_ref())
83 .map_err(|e| vortex_error::vortex_err!("list element at index {i}: {e}"))?;
84 }
85 }
86 DType::FixedSizeList(elem_dtype, size, _) => {
87 let ScalarValue::List(elements) = value else {
88 vortex_bail!("fixed-size list dtype expected List value, got {value}",);
89 };
90
91 let len = elements.len();
92 vortex_ensure_eq!(
93 len,
94 *size as usize,
95 "fixed-size list dtype expected {size} elements, got {len}",
96 );
97
98 for (i, element) in elements.iter().enumerate() {
99 Self::validate(elem_dtype.as_ref(), element.as_ref()).map_err(|e| {
100 vortex_error::vortex_err!("fixed-size list element at index {i}: {e}",)
101 })?;
102 }
103 }
104 DType::Struct(fields, _) => {
105 let ScalarValue::List(values) = value else {
106 vortex_bail!("struct dtype expected List value, got {value}");
107 };
108
109 let nfields = fields.nfields();
110 let nvalues = values.len();
111 vortex_ensure_eq!(
112 nvalues,
113 nfields,
114 "struct dtype expected {nfields} fields, got {nvalues}",
115 );
116
117 for (field, field_value) in fields.fields().zip(values.iter()) {
118 Self::validate(&field, field_value.as_ref())?;
119 }
120 }
121 DType::Extension(ext_dtype) => ext_dtype.validate_storage_value(value)?,
122 }
123
124 Ok(())
125 }
126}