rigetti_pyo3/to_python/
mod.rs

1// Copyright 2022 Rigetti Computing
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Unifying conversion traits from Rust data to Python.
16
17use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
18use std::hash::BuildHasher;
19
20use pyo3::conversion::IntoPy;
21
22use pyo3::types::{
23    PyBool, PyByteArray, PyBytes, PyDict, PyFloat, PyFrozenSet, PyList, PyLong, PySet, PyString,
24};
25
26#[cfg(feature = "time")]
27use pyo3::{
28    exceptions::PyValueError,
29    types::{PyDate, PyDateTime, PyDelta, PyTime, PyTzInfo},
30};
31
32use pyo3::{Py, PyAny, PyResult, Python, ToPyObject};
33
34#[cfg(feature = "complex")]
35/// Conversion traits for complex numbers.
36mod complex;
37
38#[cfg(feature = "time")]
39use crate::datetime::DateTime;
40#[cfg(feature = "time")]
41use pyo3::types::PyTuple;
42#[cfg(feature = "time")]
43use time::{Date, Duration, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset};
44
45#[cfg(feature = "indexmap")]
46/// Conversion traits for [`indexmap`].
47mod indexmap;
48
49/// Convert from a Rust type into a Python type.
50pub trait ToPython<P: ToPyObject> {
51    /// Convert from Rust `self` into a Python type.
52    ///
53    /// # Errors
54    ///
55    /// Any failure while converting to Python.
56    fn to_python(&self, py: Python) -> PyResult<P>;
57}
58
59impl<T, P> ToPython<P> for &Box<T>
60where
61    T: ToPython<P>,
62    P: ToPyObject,
63{
64    fn to_python(&self, py: Python) -> PyResult<P> {
65        T::to_python(self, py)
66    }
67}
68
69impl<T, P> ToPython<P> for Box<T>
70where
71    T: ToPython<P>,
72    P: ToPyObject,
73{
74    fn to_python(&self, py: Python) -> PyResult<P> {
75        T::to_python(self, py)
76    }
77}
78
79/// Provides a generic implementation of [`ToPython`] for heterogenous tuples of types that themselves implement
80/// [`ToPython`].
81macro_rules! impl_to_python_for_tuple {
82    ($($idx:tt $t:tt $p:tt),+) => {
83        impl<$($t,)+ $($p,)+> ToPython<($($p,)+)> for ($($t,)+)
84        where
85            $($t: ToPython<$p>, $p: ToPyObject,)+
86
87        {
88            fn to_python(&self, py: Python) -> PyResult<($($p,)+)> {
89                Ok(($(
90                    $t :: to_python(&self.$idx, py)?,
91                )+))
92            }
93        }
94    };
95}
96
97// Implement [`ToPython`] for tuples of length 1 to 12, 12 being the maximum arity that [`pyo3::ToPyObject`]
98// is implemented for.
99impl_to_python_for_tuple!(0 T0 P0);
100impl_to_python_for_tuple!(0 T0 P0, 1 T1 P1);
101impl_to_python_for_tuple!(0 T0 P0, 1 T1 P1, 2 T2 P2);
102impl_to_python_for_tuple!(0 T0 P0, 1 T1 P1, 2 T2 P2, 3 T3 P3);
103impl_to_python_for_tuple!(0 T0 P0, 1 T1 P1, 2 T2 P2, 3 T3 P3, 4 T4 P4);
104impl_to_python_for_tuple!(0 T0 P0, 1 T1 P1, 2 T2 P2, 3 T3 P3, 4 T4 P4, 5 T5 P5);
105impl_to_python_for_tuple!(0 T0 P0, 1 T1 P1, 2 T2 P2, 3 T3 P3, 4 T4 P4, 5 T5 P5, 6 T6 P6);
106impl_to_python_for_tuple!(0 T0 P0, 1 T1 P1, 2 T2 P2, 3 T3 P3, 4 T4 P4, 5 T5 P5, 6 T6 P6, 7 T7 P7);
107impl_to_python_for_tuple!(0 T0 P0, 1 T1 P1, 2 T2 P2, 3 T3 P3, 4 T4 P4, 5 T5 P5, 6 T6 P6, 7 T7 P7, 8 T8 P8);
108impl_to_python_for_tuple!(0 T0 P0, 1 T1 P1, 2 T2 P2, 3 T3 P3, 4 T4 P4, 5 T5 P5, 6 T6 P6, 7 T7 P7, 8 T8 P8, 9 T9 P9);
109impl_to_python_for_tuple!(0 T0 P0, 1 T1 P1, 2 T2 P2, 3 T3 P3, 4 T4 P4, 5 T5 P5, 6 T6 P6, 7 T7 P7, 8 T8 P8, 9 T9 P9, 10 T10 P10);
110impl_to_python_for_tuple!(0 T0 P0, 1 T1 P1, 2 T2 P2, 3 T3 P3, 4 T4 P4, 5 T5 P5, 6 T6 P6, 7 T7 P7, 8 T8 P8, 9 T9 P9, 10 T10 P10, 11 T11 P11);
111
112/// Implement [`ToPython`] once for the given Rust type. Will implement for a reference to the type
113/// if a lifetime is provided.
114#[macro_export]
115macro_rules! private_impl_to_python_for {
116    (&$($lt: lifetime)? $self: ident, $py: ident, $rs_type: ty => $py_type: ty $convert: block) => {
117        #[allow(clippy::use_self)]
118        impl$(<$lt>)? $crate::ToPython<$py_type> for $(&$lt)? $rs_type {
119            fn to_python(&$self, $py: $crate::pyo3::Python<'_>) -> $crate::pyo3::PyResult<$py_type> {
120                $convert
121            }
122        }
123    }
124}
125
126/// Implement [`ToPython`] on the given Rust type and a reference to it.
127#[macro_export]
128macro_rules! private_impl_to_python_with_reference {
129    (&$self: ident, $py: ident, $rs_type: ty => $py_type: ty $convert: block) => {
130        $crate::private_impl_to_python_for!(&$self, $py, $rs_type => $py_type $convert);
131        $crate::private_impl_to_python_for!(&'a $self, $py, $rs_type => $py_type {
132            <$rs_type as $crate::ToPython<$py_type>>::to_python(*$self, $py)
133        });
134    };
135}
136
137/// Implement [`ToPython<Py<PyAny>>`] for a type using its implementation for `ToPython<P>` where `P: ToPyObject`.
138#[macro_export]
139macro_rules! private_impl_to_python_pyany {
140    ($rs_type: ty => $py_type: ty) => {
141        $crate::private_impl_to_python_with_reference!(&self, py, $rs_type => $crate::pyo3::Py<$crate::pyo3::PyAny> {
142            $crate::ToPython::<$py_type>::to_python(self, py).map(|item| $crate::pyo3::ToPyObject::to_object(&item, py))
143        });
144    }
145}
146pub(crate) use private_impl_to_python_pyany;
147
148/// Implements [`IntoPython`] by converting to `Py<PyAny>` and extracting `Py<T>` from that.
149///
150/// For types like integers, this is only way to convert.
151macro_rules! impl_for_primitive {
152    ($rs_type: ty => $py_type: ty) => {
153        private_impl_to_python_with_reference!(&self, py, $rs_type => $py_type {
154            // No way to convert except via ToPyObject and downcasting.
155            self.into_py(py).extract(py)
156        });
157    };
158}
159
160/// Implement `ToPython<Self>` for a given type.
161#[macro_export]
162macro_rules! impl_for_self {
163    ($type: ty) => {
164        $crate::private_impl_to_python_with_reference!(&self, _py, $type => $type {
165            Ok(self.clone())
166        });
167        $crate::private_impl_to_python_pyany!($type => $type);
168    }
169}
170pub(crate) use impl_for_self;
171
172// ============ Begin Implementations ==============
173
174// ==== Bool ====
175
176impl_for_self!(bool);
177impl_for_self!(Py<PyBool>);
178
179private_impl_to_python_with_reference!(&self, py, bool => Py<PyBool> {
180    Ok(PyBool::new(py, *self).into_py(py))
181});
182
183// ==== ByteArray ====
184
185impl_for_self!(Py<PyByteArray>);
186
187private_impl_to_python_with_reference!(&self, py, [u8] => Py<PyByteArray> {
188    Ok(PyByteArray::new(py, self).into_py(py))
189});
190
191private_impl_to_python_with_reference!(&self, py, Vec<u8> => Py<PyByteArray> {
192    self.as_slice().to_python(py)
193});
194
195// ==== Bytes ====
196
197impl_for_self!(Py<PyBytes>);
198
199private_impl_to_python_with_reference!(&self, py, [u8] => Py<PyBytes> {
200    Ok(PyBytes::new(py, self).into_py(py))
201});
202
203private_impl_to_python_with_reference!(&self, py, Vec<u8> => Py<PyBytes> {
204    self.as_slice().to_python(py)
205});
206
207// ==== Date ====
208
209#[cfg(feature = "time")]
210impl_for_self!(Py<PyDate>);
211
212#[cfg(feature = "time")]
213private_impl_to_python_with_reference!(&self, py, Date => Py<PyDate> {
214    let year: i32 = self.year();
215    let month: u8 = self.month().into();
216    let day: u8 = self.day();
217    PyDate::new(py, year, month, day).map(|date| date.into_py(py))
218});
219
220#[cfg(feature = "time")]
221private_impl_to_python_pyany!(Date => Py<PyDate>);
222
223// ==== DateTime ====
224
225#[cfg(feature = "time")]
226impl_for_self!(Py<PyDateTime>);
227
228#[cfg(feature = "time")]
229private_impl_to_python_with_reference!(&self, py, DateTime => Py<PyDateTime> {
230    match self {
231        Self::Primitive(datetime) => datetime.to_python(py),
232        Self::Offset(datetime) => datetime.to_python(py),
233    }
234});
235
236#[cfg(feature = "time")]
237private_impl_to_python_pyany!(DateTime => Py<PyDateTime>);
238
239#[cfg(feature = "time")]
240private_impl_to_python_with_reference!(&self, py, PrimitiveDateTime => Py<PyDateTime> {
241    let date = self.date();
242    let time = self.time();
243    let year: i32 = date.year();
244    let month: u8 = date.month().into();
245    let day: u8 = date.day();
246    let hour = time.hour();
247    let minute = time.minute();
248    let second = time.second();
249    let microsecond = time.microsecond();
250    PyDateTime::new(py, year, month, day, hour, minute, second, microsecond, None).map(|dt| dt.into_py(py))
251});
252
253#[cfg(feature = "time")]
254private_impl_to_python_pyany!(PrimitiveDateTime => Py<PyDateTime>);
255
256#[cfg(feature = "time")]
257private_impl_to_python_with_reference!(&self, py, OffsetDateTime => Py<PyDateTime> {
258    let date = self.date();
259    let time = self.time();
260    let offset = self.offset();
261    let year: i32 = date.year();
262    let month: u8 = date.month().into();
263    let day: u8 = date.day();
264    let hour = time.hour();
265    let minute = time.minute();
266    let second = time.second();
267    let microsecond = time.microsecond();
268    let tzinfo: Py<PyTzInfo> = offset.to_python(py)?;
269    let tzinfo = tzinfo.as_ref(py);
270    PyDateTime::new(py, year, month, day, hour, minute, second, microsecond, Some(tzinfo)).map(|dt| dt.into_py(py))
271});
272
273#[cfg(feature = "time")]
274private_impl_to_python_pyany!(OffsetDateTime => Py<PyDateTime>);
275
276// ==== Delta ====
277
278#[cfg(feature = "time")]
279impl_for_self!(Py<PyDelta>);
280
281#[cfg(feature = "time")]
282private_impl_to_python_with_reference!(&self, py, Duration => Py<PyDelta> {
283    let days: i32 = self.whole_days().try_into().map_err(|_| {
284        PyValueError::new_err(format!("Cannot fit {} days into a 32-bit signed integer", self.whole_days()))
285    })?;
286    let seconds: i32 = self.whole_seconds().try_into().map_err(|_| {
287        PyValueError::new_err(format!("Cannot fit {} seconds into a 32-bit signed integer", self.whole_seconds()))
288    })?;
289    let microseconds:i32 = self.whole_microseconds().try_into().map_err(|_| {
290        PyValueError::new_err(format!("Cannot fit {} microseconds into a 32-bit signed integer", self.whole_microseconds()))
291    })?;
292    PyDelta::new(py, days, seconds, microseconds, true).map(|delta| delta.into_py(py))
293});
294
295#[cfg(feature = "time")]
296private_impl_to_python_pyany!(Duration => Py<PyDelta>);
297
298#[cfg(feature = "time")]
299private_impl_to_python_with_reference!(&self, py, std::time::Duration => Py<PyDelta> {
300    /// The number of seconds in a day.
301    const DAY_FACTOR: u64 = 60 * 60 * 24;
302    let microseconds = self.as_micros() % 1_000_000;
303    let seconds = self.as_secs() % DAY_FACTOR;
304    let days = self.as_secs() / DAY_FACTOR;
305
306    let microseconds: i32 = microseconds.try_into().map_err(|_| {
307        PyValueError::new_err(format!("Cannot fit {microseconds} microseconds into a 32-bit signed integer"))
308    })?;
309
310    let seconds: i32 = seconds.try_into().map_err(|_| {
311        PyValueError::new_err(format!("Cannot fit {seconds} seconds into a 32-bit signed integer"))
312    })?;
313
314    let days: i32 = days.try_into().map_err(|_| {
315        PyValueError::new_err(format!("Cannot fit {days} days into a 32-bit signed integer"))
316    })?;
317
318    PyDelta::new(py, days, seconds, microseconds, true).map(|delta| delta.into_py(py))
319});
320
321#[cfg(feature = "time")]
322private_impl_to_python_pyany!(std::time::Duration => Py<PyDelta>);
323
324// ==== Dict ====
325
326impl_for_self!(Py<PyDict>);
327
328impl<K1, K2, V1, V2, Hasher> ToPython<HashMap<K2, V2>> for &HashMap<K1, V1, Hasher>
329where
330    K1: ToPython<K2>,
331    V1: ToPython<V2>,
332    K2: ToPyObject + Eq + std::hash::Hash,
333    V2: ToPyObject,
334{
335    fn to_python(&self, py: Python) -> PyResult<HashMap<K2, V2>> {
336        self.iter()
337            .map(|(key, val)| {
338                let key = key.to_python(py)?;
339                let val = val.to_python(py)?;
340                Ok((key, val))
341            })
342            .collect::<Result<_, _>>()
343    }
344}
345
346impl<K, V, Hasher> ToPython<Py<PyDict>> for &HashMap<K, V, Hasher>
347where
348    K: ToPython<Py<PyAny>> + std::fmt::Debug,
349    V: ToPython<Py<PyAny>>,
350{
351    fn to_python(&self, py: Python) -> PyResult<Py<PyDict>> {
352        let dict = PyDict::new(py);
353        for (key, val) in *self {
354            let pykey = key.to_python(py)?;
355            let pyval = val.to_python(py)?;
356            dict.set_item(pykey, pyval)?;
357        }
358        Ok(dict.into_py(py))
359    }
360}
361
362impl<K, V, Hasher> ToPython<Py<PyAny>> for &HashMap<K, V, Hasher>
363where
364    K: ToPython<Py<PyAny>> + std::fmt::Debug,
365    V: ToPython<Py<PyAny>>,
366{
367    fn to_python(&self, py: Python) -> PyResult<Py<PyAny>> {
368        <Self as ToPython<Py<PyDict>>>::to_python(self, py).map(|dict| dict.into_py(py))
369    }
370}
371
372impl<K1, K2, V1, V2, Hasher> ToPython<HashMap<K2, V2>> for HashMap<K1, V1, Hasher>
373where
374    K1: ToPython<K2>,
375    V1: ToPython<V2>,
376    K2: ToPyObject + Eq + std::hash::Hash,
377    V2: ToPyObject,
378{
379    fn to_python(&self, py: Python) -> PyResult<HashMap<K2, V2>> {
380        <&Self as ToPython<HashMap<K2, V2>>>::to_python(&self, py)
381    }
382}
383
384impl<K, V, Hasher> ToPython<Py<PyDict>> for HashMap<K, V, Hasher>
385where
386    K: ToPython<Py<PyAny>> + std::fmt::Debug,
387    V: ToPython<Py<PyAny>>,
388{
389    fn to_python(&self, py: Python) -> PyResult<Py<PyDict>> {
390        <&Self as ToPython<Py<PyDict>>>::to_python(&self, py)
391    }
392}
393
394impl<K, V, Hasher> ToPython<Py<PyAny>> for HashMap<K, V, Hasher>
395where
396    K: ToPython<Py<PyAny>> + std::fmt::Debug,
397    V: ToPython<Py<PyAny>>,
398{
399    fn to_python(&self, py: Python) -> PyResult<Py<PyAny>> {
400        <Self as ToPython<Py<PyDict>>>::to_python(self, py).map(|dict| dict.into_py(py))
401    }
402}
403
404impl<K1, K2, V1, V2> ToPython<BTreeMap<K2, V2>> for &BTreeMap<K1, V1>
405where
406    K1: ToPython<K2> + std::fmt::Debug,
407    V1: ToPython<V2>,
408    K2: ToPyObject + Ord,
409    V2: ToPyObject,
410{
411    fn to_python(&self, py: Python) -> PyResult<BTreeMap<K2, V2>> {
412        let mut map = BTreeMap::new();
413        for (key, val) in *self {
414            let pykey = key.to_python(py)?;
415            let pyval = val.to_python(py)?;
416            map.insert(pykey, pyval);
417        }
418        Ok(map)
419    }
420}
421
422impl<K, V> ToPython<Py<PyDict>> for &BTreeMap<K, V>
423where
424    K: ToPython<Py<PyAny>> + std::fmt::Debug,
425    V: ToPython<Py<PyAny>>,
426{
427    fn to_python(&self, py: Python) -> PyResult<Py<PyDict>> {
428        let dict = PyDict::new(py);
429        for (key, val) in *self {
430            let pykey = key.to_python(py)?;
431            let pyval = val.to_python(py)?;
432            dict.set_item(pykey, pyval)?;
433        }
434        Ok(dict.into_py(py))
435    }
436}
437
438impl<K, V> ToPython<Py<PyAny>> for &BTreeMap<K, V>
439where
440    K: ToPython<Py<PyAny>> + std::fmt::Debug,
441    V: ToPython<Py<PyAny>>,
442{
443    fn to_python(&self, py: Python) -> PyResult<Py<PyAny>> {
444        <Self as ToPython<Py<PyDict>>>::to_python(self, py).map(|dict| dict.into_py(py))
445    }
446}
447
448impl<K1, K2, V1, V2> ToPython<BTreeMap<K2, V2>> for BTreeMap<K1, V1>
449where
450    K1: ToPython<K2> + std::fmt::Debug,
451    V1: ToPython<V2>,
452    K2: ToPyObject + Ord,
453    V2: ToPyObject,
454{
455    fn to_python(&self, py: Python) -> PyResult<BTreeMap<K2, V2>> {
456        <&Self as ToPython<BTreeMap<K2, V2>>>::to_python(&self, py)
457    }
458}
459
460impl<K, V> ToPython<Py<PyDict>> for BTreeMap<K, V>
461where
462    K: ToPython<Py<PyAny>> + std::fmt::Debug,
463    V: ToPython<Py<PyAny>>,
464{
465    fn to_python(&self, py: Python) -> PyResult<Py<PyDict>> {
466        <&Self as ToPython<Py<PyDict>>>::to_python(&self, py)
467    }
468}
469
470impl<K, V> ToPython<Py<PyAny>> for BTreeMap<K, V>
471where
472    K: ToPython<Py<PyAny>> + std::fmt::Debug,
473    V: ToPython<Py<PyAny>>,
474{
475    fn to_python(&self, py: Python) -> PyResult<Py<PyAny>> {
476        <Self as ToPython<Py<PyDict>>>::to_python(self, py).map(|dict| dict.into_py(py))
477    }
478}
479
480// ==== Float ====
481
482impl_for_self!(Py<PyFloat>);
483impl_for_self!(f32);
484impl_for_self!(f64);
485
486impl_for_primitive!(f32 => Py<PyFloat>);
487impl_for_primitive!(f64 => Py<PyFloat>);
488
489// ==== FrozenSet ====
490
491impl<T, Hasher> ToPython<Py<PyFrozenSet>> for &HashSet<T, Hasher>
492where
493    T: ToPython<Py<PyAny>> + Clone,
494{
495    fn to_python(&self, py: Python) -> PyResult<Py<PyFrozenSet>> {
496        let elements = self
497            .iter()
498            .map(|item| item.to_python(py))
499            .collect::<PyResult<Vec<_>>>()?;
500        PyFrozenSet::new(py, &elements).map(|set| set.into_py(py))
501    }
502}
503
504impl<T, Hasher> ToPython<Py<PyFrozenSet>> for HashSet<T, Hasher>
505where
506    T: ToPython<Py<PyAny>> + Clone,
507{
508    fn to_python(&self, py: Python) -> PyResult<Py<PyFrozenSet>> {
509        <&Self as ToPython<Py<PyFrozenSet>>>::to_python(&self, py)
510    }
511}
512
513impl<T> ToPython<Py<PyFrozenSet>> for &BTreeSet<T>
514where
515    T: ToPython<Py<PyAny>> + Clone,
516{
517    fn to_python(&self, py: Python) -> PyResult<Py<PyFrozenSet>> {
518        let elements = self
519            .iter()
520            .map(|item| item.to_python(py))
521            .collect::<PyResult<Vec<_>>>()?;
522        PyFrozenSet::new(py, &elements).map(|set| set.into_py(py))
523    }
524}
525
526impl<T> ToPython<Py<PyFrozenSet>> for BTreeSet<T>
527where
528    T: ToPython<Py<PyAny>> + Clone,
529{
530    fn to_python(&self, py: Python) -> PyResult<Py<PyFrozenSet>> {
531        <&Self as ToPython<Py<PyFrozenSet>>>::to_python(&self, py)
532    }
533}
534
535// ==== Integer ====
536
537impl_for_self!(Py<PyLong>);
538impl_for_self!(i8);
539impl_for_self!(i16);
540impl_for_self!(i32);
541impl_for_self!(i64);
542impl_for_self!(i128);
543impl_for_self!(isize);
544impl_for_self!(u8);
545impl_for_self!(u16);
546impl_for_self!(u32);
547impl_for_self!(u64);
548impl_for_self!(u128);
549impl_for_self!(usize);
550
551impl_for_primitive!(i8 => Py<PyLong>);
552impl_for_primitive!(i16 => Py<PyLong>);
553impl_for_primitive!(i32 => Py<PyLong>);
554impl_for_primitive!(i64 => Py<PyLong>);
555impl_for_primitive!(i128 => Py<PyLong>);
556impl_for_primitive!(isize => Py<PyLong>);
557impl_for_primitive!(u8 => Py<PyLong>);
558impl_for_primitive!(u16 => Py<PyLong>);
559impl_for_primitive!(u32 => Py<PyLong>);
560impl_for_primitive!(u64 => Py<PyLong>);
561impl_for_primitive!(u128 => Py<PyLong>);
562impl_for_primitive!(usize => Py<PyLong>);
563
564// ==== Optional[T] ====
565
566impl<T, P> ToPython<Option<P>> for &Option<T>
567where
568    T: ToPython<P>,
569    P: ToPyObject,
570{
571    fn to_python(&self, py: Python) -> PyResult<Option<P>> {
572        self.as_ref().map(|inner| inner.to_python(py)).transpose()
573    }
574}
575
576impl<T, P> ToPython<Option<P>> for Option<T>
577where
578    T: ToPython<P>,
579    P: ToPyObject,
580{
581    fn to_python(&self, py: Python) -> PyResult<Option<P>> {
582        <&Self as ToPython<Option<P>>>::to_python(&self, py)
583    }
584}
585
586// ==== List ====
587
588impl_for_self!(Py<PyList>);
589
590impl<T, P> ToPython<Vec<P>> for &[T]
591where
592    T: ToPython<P> + Clone,
593    P: ToPyObject,
594{
595    fn to_python(&self, py: Python) -> PyResult<Vec<P>> {
596        self.iter()
597            .map(|item| item.to_python(py))
598            .collect::<PyResult<Vec<_>>>()
599    }
600}
601
602impl<T> ToPython<Py<PyList>> for &[T]
603where
604    T: ToPython<Py<PyAny>> + Clone,
605{
606    fn to_python(&self, py: Python) -> PyResult<Py<PyList>> {
607        let elements = self
608            .iter()
609            .map(|item| item.to_python(py))
610            .collect::<PyResult<Vec<_>>>()?;
611        Ok(PyList::new(py, elements).into_py(py))
612    }
613}
614
615impl<T> ToPython<Py<PyAny>> for &[T]
616where
617    T: ToPython<Py<PyAny>> + Clone,
618{
619    fn to_python(&self, py: Python) -> PyResult<Py<PyAny>> {
620        <Self as ToPython<Py<PyList>>>::to_python(self, py).map(|item| item.into_py(py))
621    }
622}
623
624impl<T, P> ToPython<Vec<P>> for [T]
625where
626    T: ToPython<P> + Clone,
627    P: ToPyObject,
628{
629    fn to_python(&self, py: Python) -> PyResult<Vec<P>> {
630        <&Self as ToPython<Vec<P>>>::to_python(&self, py)
631    }
632}
633
634impl<T> ToPython<Py<PyList>> for [T]
635where
636    T: ToPython<Py<PyAny>> + Clone,
637{
638    fn to_python(&self, py: Python) -> PyResult<Py<PyList>> {
639        <&Self as ToPython<Py<PyList>>>::to_python(&self, py)
640    }
641}
642
643impl<T> ToPython<Py<PyAny>> for [T]
644where
645    T: ToPython<Py<PyAny>> + Clone,
646{
647    fn to_python(&self, py: Python) -> PyResult<Py<PyAny>> {
648        <&Self as ToPython<Py<PyAny>>>::to_python(&self, py)
649    }
650}
651
652impl<T, P> ToPython<Vec<P>> for Vec<T>
653where
654    T: ToPython<P> + Clone,
655    P: ToPyObject,
656{
657    fn to_python(&self, py: Python) -> PyResult<Vec<P>> {
658        self.as_slice().to_python(py)
659    }
660}
661
662impl<T, P> ToPython<Vec<P>> for &Vec<T>
663where
664    T: ToPython<P> + Clone,
665    P: ToPyObject,
666{
667    fn to_python(&self, py: Python) -> PyResult<Vec<P>> {
668        self.as_slice().to_python(py)
669    }
670}
671
672impl<T> ToPython<Py<PyList>> for Vec<T>
673where
674    T: ToPython<Py<PyAny>> + Clone,
675{
676    fn to_python(&self, py: Python) -> PyResult<Py<PyList>> {
677        self.as_slice().to_python(py)
678    }
679}
680
681impl<T> ToPython<Py<PyList>> for &Vec<T>
682where
683    T: ToPython<Py<PyAny>> + Clone,
684{
685    fn to_python(&self, py: Python) -> PyResult<Py<PyList>> {
686        self.as_slice().to_python(py)
687    }
688}
689
690impl<T> ToPython<Py<PyAny>> for Vec<T>
691where
692    T: ToPython<Py<PyAny>> + Clone,
693{
694    fn to_python(&self, py: Python) -> PyResult<Py<PyAny>> {
695        self.as_slice().to_python(py)
696    }
697}
698
699impl<T> ToPython<Py<PyAny>> for &Vec<T>
700where
701    T: ToPython<Py<PyAny>> + Clone,
702{
703    fn to_python(&self, py: Python) -> PyResult<Py<PyAny>> {
704        self.as_slice().to_python(py)
705    }
706}
707
708// ==== Set ====
709
710impl_for_self!(Py<PySet>);
711
712impl<T, P, Hasher> ToPython<HashSet<P, Hasher>> for &HashSet<T, Hasher>
713where
714    T: ToPython<P> + Clone,
715    P: ToPyObject + std::hash::Hash + Eq,
716    Hasher: Default + BuildHasher,
717{
718    fn to_python(&self, py: Python) -> PyResult<HashSet<P, Hasher>> {
719        self.iter()
720            .map(|item| item.to_python(py))
721            .collect::<PyResult<_>>()
722    }
723}
724
725impl<T, P, Hasher> ToPython<HashSet<P, Hasher>> for HashSet<T, Hasher>
726where
727    T: ToPython<P> + Clone,
728    P: ToPyObject + std::hash::Hash + Eq,
729    Hasher: Default + BuildHasher,
730{
731    fn to_python(&self, py: Python) -> PyResult<HashSet<P, Hasher>> {
732        <&Self as ToPython<HashSet<P, Hasher>>>::to_python(&self, py)
733    }
734}
735
736impl<T, Hasher> ToPython<Py<PySet>> for &HashSet<T, Hasher>
737where
738    T: ToPython<Py<PyAny>> + Clone,
739{
740    fn to_python(&self, py: Python) -> PyResult<Py<PySet>> {
741        // Using PySet::new seems to do extra cloning, so build manually.
742        let set = PySet::empty(py)?;
743        for item in *self {
744            set.add(item.to_python(py)?)?;
745        }
746        Ok(set.into_py(py))
747    }
748}
749
750impl<T, Hasher> ToPython<Py<PySet>> for HashSet<T, Hasher>
751where
752    T: ToPython<Py<PyAny>> + Clone,
753{
754    fn to_python(&self, py: Python) -> PyResult<Py<PySet>> {
755        <&Self as ToPython<Py<PySet>>>::to_python(&self, py)
756    }
757}
758
759impl<T, Hasher> ToPython<Py<PyAny>> for &HashSet<T, Hasher>
760where
761    T: ToPython<Py<PyAny>> + Clone,
762{
763    fn to_python(&self, py: Python) -> PyResult<Py<PyAny>> {
764        <Self as ToPython<Py<PySet>>>::to_python(self, py).map(|item| item.into_py(py))
765    }
766}
767
768impl<T, Hasher> ToPython<Py<PyAny>> for HashSet<T, Hasher>
769where
770    T: ToPython<Py<PyAny>> + Clone,
771{
772    fn to_python(&self, py: Python) -> PyResult<Py<PyAny>> {
773        <&Self as ToPython<Py<PyAny>>>::to_python(&self, py)
774    }
775}
776
777impl<T, P> ToPython<BTreeSet<P>> for &BTreeSet<T>
778where
779    T: ToPython<P> + Clone,
780    // Hash is required for the ToPyObject impl
781    P: ToPyObject + Ord + std::hash::Hash,
782{
783    fn to_python(&self, py: Python) -> PyResult<BTreeSet<P>> {
784        self.iter()
785            .map(|item| item.to_python(py))
786            .collect::<PyResult<_>>()
787    }
788}
789
790impl<T, P> ToPython<BTreeSet<P>> for BTreeSet<T>
791where
792    T: ToPython<P> + Clone,
793    P: ToPyObject + Ord + std::hash::Hash,
794{
795    fn to_python(&self, py: Python) -> PyResult<BTreeSet<P>> {
796        <&Self as ToPython<BTreeSet<P>>>::to_python(&self, py)
797    }
798}
799
800impl<T> ToPython<Py<PySet>> for &BTreeSet<T>
801where
802    T: ToPython<Py<PyAny>> + Clone,
803{
804    fn to_python(&self, py: Python) -> PyResult<Py<PySet>> {
805        // Using PySet::new seems to do extra cloning, so build manually.
806        let set = PySet::empty(py)?;
807        for item in *self {
808            set.add(item.to_python(py)?)?;
809        }
810        Ok(set.into_py(py))
811    }
812}
813
814impl<T> ToPython<Py<PySet>> for BTreeSet<T>
815where
816    T: ToPython<Py<PyAny>> + Clone,
817{
818    fn to_python(&self, py: Python) -> PyResult<Py<PySet>> {
819        <&Self as ToPython<Py<PySet>>>::to_python(&self, py)
820    }
821}
822
823impl<T> ToPython<Py<PyAny>> for &BTreeSet<T>
824where
825    T: ToPython<Py<PyAny>> + Clone,
826{
827    fn to_python(&self, py: Python) -> PyResult<Py<PyAny>> {
828        <Self as ToPython<Py<PySet>>>::to_python(self, py).map(|item| item.into_py(py))
829    }
830}
831
832impl<T> ToPython<Py<PyAny>> for BTreeSet<T>
833where
834    T: ToPython<Py<PyAny>> + Clone,
835{
836    fn to_python(&self, py: Python) -> PyResult<Py<PyAny>> {
837        <&Self as ToPython<Py<PyAny>>>::to_python(&self, py)
838    }
839}
840
841// ==== String ====
842
843impl_for_self!(Py<PyString>);
844impl_for_self!(String);
845
846private_impl_to_python_with_reference!(&self, py, str => Py<PyString> {
847    Ok(PyString::new(py, self).into_py(py))
848});
849
850private_impl_to_python_pyany!(str => Py<PyString>);
851
852private_impl_to_python_with_reference!(&self, py, String => Py<PyString> {
853    self.as_str().to_python(py)
854});
855
856// ==== Time ====
857
858#[cfg(feature = "time")]
859impl_for_self!(Py<PyTime>);
860
861#[cfg(feature = "time")]
862private_impl_to_python_with_reference!(&self, py, (Time, Option<UtcOffset>) => Py<PyTime> {
863    let (time, offset) = self;
864    let hour = time.hour();
865    let minute = time.minute();
866    let second = time.second();
867    let microsecond = time.microsecond();
868    let tzinfo: Option<Py<PyTzInfo>> = offset.map(|offset| {
869        offset.to_python(py)
870    }).transpose()?;
871    let tzinfo = tzinfo.as_ref().map(|tzinfo| tzinfo.as_ref(py));
872    PyTime::new(py, hour, minute, second, microsecond, tzinfo).map(|time| time.into_py(py))
873});
874
875#[cfg(feature = "time")]
876private_impl_to_python_pyany!((Time, Option<UtcOffset>) => Py<PyTime>);
877
878// ==== TzInfo ====
879
880#[cfg(feature = "time")]
881impl_for_self!(Py<PyTzInfo>);
882
883#[cfg(feature = "time")]
884private_impl_to_python_with_reference!(&self, py, UtcOffset => Py<PyTzInfo> {
885    let datetime = py.import("datetime")?;
886    let timezone = datetime.getattr("timezone")?;
887    let (hour, minute, second) = self.as_hms();
888    let seconds = i64::from(second) + 60 * (i64::from(minute) + (60 * i64::from(hour)));
889    let duration = Duration::new(seconds, 0);
890    let delta: Py<PyDelta> = duration.to_python(py)?;
891    let args = (delta,).to_object(py);
892    let args: &PyTuple = args.extract(py)?;
893    let tzinfo = timezone.call1(args)?;
894    tzinfo.extract()
895});
896
897#[cfg(feature = "time")]
898private_impl_to_python_pyany!(UtcOffset => Py<PyTzInfo>);
899
900// ============ End Implementations ==============