vortex_array/scalar/downcast.rs
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4//! Scalar downcasting methods to typed views.
5
6use vortex_buffer::BufferString;
7use vortex_buffer::ByteBuffer;
8use vortex_error::VortexExpect;
9use vortex_error::vortex_panic;
10
11use crate::scalar::BinaryScalar;
12use crate::scalar::BoolScalar;
13use crate::scalar::DecimalScalar;
14use crate::scalar::DecimalValue;
15use crate::scalar::ExtScalar;
16use crate::scalar::ListScalar;
17use crate::scalar::MapScalar;
18use crate::scalar::PValue;
19use crate::scalar::PrimitiveScalar;
20use crate::scalar::Scalar;
21use crate::scalar::ScalarValue;
22use crate::scalar::StructScalar;
23use crate::scalar::UnionScalar;
24use crate::scalar::UnionValue;
25use crate::scalar::Utf8Scalar;
26use crate::scalar::VariantScalar;
27
28impl Scalar {
29 /// Returns a view of the scalar as a boolean scalar.
30 ///
31 /// # Panics
32 ///
33 /// Panics if the scalar does not have a [`Bool`](crate::dtype::DType::Bool) type.
34 pub fn as_bool(&self) -> BoolScalar<'_> {
35 self.as_bool_opt()
36 .vortex_expect("Failed to convert scalar to bool")
37 }
38
39 /// Returns a view of the scalar as a boolean scalar if it has a boolean type.
40 pub fn as_bool_opt(&self) -> Option<BoolScalar<'_>> {
41 BoolScalar::try_new(self.dtype(), self.value()).ok()
42 }
43
44 /// Returns a view of the scalar as a primitive scalar.
45 ///
46 /// # Panics
47 ///
48 /// Panics if the scalar does not have a [`Primitive`](crate::dtype::DType::Primitive) type.
49 pub fn as_primitive(&self) -> PrimitiveScalar<'_> {
50 self.as_primitive_opt()
51 .vortex_expect("Failed to convert scalar to primitive")
52 }
53
54 /// Returns a view of the scalar as a primitive scalar if it has a primitive type.
55 pub fn as_primitive_opt(&self) -> Option<PrimitiveScalar<'_>> {
56 PrimitiveScalar::try_new(self.dtype(), self.value()).ok()
57 }
58
59 /// Returns a view of the scalar as a decimal scalar.
60 ///
61 /// # Panics
62 ///
63 /// Panics if the scalar does not have a [`Decimal`](crate::dtype::DType::Decimal) type.
64 pub fn as_decimal(&self) -> DecimalScalar<'_> {
65 self.as_decimal_opt()
66 .vortex_expect("Failed to convert scalar to decimal")
67 }
68
69 /// Returns a view of the scalar as a decimal scalar if it has a decimal type.
70 pub fn as_decimal_opt(&self) -> Option<DecimalScalar<'_>> {
71 DecimalScalar::try_new(self.dtype(), self.value()).ok()
72 }
73
74 /// Returns a view of the scalar as a UTF-8 string scalar.
75 ///
76 /// # Panics
77 ///
78 /// Panics if the scalar does not have a [`Utf8`](crate::dtype::DType::Utf8) type.
79 pub fn as_utf8(&self) -> Utf8Scalar<'_> {
80 self.as_utf8_opt()
81 .vortex_expect("Failed to convert scalar to utf8")
82 }
83
84 /// Returns a view of the scalar as a UTF-8 string scalar if it has a UTF-8 type.
85 pub fn as_utf8_opt(&self) -> Option<Utf8Scalar<'_>> {
86 Utf8Scalar::try_new(self.dtype(), self.value()).ok()
87 }
88
89 /// Returns a view of the scalar as a binary scalar.
90 ///
91 /// # Panics
92 ///
93 /// Panics if the scalar does not have a [`Binary`](crate::dtype::DType::Binary) type.
94 pub fn as_binary(&self) -> BinaryScalar<'_> {
95 self.as_binary_opt()
96 .vortex_expect("Failed to convert scalar to binary")
97 }
98
99 /// Returns a view of the scalar as a binary scalar if it has a binary type.
100 pub fn as_binary_opt(&self) -> Option<BinaryScalar<'_>> {
101 BinaryScalar::try_new(self.dtype(), self.value()).ok()
102 }
103
104 /// Returns a view of the scalar as a struct scalar.
105 ///
106 /// # Panics
107 ///
108 /// Panics if the scalar does not have a [`Struct`](crate::dtype::DType::Struct) type.
109 pub fn as_struct(&self) -> StructScalar<'_> {
110 self.as_struct_opt()
111 .vortex_expect("Failed to convert scalar to struct")
112 }
113
114 /// Returns a view of the scalar as a struct scalar if it has a struct type.
115 pub fn as_struct_opt(&self) -> Option<StructScalar<'_>> {
116 StructScalar::try_new(self.dtype(), self.value()).ok()
117 }
118
119 /// Returns a view of the scalar as a list scalar.
120 ///
121 /// Note that we use [`ListScalar`] to represent **both** [`List`](crate::dtype::DType::List)
122 /// and [`FixedSizeList`](crate::dtype::DType::FixedSizeList).
123 ///
124 /// # Panics
125 ///
126 /// Panics if the scalar does not have a [`List`](crate::dtype::DType::List) or
127 /// [`FixedSizeList`](crate::dtype::DType::FixedSizeList) type.
128 pub fn as_list(&self) -> ListScalar<'_> {
129 self.as_list_opt()
130 .vortex_expect("Failed to convert scalar to list")
131 }
132
133 /// Returns a view of the scalar as a list scalar if it has a list type.
134 ///
135 /// Note that we use [`ListScalar`] to represent **both** [`List`](crate::dtype::DType::List)
136 /// and [`FixedSizeList`](crate::dtype::DType::FixedSizeList).
137 pub fn as_list_opt(&self) -> Option<ListScalar<'_>> {
138 ListScalar::try_new(self.dtype(), self.value()).ok()
139 }
140
141 /// Returns a view of the scalar as a map scalar.
142 ///
143 /// # Panics
144 ///
145 /// Panics if the scalar does not have a [`Map`](crate::dtype::DType::Map) type.
146 pub fn as_map(&self) -> MapScalar<'_> {
147 self.as_map_opt()
148 .vortex_expect("Failed to convert scalar to map")
149 }
150
151 /// Returns a view of the scalar as a map scalar if it has a map type.
152 pub fn as_map_opt(&self) -> Option<MapScalar<'_>> {
153 MapScalar::try_new(self.dtype(), self.value()).ok()
154 }
155
156 /// Returns a view of the scalar as an extension scalar.
157 ///
158 /// # Panics
159 ///
160 /// Panics if the scalar does not have a [`Extension`](crate::dtype::DType::Extension) type.
161 pub fn as_extension(&self) -> ExtScalar<'_> {
162 self.as_extension_opt()
163 .vortex_expect("Failed to convert scalar to extension")
164 }
165
166 /// Returns a view of the scalar as an extension scalar if it has an extension type.
167 pub fn as_extension_opt(&self) -> Option<ExtScalar<'_>> {
168 if !self.dtype().is_extension() {
169 return None;
170 }
171
172 // SAFETY: Because we are a valid Scalar, we have already validated that the value is valid
173 // for this extension type.
174 Some(ExtScalar::new_unchecked(self.dtype(), self.value()))
175 }
176
177 /// Returns a view of the scalar as a union scalar.
178 ///
179 /// # Panics
180 ///
181 /// Panics if the scalar does not have a [`Union`](crate::dtype::DType::Union) type.
182 pub fn as_union(&self) -> UnionScalar<'_> {
183 self.as_union_opt()
184 .vortex_expect("Failed to convert scalar to union")
185 }
186
187 /// Returns a view of the scalar as a union scalar if it has a union dtype.
188 ///
189 /// [`None`] means the scalar's dtype is not [`DType::Union`](crate::dtype::DType); it does not
190 /// describe the scalar's nullness.
191 ///
192 /// An outer null union still returns `Some(UnionScalar)` and can be inspected with
193 /// [`UnionScalar::is_null`](crate::scalar::UnionScalar::is_null).
194 pub fn as_union_opt(&self) -> Option<UnionScalar<'_>> {
195 if !self.dtype().is_union() {
196 return None;
197 }
198
199 // Scalar construction has already validated the value against this union dtype.
200 Some(UnionScalar::new_unchecked(self.dtype(), self.value()))
201 }
202
203 /// Returns a view of the scalar as a variant scalar.
204 ///
205 /// # Panics
206 ///
207 /// Panics if the scalar does not have a [`Variant`](crate::dtype::DType::Variant) type.
208 pub fn as_variant(&self) -> VariantScalar<'_> {
209 self.as_variant_opt()
210 .vortex_expect("Failed to convert scalar to variant")
211 }
212
213 /// Returns a view of the scalar as a variant scalar if it has a variant type.
214 pub fn as_variant_opt(&self) -> Option<VariantScalar<'_>> {
215 VariantScalar::try_new(self.dtype(), self.value()).ok()
216 }
217}
218
219impl ScalarValue {
220 /// Returns the boolean value, panicking if the value is not a [`Bool`](ScalarValue::Bool).
221 pub fn as_bool(&self) -> bool {
222 match self {
223 ScalarValue::Bool(b) => *b,
224 _ => vortex_panic!("ScalarValue is not a Bool"),
225 }
226 }
227
228 /// Returns the primitive value, panicking if the value is not a
229 /// [`Primitive`](ScalarValue::Primitive).
230 pub fn as_primitive(&self) -> &PValue {
231 match self {
232 ScalarValue::Primitive(p) => p,
233 _ => vortex_panic!("ScalarValue is not a Primitive"),
234 }
235 }
236
237 /// Returns the decimal value, panicking if the value is not a
238 /// [`Decimal`](ScalarValue::Decimal).
239 pub fn as_decimal(&self) -> &DecimalValue {
240 match self {
241 ScalarValue::Decimal(d) => d,
242 _ => vortex_panic!("ScalarValue is not a Decimal"),
243 }
244 }
245
246 /// Returns the UTF-8 string value, panicking if the value is not a [`Utf8`](ScalarValue::Utf8).
247 pub fn as_utf8(&self) -> &BufferString {
248 match self {
249 ScalarValue::Utf8(s) => s,
250 _ => vortex_panic!("ScalarValue is not a Utf8"),
251 }
252 }
253
254 /// Returns the binary value, panicking if the value is not a [`Binary`](ScalarValue::Binary).
255 pub fn as_binary(&self) -> &ByteBuffer {
256 match self {
257 ScalarValue::Binary(b) => b,
258 _ => vortex_panic!("ScalarValue is not a Binary"),
259 }
260 }
261
262 /// Returns the tuple elements, panicking if the value is not a [`Tuple`](ScalarValue::Tuple).
263 pub fn as_list(&self) -> &[Option<ScalarValue>] {
264 match self {
265 ScalarValue::Tuple(elements) => elements,
266 _ => vortex_panic!("ScalarValue is not a Tuple"),
267 }
268 }
269
270 /// Returns the boolean value, panicking if the value is not a [`Bool`](ScalarValue::Bool).
271 pub fn into_bool(self) -> bool {
272 match self {
273 ScalarValue::Bool(b) => b,
274 _ => vortex_panic!("ScalarValue is not a Bool"),
275 }
276 }
277
278 /// Returns the primitive value, panicking if the value is not a
279 /// [`Primitive`](ScalarValue::Primitive).
280 pub fn into_primitive(self) -> PValue {
281 match self {
282 ScalarValue::Primitive(p) => p,
283 _ => vortex_panic!("ScalarValue is not a Primitive"),
284 }
285 }
286
287 /// Returns the decimal value, panicking if the value is not a
288 /// [`Decimal`](ScalarValue::Decimal).
289 pub fn into_decimal(self) -> DecimalValue {
290 match self {
291 ScalarValue::Decimal(d) => d,
292 _ => vortex_panic!("ScalarValue is not a Decimal"),
293 }
294 }
295
296 /// Returns the UTF-8 string value, panicking if the value is not a [`Utf8`](ScalarValue::Utf8).
297 pub fn into_utf8(self) -> BufferString {
298 match self {
299 ScalarValue::Utf8(s) => s,
300 _ => vortex_panic!("ScalarValue is not a Utf8"),
301 }
302 }
303
304 /// Returns the binary value, panicking if the value is not a [`Binary`](ScalarValue::Binary).
305 pub fn into_binary(self) -> ByteBuffer {
306 match self {
307 ScalarValue::Binary(b) => b,
308 _ => vortex_panic!("ScalarValue is not a Binary"),
309 }
310 }
311
312 /// Returns the tuple elements, panicking if the value is not a [`Tuple`](ScalarValue::Tuple).
313 pub fn into_list(self) -> Vec<Option<ScalarValue>> {
314 match self {
315 ScalarValue::Tuple(elements) => elements,
316 _ => vortex_panic!("ScalarValue is not a Tuple"),
317 }
318 }
319
320 /// Returns the union value, panicking if the value is not a [`Union`](ScalarValue::Union).
321 pub fn as_union(&self) -> &UnionValue {
322 match self {
323 ScalarValue::Union(value) => value,
324 _ => vortex_panic!("ScalarValue is not a Union"),
325 }
326 }
327
328 /// Returns the union value, panicking if the value is not a [`Union`](ScalarValue::Union).
329 pub fn into_union(self) -> UnionValue {
330 match self {
331 ScalarValue::Union(value) => value,
332 _ => vortex_panic!("ScalarValue is not a Union"),
333 }
334 }
335
336 /// Returns the row-specific scalar wrapped by a variant, panicking if the value is not a
337 /// variant.
338 pub fn as_variant(&self) -> &Scalar {
339 match self {
340 ScalarValue::Variant(value) => value,
341 _ => vortex_panic!("ScalarValue is not a Variant"),
342 }
343 }
344
345 /// Returns the row-specific scalar wrapped by a variant, panicking if the value is not a
346 /// variant.
347 pub fn into_variant(self) -> Scalar {
348 match self {
349 ScalarValue::Variant(value) => *value,
350 _ => vortex_panic!("ScalarValue is not a Variant"),
351 }
352 }
353}