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