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