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