1use std::fmt::Write;
2
3use arrow::bitmap::Bitmap;
4use num_traits::AsPrimitive;
5use polars_compute::cast::SerPrimitive;
6
7#[cfg(feature = "dtype-categorical")]
8use crate::chunked_array::builder::CategoricalChunkedBuilder;
9use crate::chunked_array::builder::{AnonymousOwnedListBuilder, get_list_builder};
10use crate::prelude::*;
11use crate::utils::any_values_to_supertype;
12
13impl<'a, T: AsRef<[AnyValue<'a>]>> NamedFrom<T, [AnyValue<'a>]> for Series {
14 fn new(name: PlSmallStr, values: T) -> Self {
23 let values = values.as_ref();
24 Series::from_any_values(name, values, true).expect("data types of values should match")
25 }
26}
27
28impl Series {
29 pub fn from_any_values(
42 name: PlSmallStr,
43 values: &[AnyValue],
44 strict: bool,
45 ) -> PolarsResult<Self> {
46 fn get_first_non_null_dtype(values: &[AnyValue]) -> DataType {
47 let mut all_flat_null = true;
48 let first_non_null = values.iter().find(|av| {
49 if !av.is_null() {
50 all_flat_null = false
51 };
52 !av.is_nested_null()
53 });
54 match first_non_null {
55 Some(av) => av.dtype(),
56 None => {
57 if all_flat_null {
58 DataType::Null
59 } else {
60 let first_nested_null = values.iter().find(|av| !av.is_null()).unwrap();
63 first_nested_null.dtype()
64 }
65 },
66 }
67 }
68 let dtype = if strict {
69 match get_first_non_null_dtype(values) {
70 #[cfg(feature = "dtype-decimal")]
71 DataType::Decimal(mut prec, mut scale) => {
72 for v in values {
73 if let DataType::Decimal(p, s) = v.dtype() {
74 prec = prec.max(p);
75 scale = scale.max(s);
76 }
77 }
78 DataType::Decimal(prec, scale)
79 },
80 dt => dt,
81 }
82 } else {
83 any_values_to_supertype(values)?
84 };
85
86 Self::from_any_values_and_dtype(name, values, &dtype, strict)
87 }
88
89 pub fn from_any_values_and_dtype(
95 name: PlSmallStr,
96 values: &[AnyValue],
97 dtype: &DataType,
98 strict: bool,
99 ) -> PolarsResult<Self> {
100 Self::from_any_values_and_dtype_unnamed(values, dtype, strict)
101 .with_context(|| format!("while constructing Series '{name}'"))
102 .map(|s| s.with_name(name))
103 }
104
105 fn from_any_values_and_dtype_unnamed(
106 values: &[AnyValue],
107 dtype: &DataType,
108 strict: bool,
109 ) -> PolarsResult<Self> {
110 if values.is_empty() {
111 return Ok(Self::new_empty(PlSmallStr::EMPTY, dtype));
112 }
113
114 Ok(match dtype {
115 #[cfg(feature = "dtype-i8")]
116 DataType::Int8 => any_values_to_integer::<Int8Type>(values, strict)?.into_series(),
117 #[cfg(feature = "dtype-i16")]
118 DataType::Int16 => any_values_to_integer::<Int16Type>(values, strict)?.into_series(),
119 DataType::Int32 => any_values_to_integer::<Int32Type>(values, strict)?.into_series(),
120 DataType::Int64 => any_values_to_integer::<Int64Type>(values, strict)?.into_series(),
121 #[cfg(feature = "dtype-i128")]
122 DataType::Int128 => any_values_to_integer::<Int128Type>(values, strict)?.into_series(),
123 #[cfg(feature = "dtype-u8")]
124 DataType::UInt8 => any_values_to_integer::<UInt8Type>(values, strict)?.into_series(),
125 #[cfg(feature = "dtype-u16")]
126 DataType::UInt16 => any_values_to_integer::<UInt16Type>(values, strict)?.into_series(),
127 DataType::UInt32 => any_values_to_integer::<UInt32Type>(values, strict)?.into_series(),
128 DataType::UInt64 => any_values_to_integer::<UInt64Type>(values, strict)?.into_series(),
129 #[cfg(feature = "dtype-u128")]
130 DataType::UInt128 => {
131 any_values_to_integer::<UInt128Type>(values, strict)?.into_series()
132 },
133 #[cfg(feature = "dtype-f16")]
134 DataType::Float16 => any_values_to_f16(values, strict)?.into_series(),
135 DataType::Float32 => any_values_to_f32(values, strict)?.into_series(),
136 DataType::Float64 => any_values_to_f64(values, strict)?.into_series(),
137 DataType::Boolean => any_values_to_bool(values, strict)?.into_series(),
138 DataType::String => any_values_to_string(values, strict)?.into_series(),
139 DataType::Binary => any_values_to_binary(values, strict)?.into_series(),
140 DataType::BinaryOffset => any_values_to_binary_offset(values, strict)?.into_series(),
141 #[cfg(feature = "dtype-date")]
142 DataType::Date => any_values_to_date(values, strict)?.into_series(),
143 #[cfg(feature = "dtype-time")]
144 DataType::Time => any_values_to_time(values, strict)?.into_series(),
145 #[cfg(feature = "dtype-datetime")]
146 DataType::Datetime(tu, tz) => {
147 any_values_to_datetime(values, *tu, (*tz).clone(), strict)?.into_series()
148 },
149 #[cfg(feature = "dtype-duration")]
150 DataType::Duration(tu) => any_values_to_duration(values, *tu, strict)?.into_series(),
151 #[cfg(feature = "dtype-categorical")]
152 dt @ (DataType::Categorical(_, _) | DataType::Enum(_, _)) => {
153 any_values_to_categorical(values, dt, strict)?
154 },
155 #[cfg(feature = "dtype-decimal")]
156 DataType::Decimal(precision, scale) => {
157 any_values_to_decimal(values, *precision, *scale, strict)?.into_series()
158 },
159 #[cfg(feature = "dtype-extension")]
160 DataType::Extension(typ, storage) => {
161 Series::from_any_values_and_dtype_unnamed(values, storage, strict)?
162 .into_extension(typ.clone())
163 },
164 DataType::List(inner) => any_values_to_list(values, inner, strict)?.into_series(),
165 #[cfg(feature = "dtype-array")]
166 DataType::Array(inner, size) => any_values_to_array(values, inner, strict, *size)?
167 .into_series()
168 .cast(&DataType::Array(inner.clone(), *size))?,
169 #[cfg(feature = "dtype-struct")]
170 DataType::Struct(fields) => any_values_to_struct(values, fields, strict)?,
171 #[cfg(feature = "object")]
172 DataType::Object(_) => any_values_to_object(values)?,
173 DataType::Null => Series::new_null(PlSmallStr::EMPTY, values.len()),
174 dt => {
175 polars_bail!(
176 InvalidOperation:
177 "constructing a Series with data type {dt:?} from AnyValues is not supported"
178 )
179 },
180 })
181 }
182}
183
184fn any_values_to_primitive_nonstrict<T: PolarsNumericType>(values: &[AnyValue]) -> ChunkedArray<T> {
185 values
186 .iter()
187 .map(|av| av.extract::<T::Native>())
188 .collect_trusted()
189}
190
191fn any_values_to_integer<T: PolarsIntegerType>(
192 values: &[AnyValue],
193 strict: bool,
194) -> PolarsResult<ChunkedArray<T>> {
195 fn any_values_to_integer_strict<T: PolarsIntegerType>(
196 values: &[AnyValue],
197 ) -> PolarsResult<ChunkedArray<T>> {
198 let mut builder = PrimitiveChunkedBuilder::<T>::new(PlSmallStr::EMPTY, values.len());
199 for av in values {
200 match &av {
201 av if av.is_integer() => {
202 let opt_val = av.extract::<T::Native>();
203 let val = match opt_val {
204 Some(v) => v,
205 None => return Err(invalid_value_error(&T::get_static_dtype(), av)),
206 };
207 builder.append_value(val)
208 },
209 AnyValue::Null => builder.append_null(),
210 av => return Err(invalid_value_error(&T::get_static_dtype(), av)),
211 }
212 }
213 Ok(builder.finish())
214 }
215
216 if strict {
217 any_values_to_integer_strict::<T>(values)
218 } else {
219 Ok(any_values_to_primitive_nonstrict::<T>(values))
220 }
221}
222
223#[cfg(feature = "dtype-f16")]
224fn any_values_to_f16(values: &[AnyValue], strict: bool) -> PolarsResult<Float16Chunked> {
225 fn any_values_to_f16_strict(values: &[AnyValue]) -> PolarsResult<Float16Chunked> {
226 let mut builder =
227 PrimitiveChunkedBuilder::<Float16Type>::new(PlSmallStr::EMPTY, values.len());
228 for av in values {
229 match av {
230 AnyValue::Float16(i) => builder.append_value(*i),
231 AnyValue::Null => builder.append_null(),
232 av => return Err(invalid_value_error(&DataType::Float16, av)),
233 }
234 }
235 Ok(builder.finish())
236 }
237 if strict {
238 any_values_to_f16_strict(values)
239 } else {
240 Ok(any_values_to_primitive_nonstrict::<Float16Type>(values))
241 }
242}
243
244fn any_values_to_f32(values: &[AnyValue], strict: bool) -> PolarsResult<Float32Chunked> {
245 fn any_values_to_f32_strict(values: &[AnyValue]) -> PolarsResult<Float32Chunked> {
246 let mut builder =
247 PrimitiveChunkedBuilder::<Float32Type>::new(PlSmallStr::EMPTY, values.len());
248 for av in values {
249 match av {
250 AnyValue::Float32(i) => builder.append_value(*i),
251 AnyValue::Float16(i) => builder.append_value(i.as_()),
252 AnyValue::Null => builder.append_null(),
253 av => return Err(invalid_value_error(&DataType::Float32, av)),
254 }
255 }
256 Ok(builder.finish())
257 }
258 if strict {
259 any_values_to_f32_strict(values)
260 } else {
261 Ok(any_values_to_primitive_nonstrict::<Float32Type>(values))
262 }
263}
264fn any_values_to_f64(values: &[AnyValue], strict: bool) -> PolarsResult<Float64Chunked> {
265 fn any_values_to_f64_strict(values: &[AnyValue]) -> PolarsResult<Float64Chunked> {
266 let mut builder =
267 PrimitiveChunkedBuilder::<Float64Type>::new(PlSmallStr::EMPTY, values.len());
268 for av in values {
269 match av {
270 AnyValue::Float64(i) => builder.append_value(*i),
271 AnyValue::Float32(i) => builder.append_value(*i as f64),
272 AnyValue::Float16(i) => builder.append_value(i.as_()),
273 AnyValue::Null => builder.append_null(),
274 av => return Err(invalid_value_error(&DataType::Float64, av)),
275 }
276 }
277 Ok(builder.finish())
278 }
279 if strict {
280 any_values_to_f64_strict(values)
281 } else {
282 Ok(any_values_to_primitive_nonstrict::<Float64Type>(values))
283 }
284}
285
286fn any_values_to_bool(values: &[AnyValue], strict: bool) -> PolarsResult<BooleanChunked> {
287 let mut builder = BooleanChunkedBuilder::new(PlSmallStr::EMPTY, values.len());
288 for av in values {
289 match av {
290 AnyValue::Boolean(b) => builder.append_value(*b),
291 AnyValue::Null => builder.append_null(),
292 av => {
293 if strict {
294 return Err(invalid_value_error(&DataType::Boolean, av));
295 }
296 match av.cast(&DataType::Boolean) {
297 AnyValue::Boolean(b) => builder.append_value(b),
298 _ => builder.append_null(),
299 }
300 },
301 }
302 }
303 Ok(builder.finish())
304}
305
306fn any_values_to_string(values: &[AnyValue], strict: bool) -> PolarsResult<StringChunked> {
307 fn any_values_to_string_strict(values: &[AnyValue]) -> PolarsResult<StringChunked> {
308 let mut builder = StringChunkedBuilder::new(PlSmallStr::EMPTY, values.len());
309 for av in values {
310 match av {
311 AnyValue::String(s) => builder.append_value(s),
312 AnyValue::StringOwned(s) => builder.append_value(s),
313 AnyValue::Null => builder.append_null(),
314 av => return Err(invalid_value_error(&DataType::String, av)),
315 }
316 }
317 Ok(builder.finish())
318 }
319 fn any_values_to_string_nonstrict(values: &[AnyValue]) -> StringChunked {
320 fn _write_any_value(av: &AnyValue<'_>, buffer: &mut String) {
321 match av {
322 AnyValue::String(s) => buffer.push_str(s),
323 AnyValue::Float64(f) => {
324 SerPrimitive::write(unsafe { buffer.as_mut_vec() }, *f);
325 },
326 AnyValue::Float32(f) => {
327 SerPrimitive::write(unsafe { buffer.as_mut_vec() }, *f);
328 },
329 #[cfg(feature = "dtype-f16")]
330 AnyValue::Float16(f) => {
331 SerPrimitive::write(unsafe { buffer.as_mut_vec() }, *f);
332 },
333 #[cfg(feature = "dtype-struct")]
334 AnyValue::StructOwned(payload) => {
335 buffer.push('{');
336 let mut iter = payload.0.iter().peekable();
337 while let Some(child) = iter.next() {
338 _write_any_value(child, buffer);
339 if iter.peek().is_some() {
340 buffer.push(',')
341 }
342 }
343 buffer.push('}');
344 },
345 #[cfg(feature = "dtype-struct")]
346 AnyValue::Struct(_, _, flds) => {
347 let mut vals = Vec::with_capacity(flds.len());
348 av._materialize_struct_av(&mut vals);
349
350 buffer.push('{');
351 let mut iter = vals.iter().peekable();
352 while let Some(child) = iter.next() {
353 _write_any_value(child, buffer);
354 if iter.peek().is_some() {
355 buffer.push(',')
356 }
357 }
358 buffer.push('}');
359 },
360 #[cfg(feature = "dtype-array")]
361 AnyValue::Array(vals, _) => {
362 buffer.push('[');
363 let mut iter = vals.iter().peekable();
364 while let Some(child) = iter.next() {
365 _write_any_value(&child, buffer);
366 if iter.peek().is_some() {
367 buffer.push(',');
368 }
369 }
370 buffer.push(']');
371 },
372 AnyValue::List(vals) => {
373 buffer.push('[');
374 let mut iter = vals.iter().peekable();
375 while let Some(child) = iter.next() {
376 _write_any_value(&child, buffer);
377 if iter.peek().is_some() {
378 buffer.push(',');
379 }
380 }
381 buffer.push(']');
382 },
383 av => {
384 write!(buffer, "{av}").unwrap();
385 },
386 }
387 }
388
389 let mut builder = StringChunkedBuilder::new(PlSmallStr::EMPTY, values.len());
390 let mut owned = String::new(); for av in values {
392 owned.clear();
393
394 match av {
395 AnyValue::String(s) => builder.append_value(s),
396 AnyValue::StringOwned(s) => builder.append_value(s),
397 AnyValue::Null => builder.append_null(),
398 AnyValue::Binary(_) | AnyValue::BinaryOwned(_) => builder.append_null(),
399
400 av => {
405 _write_any_value(av, &mut owned);
406 builder.append_value(&owned);
407 },
408 }
409 }
410 builder.finish()
411 }
412 if strict {
413 any_values_to_string_strict(values)
414 } else {
415 Ok(any_values_to_string_nonstrict(values))
416 }
417}
418
419fn any_values_to_binary(values: &[AnyValue], strict: bool) -> PolarsResult<BinaryChunked> {
420 fn any_values_to_binary_strict(values: &[AnyValue]) -> PolarsResult<BinaryChunked> {
421 let mut builder = BinaryChunkedBuilder::new(PlSmallStr::EMPTY, values.len());
422 for av in values {
423 match av {
424 AnyValue::Binary(s) => builder.append_value(*s),
425 AnyValue::BinaryOwned(s) => builder.append_value(&**s),
426 AnyValue::Null => builder.append_null(),
427 av => return Err(invalid_value_error(&DataType::Binary, av)),
428 }
429 }
430 Ok(builder.finish())
431 }
432 fn any_values_to_binary_nonstrict(values: &[AnyValue]) -> BinaryChunked {
433 values
434 .iter()
435 .map(|av| match av {
436 AnyValue::Binary(b) => Some(*b),
437 AnyValue::BinaryOwned(b) => Some(&**b),
438 AnyValue::String(s) => Some(s.as_bytes()),
439 AnyValue::StringOwned(s) => Some(s.as_bytes()),
440 _ => None,
441 })
442 .collect_trusted()
443 }
444 if strict {
445 any_values_to_binary_strict(values)
446 } else {
447 Ok(any_values_to_binary_nonstrict(values))
448 }
449}
450
451fn any_values_to_binary_offset(
452 values: &[AnyValue],
453 strict: bool,
454) -> PolarsResult<BinaryOffsetChunked> {
455 let mut builder = MutableBinaryArray::<i64>::new();
456 for av in values {
457 match av {
458 AnyValue::Binary(s) => builder.push(Some(*s)),
459 AnyValue::BinaryOwned(s) => builder.push(Some(&**s)),
460 AnyValue::Null => builder.push_null(),
461 av => {
462 if strict {
463 return Err(invalid_value_error(&DataType::Binary, av));
464 } else {
465 builder.push_null();
466 };
467 },
468 }
469 }
470 Ok(BinaryOffsetChunked::with_chunk(
471 Default::default(),
472 builder.into(),
473 ))
474}
475
476#[cfg(feature = "dtype-date")]
477fn any_values_to_date(values: &[AnyValue], strict: bool) -> PolarsResult<DateChunked> {
478 let mut builder = PrimitiveChunkedBuilder::<Int32Type>::new(PlSmallStr::EMPTY, values.len());
479 for av in values {
480 match av {
481 AnyValue::Date(i) => builder.append_value(*i),
482 AnyValue::Null => builder.append_null(),
483 av => {
484 if strict {
485 return Err(invalid_value_error(&DataType::Date, av));
486 }
487 match av.cast(&DataType::Date) {
488 AnyValue::Date(i) => builder.append_value(i),
489 _ => builder.append_null(),
490 }
491 },
492 }
493 }
494 Ok(builder.finish().into_date())
495}
496
497#[cfg(feature = "dtype-time")]
498fn any_values_to_time(values: &[AnyValue], strict: bool) -> PolarsResult<TimeChunked> {
499 let mut builder = PrimitiveChunkedBuilder::<Int64Type>::new(PlSmallStr::EMPTY, values.len());
500 for av in values {
501 match av {
502 AnyValue::Time(i) => builder.append_value(*i),
503 AnyValue::Null => builder.append_null(),
504 av => {
505 if strict {
506 return Err(invalid_value_error(&DataType::Time, av));
507 }
508 match av.cast(&DataType::Time) {
509 AnyValue::Time(i) => builder.append_value(i),
510 _ => builder.append_null(),
511 }
512 },
513 }
514 }
515 Ok(builder.finish().into_time())
516}
517
518#[cfg(feature = "dtype-datetime")]
519fn any_values_to_datetime(
520 values: &[AnyValue],
521 time_unit: TimeUnit,
522 time_zone: Option<TimeZone>,
523 strict: bool,
524) -> PolarsResult<DatetimeChunked> {
525 let mut builder = PrimitiveChunkedBuilder::<Int64Type>::new(PlSmallStr::EMPTY, values.len());
526 let target_dtype = DataType::Datetime(time_unit, time_zone.clone());
527 for av in values {
528 match av {
529 AnyValue::Datetime(i, tu, _) if *tu == time_unit => builder.append_value(*i),
530 AnyValue::DatetimeOwned(i, tu, _) if *tu == time_unit => builder.append_value(*i),
531 AnyValue::Null => builder.append_null(),
532 av => {
533 if strict {
534 return Err(invalid_value_error(&target_dtype, av));
535 }
536 match av.cast(&target_dtype) {
537 AnyValue::Datetime(i, _, _) => builder.append_value(i),
538 AnyValue::DatetimeOwned(i, _, _) => builder.append_value(i),
539 _ => builder.append_null(),
540 }
541 },
542 }
543 }
544 Ok(builder.finish().into_datetime(time_unit, time_zone))
545}
546
547#[cfg(feature = "dtype-duration")]
548fn any_values_to_duration(
549 values: &[AnyValue],
550 time_unit: TimeUnit,
551 strict: bool,
552) -> PolarsResult<DurationChunked> {
553 let mut builder = PrimitiveChunkedBuilder::<Int64Type>::new(PlSmallStr::EMPTY, values.len());
554 let target_dtype = DataType::Duration(time_unit);
555 for av in values {
556 match av {
557 AnyValue::Duration(i, tu) if *tu == time_unit => builder.append_value(*i),
558 AnyValue::Null => builder.append_null(),
559 av => {
560 if strict {
561 return Err(invalid_value_error(&target_dtype, av));
562 }
563 match av.cast(&target_dtype) {
564 AnyValue::Duration(i, _) => builder.append_value(i),
565 _ => builder.append_null(),
566 }
567 },
568 }
569 }
570 Ok(builder.finish().into_duration(time_unit))
571}
572
573#[cfg(feature = "dtype-categorical")]
574fn any_values_to_categorical(
575 values: &[AnyValue],
576 dtype: &DataType,
577 strict: bool,
578) -> PolarsResult<Series> {
579 with_match_categorical_physical_type!(dtype.cat_physical().unwrap(), |$C| {
580 let mut builder = CategoricalChunkedBuilder::<$C>::new(PlSmallStr::EMPTY, dtype.clone());
581
582 let mut owned = String::new(); for av in values {
584 let ret = match av {
585 AnyValue::String(s) => builder.append_str(s),
586 AnyValue::StringOwned(s) => builder.append_str(s),
587
588 &AnyValue::Enum(cat, &ref map) |
589 &AnyValue::EnumOwned(cat, ref map) |
590 &AnyValue::Categorical(cat, &ref map) |
591 &AnyValue::CategoricalOwned(cat, ref map) => builder.append_cat(cat, map),
592
593 AnyValue::Binary(_) | AnyValue::BinaryOwned(_) if !strict => {
594 builder.append_null();
595 Ok(())
596 },
597 AnyValue::Null => {
598 builder.append_null();
599 Ok(())
600 }
601
602 av => {
603 if strict {
604 return Err(invalid_value_error(&DataType::String, av));
605 }
606
607 owned.clear();
608 write!(owned, "{av}").unwrap();
609 builder.append_str(&owned)
610 },
611 };
612
613 if let Err(e) = ret {
614 if strict {
615 return Err(e);
616 } else {
617 builder.append_null();
618 }
619 }
620 }
621
622 let ca = builder.finish();
623 Ok(ca.into_series())
624 })
625}
626
627#[cfg(feature = "dtype-decimal")]
628fn any_values_to_decimal(
629 values: &[AnyValue],
630 precision: usize,
631 scale: usize,
632 strict: bool,
633) -> PolarsResult<DecimalChunked> {
634 let target_dtype = DataType::Decimal(precision, scale);
635
636 let mut builder = PrimitiveChunkedBuilder::<Int128Type>::new(PlSmallStr::EMPTY, values.len());
637 for av in values {
638 match av {
639 AnyValue::Decimal(v, p, s) if *s <= scale => {
641 if *p <= precision && *s == scale {
642 builder.append_value(*v)
643 } else {
644 match av.strict_cast(&target_dtype) {
645 Some(AnyValue::Decimal(i, _, _)) => builder.append_value(i),
646 _ => builder.append_null(),
647 }
648 }
649 },
650 AnyValue::Null => builder.append_null(),
651 av => {
652 if strict {
653 return Err(invalid_value_error(&target_dtype, av));
654 }
655 match av.strict_cast(&target_dtype) {
656 Some(AnyValue::Decimal(i, _, _)) => builder.append_value(i),
657 _ => builder.append_null(),
658 }
659 },
660 };
661 }
662
663 builder.finish().into_decimal(precision, scale)
665}
666
667fn any_values_to_list(
668 avs: &[AnyValue],
669 inner_type: &DataType,
670 strict: bool,
671) -> PolarsResult<ListChunked> {
672 let mut valid = true;
688 let capacity = avs.len();
689
690 let ca = match inner_type {
691 DataType::Null => {
697 let mut builder = AnonymousOwnedListBuilder::new(PlSmallStr::EMPTY, capacity, None);
698 for av in avs {
699 match av {
700 AnyValue::List(b) => builder.append_series(b)?,
701 AnyValue::Null => builder.append_null(),
702 _ => {
703 valid = false;
704 builder.append_null();
705 },
706 }
707 }
708 builder.finish()
709 },
710
711 #[cfg(feature = "object")]
712 DataType::Object(_) => polars_bail!(nyi = "Nested object types"),
713
714 _ => {
715 let mut builder =
716 get_list_builder(inner_type, capacity * 5, capacity, PlSmallStr::EMPTY);
717 for av in avs {
718 match av {
719 AnyValue::List(b) => match b.cast(inner_type) {
720 Ok(casted) => {
721 if casted.null_count() != b.null_count() {
722 valid = !strict;
723 }
724 builder.append_series(&casted)?;
725 },
726 Err(_) => {
727 valid = false;
728 for _ in 0..b.len() {
729 builder.append_null();
730 }
731 },
732 },
733 AnyValue::Null => builder.append_null(),
734 _ => {
735 valid = false;
736 builder.append_null()
737 },
738 }
739 }
740
741 builder.finish()
742 },
743 };
744
745 if strict && !valid {
746 polars_bail!(SchemaMismatch: "unexpected value while building Series of type {:?}", DataType::List(Box::new(inner_type.clone())));
747 }
748
749 Ok(ca)
750}
751
752#[cfg(feature = "dtype-array")]
753fn any_values_to_array(
754 avs: &[AnyValue],
755 inner_type: &DataType,
756 strict: bool,
757 width: usize,
758) -> PolarsResult<ArrayChunked> {
759 fn to_arr(s: &Series) -> Option<ArrayRef> {
760 if s.chunks().len() > 1 {
761 let s = s.rechunk();
762 Some(s.chunks()[0].clone())
763 } else {
764 Some(s.chunks()[0].clone())
765 }
766 }
767
768 let target_dtype = DataType::Array(Box::new(inner_type.clone()), width);
769
770 let mut valid = true;
772 #[allow(unused_mut)]
773 let mut out: ArrayChunked = if inner_type == &DataType::Null {
774 avs.iter()
775 .map(|av| match av {
776 AnyValue::List(b) | AnyValue::Array(b, _) => to_arr(b),
777 AnyValue::Null => None,
778 _ => {
779 valid = false;
780 None
781 },
782 })
783 .collect_ca_with_dtype(PlSmallStr::EMPTY, target_dtype.clone())
784 }
785 else {
787 avs.iter()
788 .map(|av| match av {
789 AnyValue::List(b) | AnyValue::Array(b, _) => {
790 if b.dtype() == inner_type {
791 to_arr(b)
792 } else {
793 let s = match b.cast(inner_type) {
794 Ok(out) => out,
795 Err(_) => Series::full_null(b.name().clone(), b.len(), inner_type),
796 };
797 to_arr(&s)
798 }
799 },
800 AnyValue::Null => None,
801 _ => {
802 valid = false;
803 None
804 },
805 })
806 .collect_ca_with_dtype(PlSmallStr::EMPTY, target_dtype.clone())
807 };
808
809 if strict && !valid {
810 polars_bail!(SchemaMismatch: "unexpected value while building Series of type {:?}", target_dtype);
811 }
812 polars_ensure!(
813 out.width() == width,
814 SchemaMismatch: "got mixed size array widths where width {} was expected", width
815 );
816
817 #[cfg(feature = "dtype-struct")]
819 if !matches!(inner_type, DataType::Null) && out.inner_dtype().is_nested() {
820 unsafe {
821 out.set_dtype(target_dtype);
822 };
823 }
824
825 Ok(out)
826}
827
828#[cfg(feature = "dtype-struct")]
829fn _any_values_to_struct<'a>(
830 av_fields: &[Field],
831 av_values: &[AnyValue<'a>],
832 field_index: usize,
833 field: &Field,
834 fields: &[Field],
835 field_avs: &mut Vec<AnyValue<'a>>,
836) {
837 let mut append_by_search = || {
840 if let Some(i) = av_fields
842 .iter()
843 .position(|av_fld| av_fld.name == field.name)
844 {
845 field_avs.push(av_values[i].clone());
846 return;
847 }
848 field_avs.push(AnyValue::Null)
849 };
850
851 if fields.len() == av_fields.len() {
854 if fields.iter().zip(av_fields.iter()).any(|(l, r)| l != r) {
855 append_by_search()
856 } else {
857 let av_val = av_values
858 .get(field_index)
859 .cloned()
860 .unwrap_or(AnyValue::Null);
861 field_avs.push(av_val)
862 }
863 }
864 else {
866 append_by_search()
868 }
869}
870
871#[cfg(feature = "dtype-struct")]
872fn any_values_to_struct(
873 values: &[AnyValue],
874 fields: &[Field],
875 strict: bool,
876) -> PolarsResult<Series> {
877 if fields.is_empty() {
879 let mut out = StructChunked::from_series(PlSmallStr::EMPTY, values.len(), [].iter())?;
880 out.set_outer_validity(Bitmap::opt_from_iter(values.iter().map(|av| !av.is_null())));
881 return Ok(out.into_series());
882 }
883
884 let mut series_fields = Vec::with_capacity(fields.len());
886 let mut has_outer_validity = false;
887 let mut field_avs = Vec::with_capacity(values.len());
888 for (i, field) in fields.iter().enumerate() {
889 field_avs.clear();
890
891 for av in values.iter() {
892 match av {
893 AnyValue::StructOwned(payload) => {
894 let av_fields = &payload.1;
895 let av_values = &payload.0;
896 _any_values_to_struct(av_fields, av_values, i, field, fields, &mut field_avs);
897 },
898 AnyValue::Struct(_, _, av_fields) => {
899 let av_values: Vec<_> = av._iter_struct_av().collect();
900 _any_values_to_struct(av_fields, &av_values, i, field, fields, &mut field_avs);
901 },
902 AnyValue::List(s) if s.len() == fields.len() => {
903 let av = unsafe { s.get_unchecked(i) };
904 field_avs.push(av);
905 },
906 #[cfg(feature = "dtype-array")]
907 AnyValue::Array(s, _) if s.len() == fields.len() => {
908 let av = unsafe { s.get_unchecked(i) };
909 field_avs.push(av);
910 },
911 AnyValue::Null => {
912 has_outer_validity = true;
913 field_avs.push(AnyValue::Null)
914 },
915 _ => {
916 if strict {
917 return Err(invalid_value_error(&DataType::Struct(fields.to_vec()), av));
918 } else {
919 has_outer_validity = true;
920 field_avs.push(AnyValue::Null)
921 }
922 },
923 }
924 }
925 let s = if matches!(field.dtype, DataType::Null) {
927 Series::from_any_values(field.name().clone(), &field_avs, strict)?
928 } else {
929 Series::from_any_values_and_dtype(
930 field.name().clone(),
931 &field_avs,
932 &field.dtype,
933 strict,
934 )?
935 };
936 series_fields.push(s)
937 }
938
939 let mut out =
940 StructChunked::from_series(PlSmallStr::EMPTY, values.len(), series_fields.iter())?;
941 if has_outer_validity {
942 out.set_outer_validity(Bitmap::opt_from_iter(values.iter().map(|av| !av.is_null())));
943 }
944 Ok(out.into_series())
945}
946
947#[cfg(feature = "object")]
948fn any_values_to_object(values: &[AnyValue]) -> PolarsResult<Series> {
949 use crate::chunked_array::object::registry;
950 let converter = registry::get_object_converter();
951 let mut builder = registry::get_object_builder(PlSmallStr::EMPTY, values.len());
952 for av in values {
953 match av {
954 AnyValue::Object(val) => builder.append_value(val.as_any()),
955 AnyValue::Null => builder.append_null(),
956 _ => {
957 let any = converter(av.as_borrowed());
960 builder.append_value(&*any)
961 },
962 }
963 }
964
965 Ok(builder.to_series())
966}
967
968fn invalid_value_error(dtype: &DataType, value: &AnyValue) -> PolarsError {
969 polars_err!(
970 SchemaMismatch:
971 "unexpected value while building Series of type {:?}; found value of type {:?}: {}",
972 dtype,
973 value.dtype(),
974 value
975 )
976}