polars_arrow/scalar/
mod.rs

1//! contains the [`Scalar`] trait object representing individual items of [`Array`](crate::array::Array)s,
2//! as well as concrete implementations such as [`BooleanScalar`].
3use std::any::Any;
4
5use crate::array::*;
6use crate::datatypes::*;
7
8mod dictionary;
9pub use dictionary::*;
10mod equal;
11mod primitive;
12pub use primitive::*;
13mod utf8;
14pub use utf8::*;
15mod binary;
16pub use binary::*;
17mod boolean;
18pub use boolean::*;
19mod list;
20pub use list::*;
21mod map;
22pub use map::*;
23mod null;
24pub use null::*;
25mod struct_;
26pub use struct_::*;
27mod fixed_size_list;
28pub use fixed_size_list::*;
29mod fixed_size_binary;
30pub use binview::*;
31pub use fixed_size_binary::*;
32mod binview;
33mod union;
34
35pub use union::UnionScalar;
36
37use crate::{match_integer_type, with_match_primitive_type_full};
38
39/// Trait object declaring an optional value with a [`ArrowDataType`].
40/// This strait is often used in APIs that accept multiple scalar types.
41pub trait Scalar: std::fmt::Debug + Send + Sync + dyn_clone::DynClone + 'static {
42    /// convert itself to
43    fn as_any(&self) -> &dyn Any;
44
45    /// whether it is valid
46    fn is_valid(&self) -> bool;
47
48    /// the logical type.
49    fn dtype(&self) -> &ArrowDataType;
50}
51
52dyn_clone::clone_trait_object!(Scalar);
53
54macro_rules! dyn_new_utf8 {
55    ($array:expr, $index:expr, $type:ty) => {{
56        let array = $array.as_any().downcast_ref::<Utf8Array<$type>>().unwrap();
57        let value = if array.is_valid($index) {
58            Some(array.value($index))
59        } else {
60            None
61        };
62        Box::new(Utf8Scalar::<$type>::new(value))
63    }};
64}
65
66macro_rules! dyn_new_binview {
67    ($array:expr, $index:expr, $type:ty) => {{
68        let array = $array
69            .as_any()
70            .downcast_ref::<BinaryViewArrayGeneric<$type>>()
71            .unwrap();
72        let value = if array.is_valid($index) {
73            Some(array.value($index))
74        } else {
75            None
76        };
77        Box::new(BinaryViewScalar::<$type>::new(value))
78    }};
79}
80
81macro_rules! dyn_new_binary {
82    ($array:expr, $index:expr, $type:ty) => {{
83        let array = $array
84            .as_any()
85            .downcast_ref::<BinaryArray<$type>>()
86            .unwrap();
87        let value = if array.is_valid($index) {
88            Some(array.value($index))
89        } else {
90            None
91        };
92        Box::new(BinaryScalar::<$type>::new(value))
93    }};
94}
95
96macro_rules! dyn_new_list {
97    ($array:expr, $index:expr, $type:ty) => {{
98        let array = $array.as_any().downcast_ref::<ListArray<$type>>().unwrap();
99        let value = if array.is_valid($index) {
100            Some(array.value($index).into())
101        } else {
102            None
103        };
104        Box::new(ListScalar::<$type>::new(array.dtype().clone(), value))
105    }};
106}
107
108/// creates a new [`Scalar`] from an [`Array`].
109pub fn new_scalar(array: &dyn Array, index: usize) -> Box<dyn Scalar> {
110    use PhysicalType::*;
111    match array.dtype().to_physical_type() {
112        Null => Box::new(NullScalar::new()),
113        Boolean => {
114            let array = array.as_any().downcast_ref::<BooleanArray>().unwrap();
115            let value = if array.is_valid(index) {
116                Some(array.value(index))
117            } else {
118                None
119            };
120            Box::new(BooleanScalar::new(value))
121        },
122        Primitive(primitive) => with_match_primitive_type_full!(primitive, |$T| {
123            let array = array
124                .as_any()
125                .downcast_ref::<PrimitiveArray<$T>>()
126                .unwrap();
127            let value = if array.is_valid(index) {
128                Some(array.value(index))
129            } else {
130                None
131            };
132            Box::new(PrimitiveScalar::new(array.dtype().clone(), value))
133        }),
134        BinaryView => dyn_new_binview!(array, index, [u8]),
135        Utf8View => dyn_new_binview!(array, index, str),
136        Utf8 => dyn_new_utf8!(array, index, i32),
137        LargeUtf8 => dyn_new_utf8!(array, index, i64),
138        Binary => dyn_new_binary!(array, index, i32),
139        LargeBinary => dyn_new_binary!(array, index, i64),
140        List => dyn_new_list!(array, index, i32),
141        LargeList => dyn_new_list!(array, index, i64),
142        Struct => {
143            let array = array.as_any().downcast_ref::<StructArray>().unwrap();
144            if array.is_valid(index) {
145                let values = array
146                    .values()
147                    .iter()
148                    .map(|x| new_scalar(x.as_ref(), index))
149                    .collect();
150                Box::new(StructScalar::new(array.dtype().clone(), Some(values)))
151            } else {
152                Box::new(StructScalar::new(array.dtype().clone(), None))
153            }
154        },
155        FixedSizeBinary => {
156            let array = array
157                .as_any()
158                .downcast_ref::<FixedSizeBinaryArray>()
159                .unwrap();
160            let value = if array.is_valid(index) {
161                Some(array.value(index))
162            } else {
163                None
164            };
165            Box::new(FixedSizeBinaryScalar::new(array.dtype().clone(), value))
166        },
167        FixedSizeList => {
168            let array = array.as_any().downcast_ref::<FixedSizeListArray>().unwrap();
169            let value = if array.is_valid(index) {
170                Some(array.value(index))
171            } else {
172                None
173            };
174            Box::new(FixedSizeListScalar::new(array.dtype().clone(), value))
175        },
176        Union => {
177            let array = array.as_any().downcast_ref::<UnionArray>().unwrap();
178            Box::new(UnionScalar::new(
179                array.dtype().clone(),
180                array.types()[index],
181                array.value(index),
182            ))
183        },
184        Map => {
185            let array = array.as_any().downcast_ref::<MapArray>().unwrap();
186            let value = if array.is_valid(index) {
187                Some(array.value(index))
188            } else {
189                None
190            };
191            Box::new(MapScalar::new(array.dtype().clone(), value))
192        },
193        Dictionary(key_type) => match_integer_type!(key_type, |$T| {
194            let array = array
195                .as_any()
196                .downcast_ref::<DictionaryArray<$T>>()
197                .unwrap();
198            let value = if array.is_valid(index) {
199                Some(array.value(index).into())
200            } else {
201                None
202            };
203            Box::new(DictionaryScalar::<$T>::new(
204                array.dtype().clone(),
205                value,
206            ))
207        }),
208    }
209}