pyo3/impl_/
wrap.rs

1use std::{convert::Infallible, marker::PhantomData, ops::Deref};
2
3use crate::{
4    ffi, types::PyNone, Bound, IntoPyObject, IntoPyObjectExt, Py, PyAny, PyResult, Python,
5};
6
7/// Used to wrap values in `Option<T>` for default arguments.
8pub trait SomeWrap<T> {
9    fn wrap(self) -> Option<T>;
10}
11
12impl<T> SomeWrap<T> for T {
13    fn wrap(self) -> Option<T> {
14        Some(self)
15    }
16}
17
18impl<T> SomeWrap<T> for Option<T> {
19    fn wrap(self) -> Self {
20        self
21    }
22}
23
24// Hierarchy of conversions used in the `IntoPy` implementation
25pub struct Converter<T>(EmptyTupleConverter<T>);
26pub struct EmptyTupleConverter<T>(IntoPyObjectConverter<T>);
27pub struct IntoPyObjectConverter<T>(IntoPyConverter<T>);
28pub struct IntoPyConverter<T>(UnknownReturnResultType<T>);
29pub struct UnknownReturnResultType<T>(UnknownReturnType<T>);
30pub struct UnknownReturnType<T>(PhantomData<T>);
31
32pub fn converter<T>(_: &T) -> Converter<T> {
33    Converter(EmptyTupleConverter(IntoPyObjectConverter(IntoPyConverter(
34        UnknownReturnResultType(UnknownReturnType(PhantomData)),
35    ))))
36}
37
38impl<T> Deref for Converter<T> {
39    type Target = EmptyTupleConverter<T>;
40    fn deref(&self) -> &Self::Target {
41        &self.0
42    }
43}
44
45impl<T> Deref for EmptyTupleConverter<T> {
46    type Target = IntoPyObjectConverter<T>;
47    fn deref(&self) -> &Self::Target {
48        &self.0
49    }
50}
51
52impl<T> Deref for IntoPyObjectConverter<T> {
53    type Target = IntoPyConverter<T>;
54    fn deref(&self) -> &Self::Target {
55        &self.0
56    }
57}
58
59impl<T> Deref for IntoPyConverter<T> {
60    type Target = UnknownReturnResultType<T>;
61    fn deref(&self) -> &Self::Target {
62        &self.0
63    }
64}
65
66impl<T> Deref for UnknownReturnResultType<T> {
67    type Target = UnknownReturnType<T>;
68    fn deref(&self) -> &Self::Target {
69        &self.0
70    }
71}
72
73impl EmptyTupleConverter<PyResult<()>> {
74    #[inline]
75    pub fn map_into_ptr(&self, py: Python<'_>, obj: PyResult<()>) -> PyResult<*mut ffi::PyObject> {
76        obj.map(|_| PyNone::get(py).to_owned().into_ptr())
77    }
78}
79
80impl<'py, T: IntoPyObject<'py>> IntoPyObjectConverter<T> {
81    #[inline]
82    pub fn wrap(&self, obj: T) -> Result<T, Infallible> {
83        Ok(obj)
84    }
85}
86
87impl<'py, T: IntoPyObject<'py>, E> IntoPyObjectConverter<Result<T, E>> {
88    #[inline]
89    pub fn wrap(&self, obj: Result<T, E>) -> Result<T, E> {
90        obj
91    }
92
93    #[inline]
94    pub fn map_into_pyobject(&self, py: Python<'py>, obj: PyResult<T>) -> PyResult<Py<PyAny>>
95    where
96        T: IntoPyObject<'py>,
97    {
98        obj.and_then(|obj| obj.into_py_any(py))
99    }
100
101    #[inline]
102    pub fn map_into_ptr(&self, py: Python<'py>, obj: PyResult<T>) -> PyResult<*mut ffi::PyObject>
103    where
104        T: IntoPyObject<'py>,
105    {
106        obj.and_then(|obj| obj.into_bound_py_any(py))
107            .map(Bound::into_ptr)
108    }
109}
110
111impl<T, E> UnknownReturnResultType<Result<T, E>> {
112    #[inline]
113    pub fn wrap<'py>(&self, _: Result<T, E>) -> Result<T, E>
114    where
115        T: IntoPyObject<'py>,
116    {
117        unreachable!("should be handled by IntoPyObjectConverter")
118    }
119}
120
121impl<T> UnknownReturnType<T> {
122    #[inline]
123    pub fn wrap<'py>(&self, _: T) -> T
124    where
125        T: IntoPyObject<'py>,
126    {
127        unreachable!("should be handled by IntoPyObjectConverter")
128    }
129
130    #[inline]
131    pub fn map_into_pyobject<'py>(&self, _: Python<'py>, _: PyResult<T>) -> PyResult<Py<PyAny>>
132    where
133        T: IntoPyObject<'py>,
134    {
135        unreachable!("should be handled by IntoPyObjectConverter")
136    }
137
138    #[inline]
139    pub fn map_into_ptr<'py>(&self, _: Python<'py>, _: PyResult<T>) -> PyResult<*mut ffi::PyObject>
140    where
141        T: IntoPyObject<'py>,
142    {
143        unreachable!("should be handled by IntoPyObjectConverter")
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150
151    #[test]
152    fn wrap_option() {
153        let a: Option<u8> = SomeWrap::wrap(42);
154        assert_eq!(a, Some(42));
155
156        let b: Option<u8> = SomeWrap::wrap(None);
157        assert_eq!(b, None);
158    }
159}