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