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