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