Skip to main content

pyo3/impl_/
wrap.rs

1#![warn(clippy::undocumented_unsafe_blocks)]
2
3use core::{convert::Infallible, marker::PhantomData, ops::Deref};
4
5use crate::{
6    ffi, types::PyNone, Bound, IntoPyObject, IntoPyObjectExt, Py, PyAny, PyResult, Python,
7};
8
9/// Used to wrap values in `Option<T>` for default arguments.
10pub trait SomeWrap<T> {
11    fn wrap(self) -> Option<T>;
12}
13
14impl<T> SomeWrap<T> for T {
15    fn wrap(self) -> Option<T> {
16        Some(self)
17    }
18}
19
20impl<T> SomeWrap<T> for Option<T> {
21    fn wrap(self) -> Self {
22        self
23    }
24}
25
26pub struct OkWrapper<T>(OkWrapperInner<T>);
27pub struct OkWrapperInner<T>(PhantomData<T>);
28
29impl<T> OkWrapper<T> {
30    pub fn new(_: &T) -> Self {
31        Self(OkWrapperInner(PhantomData))
32    }
33}
34
35impl<T> Deref for OkWrapper<T> {
36    type Target = OkWrapperInner<T>;
37    fn deref(&self) -> &Self::Target {
38        &self.0
39    }
40}
41
42impl<T, E> OkWrapper<Result<T, E>> {
43    pub fn ok_wrap(&self, value: Result<T, E>) -> Result<T, E> {
44        value
45    }
46}
47
48impl<T> OkWrapperInner<T> {
49    pub fn ok_wrap(&self, value: T) -> Result<T, Infallible> {
50        Ok(value)
51    }
52}
53
54// Hierarchy of conversions used in the function return type machinery
55pub struct Converter<T>(EmptyTupleConverter<T>);
56pub struct EmptyTupleConverter<T>(IntoPyObjectConverter<T>);
57pub struct IntoPyObjectConverter<T>(UnknownReturnResultType<T>);
58pub struct UnknownReturnResultType<T>(UnknownReturnType<T>);
59pub struct UnknownReturnType<T>(PhantomData<T>);
60
61pub fn converter<T>(_: &T) -> Converter<T> {
62    Converter(EmptyTupleConverter(IntoPyObjectConverter(
63        UnknownReturnResultType(UnknownReturnType(PhantomData)),
64    )))
65}
66
67impl<T> Deref for Converter<T> {
68    type Target = EmptyTupleConverter<T>;
69    fn deref(&self) -> &Self::Target {
70        &self.0
71    }
72}
73
74impl<T> Deref for EmptyTupleConverter<T> {
75    type Target = IntoPyObjectConverter<T>;
76    fn deref(&self) -> &Self::Target {
77        &self.0
78    }
79}
80
81impl<T> Deref for IntoPyObjectConverter<T> {
82    type Target = UnknownReturnResultType<T>;
83    fn deref(&self) -> &Self::Target {
84        &self.0
85    }
86}
87
88impl<T> Deref for UnknownReturnResultType<T> {
89    type Target = UnknownReturnType<T>;
90    fn deref(&self) -> &Self::Target {
91        &self.0
92    }
93}
94
95impl EmptyTupleConverter<PyResult<()>> {
96    #[inline]
97    pub fn map_into_ptr(&self, py: Python<'_>, obj: PyResult<()>) -> PyResult<*mut ffi::PyObject> {
98        obj.map(|_| PyNone::get(py).to_owned().into_ptr())
99    }
100
101    #[inline]
102    pub fn map_into_pyobject(&self, py: Python<'_>, obj: PyResult<()>) -> PyResult<Py<PyAny>> {
103        obj.map(|_| PyNone::get(py).to_owned().into_any().unbind())
104    }
105}
106
107impl<'py, T: IntoPyObject<'py>> IntoPyObjectConverter<T> {
108    #[inline]
109    pub fn wrap(&self, obj: T) -> Result<T, Infallible> {
110        Ok(obj)
111    }
112}
113
114impl<'py, T: IntoPyObject<'py>, E> IntoPyObjectConverter<Result<T, E>> {
115    #[inline]
116    pub fn wrap(&self, obj: Result<T, E>) -> Result<T, E> {
117        obj
118    }
119
120    #[inline]
121    pub fn map_into_pyobject(&self, py: Python<'py>, obj: PyResult<T>) -> PyResult<Py<PyAny>>
122    where
123        T: IntoPyObject<'py>,
124    {
125        obj.and_then(|obj| obj.into_py_any(py))
126    }
127
128    #[inline]
129    pub fn map_into_ptr(&self, py: Python<'py>, obj: PyResult<T>) -> PyResult<*mut ffi::PyObject>
130    where
131        T: IntoPyObject<'py>,
132    {
133        obj.and_then(|obj| obj.into_bound_py_any(py))
134            .map(Bound::into_ptr)
135    }
136}
137
138impl<T, E> UnknownReturnResultType<Result<T, E>> {
139    #[inline]
140    pub fn wrap<'py>(&self, _: Result<T, E>) -> Result<T, E>
141    where
142        T: IntoPyObject<'py>,
143    {
144        unreachable!("should be handled by IntoPyObjectConverter")
145    }
146}
147
148impl<T> UnknownReturnType<T> {
149    #[inline]
150    pub fn wrap<'py>(&self, _: T) -> T
151    where
152        T: IntoPyObject<'py>,
153    {
154        unreachable!("should be handled by IntoPyObjectConverter")
155    }
156
157    #[inline]
158    pub fn map_into_pyobject<'py>(&self, _: Python<'py>, _: PyResult<T>) -> PyResult<Py<PyAny>>
159    where
160        T: IntoPyObject<'py>,
161    {
162        unreachable!("should be handled by IntoPyObjectConverter")
163    }
164
165    #[inline]
166    pub fn map_into_ptr<'py>(&self, _: Python<'py>, _: PyResult<T>) -> PyResult<*mut ffi::PyObject>
167    where
168        T: IntoPyObject<'py>,
169    {
170        unreachable!("should be handled by IntoPyObjectConverter")
171    }
172}
173
174#[cfg(test)]
175mod tests {
176    use super::*;
177
178    #[test]
179    fn wrap_option() {
180        let a: Option<u8> = SomeWrap::wrap(42);
181        assert_eq!(a, Some(42));
182
183        let b: Option<u8> = SomeWrap::wrap(None);
184        assert_eq!(b, None);
185    }
186
187    #[test]
188    fn wrap_result() {
189        let a = 42;
190        let Ok(a) = OkWrapper::new(&a).ok_wrap(a);
191        assert_eq!(a, 42);
192
193        let b = Result::<_, String>::Ok(42);
194        let b = OkWrapper::new(&b).ok_wrap(b);
195        assert_eq!(b, Ok(42));
196    }
197}
⚠️ Internal Docs ⚠️ Not Public API 👉 Official Docs Here