polars_core/chunked_array/ops/
any_value.rs1#![allow(unsafe_op_in_unsafe_fn)]
2#[cfg(feature = "dtype-categorical")]
3use polars_utils::sync::SyncPtr;
4
5#[cfg(feature = "object")]
6use crate::chunked_array::object::extension::polars_extension::PolarsExtension;
7use crate::prelude::*;
8use crate::series::implementations::null::NullChunked;
9use crate::utils::index_to_chunked_index;
10
11#[inline]
12#[allow(unused_variables)]
13pub(crate) unsafe fn arr_to_any_value<'a>(
14 arr: &'a dyn Array,
15 idx: usize,
16 dtype: &'a DataType,
17) -> AnyValue<'a> {
18 debug_assert!(idx < arr.len());
19 if arr.is_null(idx) {
20 return AnyValue::Null;
21 }
22
23 macro_rules! downcast_and_pack {
24 ($casttype:ident, $variant:ident) => {{
25 let arr = &*(arr as *const dyn Array as *const $casttype);
26 let v = arr.value_unchecked(idx);
27 AnyValue::$variant(v)
28 }};
29 }
30 macro_rules! downcast {
31 ($casttype:ident) => {{
32 let arr = &*(arr as *const dyn Array as *const $casttype);
33 arr.value_unchecked(idx)
34 }};
35 }
36 match dtype {
37 DataType::String => downcast_and_pack!(Utf8ViewArray, String),
38 DataType::Binary => downcast_and_pack!(BinaryViewArray, Binary),
39 DataType::Boolean => downcast_and_pack!(BooleanArray, Boolean),
40 DataType::UInt8 => downcast_and_pack!(UInt8Array, UInt8),
41 DataType::UInt16 => downcast_and_pack!(UInt16Array, UInt16),
42 DataType::UInt32 => downcast_and_pack!(UInt32Array, UInt32),
43 DataType::UInt64 => downcast_and_pack!(UInt64Array, UInt64),
44 DataType::Int8 => downcast_and_pack!(Int8Array, Int8),
45 DataType::Int16 => downcast_and_pack!(Int16Array, Int16),
46 DataType::Int32 => downcast_and_pack!(Int32Array, Int32),
47 DataType::Int64 => downcast_and_pack!(Int64Array, Int64),
48 DataType::Int128 => downcast_and_pack!(Int128Array, Int128),
49 DataType::Float32 => downcast_and_pack!(Float32Array, Float32),
50 DataType::Float64 => downcast_and_pack!(Float64Array, Float64),
51 DataType::List(dt) => {
52 let v: ArrayRef = downcast!(LargeListArray);
53 if dt.is_primitive() {
54 let s = Series::from_chunks_and_dtype_unchecked(PlSmallStr::EMPTY, vec![v], dt);
55 AnyValue::List(s)
56 } else {
57 let s = Series::from_chunks_and_dtype_unchecked(
58 PlSmallStr::EMPTY,
59 vec![v],
60 &dt.to_physical(),
61 )
62 .from_physical_unchecked(dt)
63 .unwrap();
64 AnyValue::List(s)
65 }
66 },
67 #[cfg(feature = "dtype-array")]
68 DataType::Array(dt, width) => {
69 let v: ArrayRef = downcast!(FixedSizeListArray);
70 if dt.is_primitive() {
71 let s = Series::from_chunks_and_dtype_unchecked(PlSmallStr::EMPTY, vec![v], dt);
72 AnyValue::Array(s, *width)
73 } else {
74 let s = Series::from_chunks_and_dtype_unchecked(
75 PlSmallStr::EMPTY,
76 vec![v],
77 &dt.to_physical(),
78 )
79 .from_physical_unchecked(dt)
80 .unwrap();
81 AnyValue::Array(s, *width)
82 }
83 },
84 #[cfg(feature = "dtype-categorical")]
85 DataType::Categorical(rev_map, _) => {
86 let arr = &*(arr as *const dyn Array as *const UInt32Array);
87 let v = arr.value_unchecked(idx);
88 AnyValue::Categorical(v, rev_map.as_ref().unwrap().as_ref(), SyncPtr::new_null())
89 },
90 #[cfg(feature = "dtype-categorical")]
91 DataType::Enum(rev_map, _) => {
92 let arr = &*(arr as *const dyn Array as *const UInt32Array);
93 let v = arr.value_unchecked(idx);
94 AnyValue::Enum(v, rev_map.as_ref().unwrap().as_ref(), SyncPtr::new_null())
95 },
96 #[cfg(feature = "dtype-struct")]
97 DataType::Struct(flds) => {
98 let arr = &*(arr as *const dyn Array as *const StructArray);
99 AnyValue::Struct(idx, arr, flds)
100 },
101 #[cfg(feature = "dtype-datetime")]
102 DataType::Datetime(tu, tz) => {
103 let arr = &*(arr as *const dyn Array as *const Int64Array);
104 let v = arr.value_unchecked(idx);
105 AnyValue::Datetime(v, *tu, tz.as_ref())
106 },
107 #[cfg(feature = "dtype-date")]
108 DataType::Date => {
109 let arr = &*(arr as *const dyn Array as *const Int32Array);
110 let v = arr.value_unchecked(idx);
111 AnyValue::Date(v)
112 },
113 #[cfg(feature = "dtype-duration")]
114 DataType::Duration(tu) => {
115 let arr = &*(arr as *const dyn Array as *const Int64Array);
116 let v = arr.value_unchecked(idx);
117 AnyValue::Duration(v, *tu)
118 },
119 #[cfg(feature = "dtype-time")]
120 DataType::Time => {
121 let arr = &*(arr as *const dyn Array as *const Int64Array);
122 let v = arr.value_unchecked(idx);
123 AnyValue::Time(v)
124 },
125 #[cfg(feature = "dtype-decimal")]
126 DataType::Decimal(precision, scale) => {
127 let arr = &*(arr as *const dyn Array as *const Int128Array);
128 let v = arr.value_unchecked(idx);
129 AnyValue::Decimal(v, scale.unwrap_or_else(|| unreachable!()))
130 },
131 #[cfg(feature = "object")]
132 DataType::Object(_) => {
133 let arr = arr.as_any().downcast_ref::<FixedSizeBinaryArray>().unwrap();
136 PolarsExtension::arr_to_av(arr, idx)
137 },
138 DataType::Null => AnyValue::Null,
139 DataType::BinaryOffset => downcast_and_pack!(LargeBinaryArray, Binary),
140 dt => panic!("not implemented for {dt:?}"),
141 }
142}
143
144#[cfg(feature = "dtype-struct")]
145impl<'a> AnyValue<'a> {
146 pub fn _iter_struct_av(&self) -> impl Iterator<Item = AnyValue> {
147 match self {
148 AnyValue::Struct(idx, arr, flds) => {
149 let idx = *idx;
150 unsafe {
151 arr.values().iter().zip(*flds).map(move |(arr, fld)| {
152 #[cfg(feature = "dtype-categorical")]
155 {
156 use arrow::legacy::is_valid::IsValid as _;
157 if let Some(arr) = arr.as_any().downcast_ref::<DictionaryArray<u32>>() {
158 let keys = arr.keys();
159 let values = arr.values();
160 let values =
161 values.as_any().downcast_ref::<Utf8ViewArray>().unwrap();
162 let arr = &*(keys as *const dyn Array as *const UInt32Array);
163
164 if arr.is_valid_unchecked(idx) {
165 let v = arr.value_unchecked(idx);
166 match fld.dtype() {
167 DataType::Categorical(Some(rev_map), _) => {
168 AnyValue::Categorical(
169 v,
170 rev_map,
171 SyncPtr::from_const(values),
172 )
173 },
174 DataType::Enum(Some(rev_map), _) => {
175 AnyValue::Enum(v, rev_map, SyncPtr::from_const(values))
176 },
177 _ => unimplemented!(),
178 }
179 } else {
180 AnyValue::Null
181 }
182 } else {
183 arr_to_any_value(&**arr, idx, fld.dtype())
184 }
185 }
186
187 #[cfg(not(feature = "dtype-categorical"))]
188 {
189 arr_to_any_value(&**arr, idx, fld.dtype())
190 }
191 })
192 }
193 },
194 _ => unreachable!(),
195 }
196 }
197
198 pub fn _materialize_struct_av(&'a self, buf: &mut Vec<AnyValue<'a>>) {
199 let iter = self._iter_struct_av();
200 buf.extend(iter)
201 }
202}
203
204macro_rules! get_any_value_unchecked {
205 ($self:ident, $index:expr) => {{
206 let (chunk_idx, idx) = $self.index_to_chunked_index($index);
207 debug_assert!(chunk_idx < $self.chunks.len());
208 let arr = &**$self.chunks.get_unchecked(chunk_idx);
209 debug_assert!(idx < arr.len());
210 arr_to_any_value(arr, idx, $self.dtype())
211 }};
212}
213
214macro_rules! get_any_value {
215 ($self:ident, $index:expr) => {{
216 if $index >= $self.len() {
217 polars_bail!(oob = $index, $self.len());
218 }
219 Ok(unsafe { $self.get_any_value_unchecked($index) })
222 }};
223}
224
225impl<T> ChunkAnyValue for ChunkedArray<T>
226where
227 T: PolarsNumericType,
228{
229 #[inline]
230 unsafe fn get_any_value_unchecked(&self, index: usize) -> AnyValue {
231 get_any_value_unchecked!(self, index)
232 }
233
234 fn get_any_value(&self, index: usize) -> PolarsResult<AnyValue> {
235 get_any_value!(self, index)
236 }
237}
238
239impl ChunkAnyValue for BooleanChunked {
240 #[inline]
241 unsafe fn get_any_value_unchecked(&self, index: usize) -> AnyValue {
242 get_any_value_unchecked!(self, index)
243 }
244
245 fn get_any_value(&self, index: usize) -> PolarsResult<AnyValue> {
246 get_any_value!(self, index)
247 }
248}
249
250impl ChunkAnyValue for StringChunked {
251 #[inline]
252 unsafe fn get_any_value_unchecked(&self, index: usize) -> AnyValue {
253 get_any_value_unchecked!(self, index)
254 }
255
256 fn get_any_value(&self, index: usize) -> PolarsResult<AnyValue> {
257 get_any_value!(self, index)
258 }
259}
260
261impl ChunkAnyValue for BinaryChunked {
262 #[inline]
263 unsafe fn get_any_value_unchecked(&self, index: usize) -> AnyValue {
264 get_any_value_unchecked!(self, index)
265 }
266
267 fn get_any_value(&self, index: usize) -> PolarsResult<AnyValue> {
268 get_any_value!(self, index)
269 }
270}
271
272impl ChunkAnyValue for BinaryOffsetChunked {
273 #[inline]
274 unsafe fn get_any_value_unchecked(&self, index: usize) -> AnyValue {
275 get_any_value_unchecked!(self, index)
276 }
277
278 fn get_any_value(&self, index: usize) -> PolarsResult<AnyValue> {
279 get_any_value!(self, index)
280 }
281}
282
283impl ChunkAnyValue for ListChunked {
284 #[inline]
285 unsafe fn get_any_value_unchecked(&self, index: usize) -> AnyValue {
286 get_any_value_unchecked!(self, index)
287 }
288
289 fn get_any_value(&self, index: usize) -> PolarsResult<AnyValue> {
290 get_any_value!(self, index)
291 }
292}
293
294#[cfg(feature = "dtype-array")]
295impl ChunkAnyValue for ArrayChunked {
296 #[inline]
297 unsafe fn get_any_value_unchecked(&self, index: usize) -> AnyValue {
298 get_any_value_unchecked!(self, index)
299 }
300
301 fn get_any_value(&self, index: usize) -> PolarsResult<AnyValue> {
302 get_any_value!(self, index)
303 }
304}
305
306#[cfg(feature = "object")]
307impl<T: PolarsObject> ChunkAnyValue for ObjectChunked<T> {
308 #[inline]
309 unsafe fn get_any_value_unchecked(&self, index: usize) -> AnyValue {
310 match self.get_object_unchecked(index) {
311 None => AnyValue::Null,
312 Some(v) => AnyValue::Object(v),
313 }
314 }
315
316 fn get_any_value(&self, index: usize) -> PolarsResult<AnyValue> {
317 get_any_value!(self, index)
318 }
319}
320
321impl ChunkAnyValue for NullChunked {
322 #[inline]
323 unsafe fn get_any_value_unchecked(&self, _index: usize) -> AnyValue {
324 AnyValue::Null
325 }
326
327 fn get_any_value(&self, _index: usize) -> PolarsResult<AnyValue> {
328 Ok(AnyValue::Null)
329 }
330}
331
332#[cfg(feature = "dtype-struct")]
333impl ChunkAnyValue for StructChunked {
334 fn get_any_value(&self, i: usize) -> PolarsResult<AnyValue<'_>> {
336 polars_ensure!(i < self.len(), oob = i, self.len());
337 unsafe { Ok(self.get_any_value_unchecked(i)) }
338 }
339
340 unsafe fn get_any_value_unchecked(&self, i: usize) -> AnyValue<'_> {
341 let (chunk_idx, idx) = index_to_chunked_index(self.chunks.iter().map(|c| c.len()), i);
342 if let DataType::Struct(flds) = self.dtype() {
343 unsafe {
346 let arr = &**self.chunks.get_unchecked(chunk_idx);
347 let arr = &*(arr as *const dyn Array as *const StructArray);
348
349 if arr.is_null_unchecked(idx) {
350 AnyValue::Null
351 } else {
352 AnyValue::Struct(idx, arr, flds)
353 }
354 }
355 } else {
356 unreachable!()
357 }
358 }
359}