1use std::borrow::Cow;
2
3#[cfg(feature = "dtype-duration")]
4use chrono::Duration as ChronoDuration;
5#[cfg(feature = "dtype-date")]
6use chrono::NaiveDate;
7#[cfg(feature = "dtype-datetime")]
8use chrono::NaiveDateTime;
9#[cfg(feature = "dtype-time")]
10use chrono::NaiveTime;
11#[cfg(feature = "dtype-f16")]
12use polars_utils::float16::pf16;
13
14use crate::chunked_array::builder::get_list_builder;
15use crate::prelude::*;
16
17pub trait NamedFrom<T, Phantom: ?Sized> {
18 fn new(name: PlSmallStr, _: T) -> Self;
20}
21
22pub trait NamedFromOwned<T> {
23 fn from_vec(name: PlSmallStr, _: T) -> Self;
25}
26
27macro_rules! impl_named_from_owned {
28 ($type:ty, $polars_type:ident) => {
29 impl NamedFromOwned<$type> for Series {
30 fn from_vec(name: PlSmallStr, v: $type) -> Self {
31 ChunkedArray::<$polars_type>::from_vec(name, v).into_series()
32 }
33 }
34 };
35}
36
37#[cfg(feature = "dtype-i8")]
38impl_named_from_owned!(Vec<i8>, Int8Type);
39#[cfg(feature = "dtype-i16")]
40impl_named_from_owned!(Vec<i16>, Int16Type);
41impl_named_from_owned!(Vec<i32>, Int32Type);
42impl_named_from_owned!(Vec<i64>, Int64Type);
43#[cfg(feature = "dtype-i128")]
44impl_named_from_owned!(Vec<i128>, Int128Type);
45#[cfg(feature = "dtype-u8")]
46impl_named_from_owned!(Vec<u8>, UInt8Type);
47#[cfg(feature = "dtype-u16")]
48impl_named_from_owned!(Vec<u16>, UInt16Type);
49impl_named_from_owned!(Vec<u32>, UInt32Type);
50impl_named_from_owned!(Vec<u64>, UInt64Type);
51#[cfg(feature = "dtype-u128")]
52impl_named_from_owned!(Vec<u128>, UInt128Type);
53#[cfg(feature = "dtype-f16")]
54impl_named_from_owned!(Vec<pf16>, Float16Type);
55impl_named_from_owned!(Vec<f32>, Float32Type);
56impl_named_from_owned!(Vec<f64>, Float64Type);
57
58macro_rules! impl_named_from {
59 ($type:ty, $polars_type:ident, $method:ident) => {
60 impl<T: AsRef<$type>> NamedFrom<T, $type> for Series {
61 fn new(name: PlSmallStr, v: T) -> Self {
62 ChunkedArray::<$polars_type>::$method(name, v.as_ref()).into_series()
63 }
64 }
65 impl<T: AsRef<$type>> NamedFrom<T, $type> for ChunkedArray<$polars_type> {
66 fn new(name: PlSmallStr, v: T) -> Self {
67 ChunkedArray::<$polars_type>::$method(name, v.as_ref())
68 }
69 }
70 };
71}
72
73impl_named_from!([String], StringType, from_slice);
74impl_named_from!([Vec<u8>], BinaryType, from_slice);
75impl_named_from!([bool], BooleanType, from_slice);
76#[cfg(feature = "dtype-u8")]
77impl_named_from!([u8], UInt8Type, from_slice);
78#[cfg(feature = "dtype-u16")]
79impl_named_from!([u16], UInt16Type, from_slice);
80impl_named_from!([u32], UInt32Type, from_slice);
81impl_named_from!([u64], UInt64Type, from_slice);
82#[cfg(feature = "dtype-u128")]
83impl_named_from!([u128], UInt128Type, from_slice);
84#[cfg(feature = "dtype-i8")]
85impl_named_from!([i8], Int8Type, from_slice);
86#[cfg(feature = "dtype-i16")]
87impl_named_from!([i16], Int16Type, from_slice);
88impl_named_from!([i32], Int32Type, from_slice);
89impl_named_from!([i64], Int64Type, from_slice);
90#[cfg(any(feature = "dtype-i128", feature = "dtype-decimal"))]
91impl_named_from!([i128], Int128Type, from_slice);
92#[cfg(feature = "dtype-f16")]
93impl_named_from!([pf16], Float16Type, from_slice);
94impl_named_from!([f32], Float32Type, from_slice);
95impl_named_from!([f64], Float64Type, from_slice);
96impl_named_from!([Option<String>], StringType, from_slice_options);
97impl_named_from!([Option<Vec<u8>>], BinaryType, from_slice_options);
98impl_named_from!([Option<bool>], BooleanType, from_slice_options);
99#[cfg(feature = "dtype-u8")]
100impl_named_from!([Option<u8>], UInt8Type, from_slice_options);
101#[cfg(feature = "dtype-u16")]
102impl_named_from!([Option<u16>], UInt16Type, from_slice_options);
103impl_named_from!([Option<u32>], UInt32Type, from_slice_options);
104impl_named_from!([Option<u64>], UInt64Type, from_slice_options);
105#[cfg(feature = "dtype-u128")]
106impl_named_from!([Option<u128>], UInt128Type, from_slice_options);
107#[cfg(feature = "dtype-i8")]
108impl_named_from!([Option<i8>], Int8Type, from_slice_options);
109#[cfg(feature = "dtype-i16")]
110impl_named_from!([Option<i16>], Int16Type, from_slice_options);
111impl_named_from!([Option<i32>], Int32Type, from_slice_options);
112impl_named_from!([Option<i64>], Int64Type, from_slice_options);
113#[cfg(any(feature = "dtype-i128", feature = "dtype-decimal"))]
114impl_named_from!([Option<i128>], Int128Type, from_slice_options);
115#[cfg(feature = "dtype-f16")]
116impl_named_from!([Option<pf16>], Float16Type, from_slice_options);
117impl_named_from!([Option<f32>], Float32Type, from_slice_options);
118impl_named_from!([Option<f64>], Float64Type, from_slice_options);
119
120macro_rules! impl_named_from_range {
121 ($range:ty, $polars_type:ident) => {
122 impl NamedFrom<$range, $polars_type> for ChunkedArray<$polars_type> {
123 fn new(name: PlSmallStr, range: $range) -> Self {
124 let values = range.collect::<Vec<_>>();
125 ChunkedArray::<$polars_type>::from_vec(name, values)
126 }
127 }
128
129 impl NamedFrom<$range, $polars_type> for Series {
130 fn new(name: PlSmallStr, range: $range) -> Self {
131 ChunkedArray::new(name, range).into_series()
132 }
133 }
134 };
135}
136impl_named_from_range!(std::ops::Range<i64>, Int64Type);
137impl_named_from_range!(std::ops::Range<i32>, Int32Type);
138impl_named_from_range!(std::ops::Range<u64>, UInt64Type);
139impl_named_from_range!(std::ops::Range<u32>, UInt32Type);
140
141impl<T: AsRef<[Series]>> NamedFrom<T, ListType> for Series {
142 fn new(name: PlSmallStr, s: T) -> Self {
143 let series_slice = s.as_ref();
144 let list_cap = series_slice.len();
145
146 if series_slice.is_empty() {
147 return Series::new_empty(name, &DataType::Null);
148 }
149
150 let dt = series_slice[0].dtype();
151
152 let values_cap = series_slice.iter().fold(0, |acc, s| acc + s.len());
153
154 let mut builder = get_list_builder(dt, values_cap, list_cap, name);
155 for series in series_slice {
156 builder.append_series(series).unwrap();
157 }
158 builder.finish().into_series()
159 }
160}
161
162impl<T: AsRef<[Option<Series>]>> NamedFrom<T, [Option<Series>]> for Series {
163 fn new(name: PlSmallStr, s: T) -> Self {
164 let series_slice = s.as_ref();
165 let values_cap = series_slice.iter().fold(0, |acc, opt_s| {
166 acc + opt_s.as_ref().map(|s| s.len()).unwrap_or(0)
167 });
168 let dt = match series_slice.iter().filter_map(|opt| opt.as_ref()).next() {
169 Some(series) => series.dtype(),
170 None => &DataType::Null,
171 };
172
173 let mut builder = get_list_builder(dt, values_cap, series_slice.len(), name);
174 for series in series_slice {
175 builder.append_opt_series(series.as_ref()).unwrap();
176 }
177 builder.finish().into_series()
178 }
179}
180impl<'a, T: AsRef<[&'a str]>> NamedFrom<T, [&'a str]> for Series {
181 fn new(name: PlSmallStr, v: T) -> Self {
182 StringChunked::from_slice(name, v.as_ref()).into_series()
183 }
184}
185
186impl NamedFrom<&Series, str> for Series {
187 fn new(name: PlSmallStr, s: &Series) -> Self {
188 let mut s = s.clone();
189 s.rename(name);
190 s
191 }
192}
193
194impl<'a, T: AsRef<[&'a str]>> NamedFrom<T, [&'a str]> for StringChunked {
195 fn new(name: PlSmallStr, v: T) -> Self {
196 StringChunked::from_slice(name, v.as_ref())
197 }
198}
199
200impl<'a, T: AsRef<[Option<&'a str>]>> NamedFrom<T, [Option<&'a str>]> for Series {
201 fn new(name: PlSmallStr, v: T) -> Self {
202 StringChunked::from_slice_options(name, v.as_ref()).into_series()
203 }
204}
205
206impl<'a, T: AsRef<[Option<&'a str>]>> NamedFrom<T, [Option<&'a str>]> for StringChunked {
207 fn new(name: PlSmallStr, v: T) -> Self {
208 StringChunked::from_slice_options(name, v.as_ref())
209 }
210}
211
212impl<'a, T: AsRef<[Cow<'a, str>]>> NamedFrom<T, [Cow<'a, str>]> for Series {
213 fn new(name: PlSmallStr, v: T) -> Self {
214 StringChunked::from_iter_values(name, v.as_ref().iter().map(|value| value.as_ref()))
215 .into_series()
216 }
217}
218
219impl<'a, T: AsRef<[Cow<'a, str>]>> NamedFrom<T, [Cow<'a, str>]> for StringChunked {
220 fn new(name: PlSmallStr, v: T) -> Self {
221 StringChunked::from_iter_values(name, v.as_ref().iter().map(|value| value.as_ref()))
222 }
223}
224
225impl<'a, T: AsRef<[Option<Cow<'a, str>>]>> NamedFrom<T, [Option<Cow<'a, str>>]> for Series {
226 fn new(name: PlSmallStr, v: T) -> Self {
227 StringChunked::new(name, v).into_series()
228 }
229}
230
231impl<'a, T: AsRef<[Option<Cow<'a, str>>]>> NamedFrom<T, [Option<Cow<'a, str>>]> for StringChunked {
232 fn new(name: PlSmallStr, v: T) -> Self {
233 StringChunked::from_iter_options(
234 name,
235 v.as_ref()
236 .iter()
237 .map(|opt| opt.as_ref().map(|value| value.as_ref())),
238 )
239 }
240}
241
242impl<'a, T: AsRef<[&'a [u8]]>> NamedFrom<T, [&'a [u8]]> for Series {
243 fn new(name: PlSmallStr, v: T) -> Self {
244 BinaryChunked::from_slice(name, v.as_ref()).into_series()
245 }
246}
247
248impl<'a, T: AsRef<[&'a [u8]]>> NamedFrom<T, [&'a [u8]]> for BinaryChunked {
249 fn new(name: PlSmallStr, v: T) -> Self {
250 BinaryChunked::from_slice(name, v.as_ref())
251 }
252}
253
254impl<'a, T: AsRef<[Option<&'a [u8]>]>> NamedFrom<T, [Option<&'a [u8]>]> for Series {
255 fn new(name: PlSmallStr, v: T) -> Self {
256 BinaryChunked::from_slice_options(name, v.as_ref()).into_series()
257 }
258}
259
260impl<'a, T: AsRef<[Option<&'a [u8]>]>> NamedFrom<T, [Option<&'a [u8]>]> for BinaryChunked {
261 fn new(name: PlSmallStr, v: T) -> Self {
262 BinaryChunked::from_slice_options(name, v.as_ref())
263 }
264}
265
266impl<'a, T: AsRef<[Cow<'a, [u8]>]>> NamedFrom<T, [Cow<'a, [u8]>]> for Series {
267 fn new(name: PlSmallStr, v: T) -> Self {
268 BinaryChunked::from_iter_values(name, v.as_ref().iter().map(|value| value.as_ref()))
269 .into_series()
270 }
271}
272
273impl<'a, T: AsRef<[Cow<'a, [u8]>]>> NamedFrom<T, [Cow<'a, [u8]>]> for BinaryChunked {
274 fn new(name: PlSmallStr, v: T) -> Self {
275 BinaryChunked::from_iter_values(name, v.as_ref().iter().map(|value| value.as_ref()))
276 }
277}
278
279impl<'a, T: AsRef<[Option<Cow<'a, [u8]>>]>> NamedFrom<T, [Option<Cow<'a, [u8]>>]> for Series {
280 fn new(name: PlSmallStr, v: T) -> Self {
281 BinaryChunked::new(name, v).into_series()
282 }
283}
284
285impl<'a, T: AsRef<[Option<Cow<'a, [u8]>>]>> NamedFrom<T, [Option<Cow<'a, [u8]>>]>
286 for BinaryChunked
287{
288 fn new(name: PlSmallStr, v: T) -> Self {
289 BinaryChunked::from_iter_options(
290 name,
291 v.as_ref()
292 .iter()
293 .map(|opt| opt.as_ref().map(|value| value.as_ref())),
294 )
295 }
296}
297
298#[cfg(feature = "dtype-date")]
299impl<T: AsRef<[NaiveDate]>> NamedFrom<T, [NaiveDate]> for DateChunked {
300 fn new(name: PlSmallStr, v: T) -> Self {
301 DateChunked::from_naive_date(name, v.as_ref().iter().copied())
302 }
303}
304
305#[cfg(feature = "dtype-date")]
306impl<T: AsRef<[NaiveDate]>> NamedFrom<T, [NaiveDate]> for Series {
307 fn new(name: PlSmallStr, v: T) -> Self {
308 DateChunked::new(name, v).into_series()
309 }
310}
311
312#[cfg(feature = "dtype-date")]
313impl<T: AsRef<[Option<NaiveDate>]>> NamedFrom<T, [Option<NaiveDate>]> for DateChunked {
314 fn new(name: PlSmallStr, v: T) -> Self {
315 DateChunked::from_naive_date_options(name, v.as_ref().iter().copied())
316 }
317}
318
319#[cfg(feature = "dtype-date")]
320impl<T: AsRef<[Option<NaiveDate>]>> NamedFrom<T, [Option<NaiveDate>]> for Series {
321 fn new(name: PlSmallStr, v: T) -> Self {
322 DateChunked::new(name, v).into_series()
323 }
324}
325
326#[cfg(feature = "dtype-datetime")]
327impl<T: AsRef<[NaiveDateTime]>> NamedFrom<T, [NaiveDateTime]> for DatetimeChunked {
328 fn new(name: PlSmallStr, v: T) -> Self {
329 DatetimeChunked::from_naive_datetime(
330 name,
331 v.as_ref().iter().copied(),
332 TimeUnit::Milliseconds,
333 )
334 }
335}
336
337#[cfg(feature = "dtype-datetime")]
338impl<T: AsRef<[NaiveDateTime]>> NamedFrom<T, [NaiveDateTime]> for Series {
339 fn new(name: PlSmallStr, v: T) -> Self {
340 DatetimeChunked::new(name, v).into_series()
341 }
342}
343
344#[cfg(feature = "dtype-datetime")]
345impl<T: AsRef<[Option<NaiveDateTime>]>> NamedFrom<T, [Option<NaiveDateTime>]> for DatetimeChunked {
346 fn new(name: PlSmallStr, v: T) -> Self {
347 DatetimeChunked::from_naive_datetime_options(
348 name,
349 v.as_ref().iter().copied(),
350 TimeUnit::Milliseconds,
351 )
352 }
353}
354
355#[cfg(feature = "dtype-datetime")]
356impl<T: AsRef<[Option<NaiveDateTime>]>> NamedFrom<T, [Option<NaiveDateTime>]> for Series {
357 fn new(name: PlSmallStr, v: T) -> Self {
358 DatetimeChunked::new(name, v).into_series()
359 }
360}
361
362#[cfg(feature = "dtype-duration")]
363impl<T: AsRef<[ChronoDuration]>> NamedFrom<T, [ChronoDuration]> for DurationChunked {
364 fn new(name: PlSmallStr, v: T) -> Self {
365 DurationChunked::from_duration(name, v.as_ref().iter().copied(), TimeUnit::Nanoseconds)
366 }
367}
368
369#[cfg(feature = "dtype-duration")]
370impl<T: AsRef<[ChronoDuration]>> NamedFrom<T, [ChronoDuration]> for Series {
371 fn new(name: PlSmallStr, v: T) -> Self {
372 DurationChunked::new(name, v).into_series()
373 }
374}
375
376#[cfg(feature = "dtype-duration")]
377impl<T: AsRef<[Option<ChronoDuration>]>> NamedFrom<T, [Option<ChronoDuration>]>
378 for DurationChunked
379{
380 fn new(name: PlSmallStr, v: T) -> Self {
381 DurationChunked::from_duration_options(
382 name,
383 v.as_ref().iter().copied(),
384 TimeUnit::Nanoseconds,
385 )
386 }
387}
388
389#[cfg(feature = "dtype-duration")]
390impl<T: AsRef<[Option<ChronoDuration>]>> NamedFrom<T, [Option<ChronoDuration>]> for Series {
391 fn new(name: PlSmallStr, v: T) -> Self {
392 DurationChunked::new(name, v).into_series()
393 }
394}
395
396#[cfg(feature = "dtype-time")]
397impl<T: AsRef<[NaiveTime]>> NamedFrom<T, [NaiveTime]> for TimeChunked {
398 fn new(name: PlSmallStr, v: T) -> Self {
399 TimeChunked::from_naive_time(name, v.as_ref().iter().copied())
400 }
401}
402
403#[cfg(feature = "dtype-time")]
404impl<T: AsRef<[NaiveTime]>> NamedFrom<T, [NaiveTime]> for Series {
405 fn new(name: PlSmallStr, v: T) -> Self {
406 TimeChunked::new(name, v).into_series()
407 }
408}
409
410#[cfg(feature = "dtype-time")]
411impl<T: AsRef<[Option<NaiveTime>]>> NamedFrom<T, [Option<NaiveTime>]> for TimeChunked {
412 fn new(name: PlSmallStr, v: T) -> Self {
413 TimeChunked::from_naive_time_options(name, v.as_ref().iter().copied())
414 }
415}
416
417#[cfg(feature = "dtype-time")]
418impl<T: AsRef<[Option<NaiveTime>]>> NamedFrom<T, [Option<NaiveTime>]> for Series {
419 fn new(name: PlSmallStr, v: T) -> Self {
420 TimeChunked::new(name, v).into_series()
421 }
422}
423
424#[cfg(feature = "object")]
425impl<T: PolarsObject> NamedFrom<&[T], &[T]> for ObjectChunked<T> {
426 fn new(name: PlSmallStr, v: &[T]) -> Self {
427 ObjectChunked::from_slice(name, v)
428 }
429}
430
431#[cfg(feature = "object")]
432impl<T: PolarsObject, S: AsRef<[Option<T>]>> NamedFrom<S, [Option<T>]> for ObjectChunked<T> {
433 fn new(name: PlSmallStr, v: S) -> Self {
434 ObjectChunked::from_slice_options(name, v.as_ref())
435 }
436}
437
438impl<T: PolarsNumericType> ChunkedArray<T> {
439 pub fn new_vec(name: PlSmallStr, v: Vec<T::Native>) -> Self {
442 ChunkedArray::from_vec(name, v)
443 }
444}
445
446impl<T: IntoSeries> NamedFrom<T, T> for Series {
448 fn new(name: PlSmallStr, t: T) -> Self {
449 let mut s = t.into_series();
450 s.rename(name);
451 s
452 }
453}
454
455#[cfg(test)]
456mod test {
457 use super::*;
458
459 #[cfg(all(
460 feature = "dtype-datetime",
461 feature = "dtype-duration",
462 feature = "dtype-date",
463 feature = "dtype-time"
464 ))]
465 #[test]
466 fn test_temporal_df_construction() {
467 let _df = df![
469 "date" => [NaiveDate::from_ymd_opt(2021, 1, 1).unwrap()],
470 "datetime" => [NaiveDate::from_ymd_opt(2021, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap()],
471 "optional_date" => [Some(NaiveDate::from_ymd_opt(2021, 1, 1).unwrap())],
472 "optional_datetime" => [Some(NaiveDate::from_ymd_opt(2021, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap())],
473 "time" => [NaiveTime::from_hms_opt(23, 23, 23).unwrap()],
474 "optional_time" => [Some(NaiveTime::from_hms_opt(23, 23, 23).unwrap())],
475 "duration" => [ChronoDuration::from_std(std::time::Duration::from_secs(10)).unwrap()],
476 "optional_duration" => [Some(ChronoDuration::from_std(std::time::Duration::from_secs(10)).unwrap())],
477 ].unwrap();
478 }
479
480 #[test]
481 fn build_series_from_empty_series_vec() {
482 let empty_series = Series::new("test".into(), Vec::<Series>::new());
483 assert_eq!(empty_series.len(), 0);
484 assert_eq!(*empty_series.dtype(), DataType::Null);
485 assert_eq!(empty_series.name().as_str(), "test");
486 }
487}