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 function return type machinery
25pub struct Converter<T>(EmptyTupleConverter<T>);
26pub struct EmptyTupleConverter<T>(IntoPyObjectConverter<T>);
27pub struct IntoPyObjectConverter<T>(UnknownReturnResultType<T>);
28pub struct UnknownReturnResultType<T>(UnknownReturnType<T>);
29pub struct UnknownReturnType<T>(PhantomData<T>);
30
31pub fn converter<T>(_: &T) -> Converter<T> {
32    Converter(EmptyTupleConverter(IntoPyObjectConverter(
33        UnknownReturnResultType(UnknownReturnType(PhantomData)),
34    )))
35}
36
37impl<T> Deref for Converter<T> {
38    type Target = EmptyTupleConverter<T>;
39    fn deref(&self) -> &Self::Target {
40        &self.0
41    }
42}
43
44impl<T> Deref for EmptyTupleConverter<T> {
45    type Target = IntoPyObjectConverter<T>;
46    fn deref(&self) -> &Self::Target {
47        &self.0
48    }
49}
50
51impl<T> Deref for IntoPyObjectConverter<T> {
52    type Target = UnknownReturnResultType<T>;
53    fn deref(&self) -> &Self::Target {
54        &self.0
55    }
56}
57
58impl<T> Deref for UnknownReturnResultType<T> {
59    type Target = UnknownReturnType<T>;
60    fn deref(&self) -> &Self::Target {
61        &self.0
62    }
63}
64
65impl EmptyTupleConverter<PyResult<()>> {
66    #[inline]
67    pub fn map_into_ptr(&self, py: Python<'_>, obj: PyResult<()>) -> PyResult<*mut ffi::PyObject> {
68        obj.map(|_| PyNone::get(py).to_owned().into_ptr())
69    }
70
71    #[inline]
72    pub fn map_into_pyobject(&self, py: Python<'_>, obj: PyResult<()>) -> PyResult<Py<PyAny>> {
73        obj.map(|_| PyNone::get(py).to_owned().into_any().unbind())
74    }
75}
76
77impl<'py, T: IntoPyObject<'py>> IntoPyObjectConverter<T> {
78    #[inline]
79    pub fn wrap(&self, obj: T) -> Result<T, Infallible> {
80        Ok(obj)
81    }
82}
83
84impl<'py, T: IntoPyObject<'py>, E> IntoPyObjectConverter<Result<T, E>> {
85    #[inline]
86    pub fn wrap(&self, obj: Result<T, E>) -> Result<T, E> {
87        obj
88    }
89
90    #[inline]
91    pub fn map_into_pyobject(&self, py: Python<'py>, obj: PyResult<T>) -> PyResult<Py<PyAny>>
92    where
93        T: IntoPyObject<'py>,
94    {
95        obj.and_then(|obj| obj.into_py_any(py))
96    }
97
98    #[inline]
99    pub fn map_into_ptr(&self, py: Python<'py>, obj: PyResult<T>) -> PyResult<*mut ffi::PyObject>
100    where
101        T: IntoPyObject<'py>,
102    {
103        obj.and_then(|obj| obj.into_bound_py_any(py))
104            .map(Bound::into_ptr)
105    }
106}
107
108impl<T, E> UnknownReturnResultType<Result<T, E>> {
109    #[inline]
110    pub fn wrap<'py>(&self, _: Result<T, E>) -> Result<T, E>
111    where
112        T: IntoPyObject<'py>,
113    {
114        unreachable!("should be handled by IntoPyObjectConverter")
115    }
116}
117
118impl<T> UnknownReturnType<T> {
119    #[inline]
120    pub fn wrap<'py>(&self, _: T) -> T
121    where
122        T: IntoPyObject<'py>,
123    {
124        unreachable!("should be handled by IntoPyObjectConverter")
125    }
126
127    #[inline]
128    pub fn map_into_pyobject<'py>(&self, _: Python<'py>, _: PyResult<T>) -> PyResult<Py<PyAny>>
129    where
130        T: IntoPyObject<'py>,
131    {
132        unreachable!("should be handled by IntoPyObjectConverter")
133    }
134
135    #[inline]
136    pub fn map_into_ptr<'py>(&self, _: Python<'py>, _: PyResult<T>) -> PyResult<*mut ffi::PyObject>
137    where
138        T: IntoPyObject<'py>,
139    {
140        unreachable!("should be handled by IntoPyObjectConverter")
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147
148    #[test]
149    fn wrap_option() {
150        let a: Option<u8> = SomeWrap::wrap(42);
151        assert_eq!(a, Some(42));
152
153        let b: Option<u8> = SomeWrap::wrap(None);
154        assert_eq!(b, None);
155    }
156}