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