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