1use std::{convert::Infallible, marker::PhantomData, ops::Deref};
2
3#[allow(deprecated)]
4use crate::IntoPy;
5use crate::{ffi, types::PyNone, Bound, IntoPyObject, IntoPyObjectExt, PyObject, PyResult, Python};
6
7pub 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
24pub 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<PyObject>
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
111#[allow(deprecated)]
112impl<T: IntoPy<PyObject>> IntoPyConverter<T> {
113 #[inline]
114 pub fn wrap(&self, obj: T) -> Result<T, Infallible> {
115 Ok(obj)
116 }
117}
118
119#[allow(deprecated)]
120impl<T: IntoPy<PyObject>, E> IntoPyConverter<Result<T, E>> {
121 #[inline]
122 pub fn wrap(&self, obj: Result<T, E>) -> Result<T, E> {
123 obj
124 }
125
126 #[inline]
127 pub fn map_into_pyobject(&self, py: Python<'_>, obj: PyResult<T>) -> PyResult<PyObject> {
128 obj.map(|obj| obj.into_py(py))
129 }
130
131 #[inline]
132 pub fn map_into_ptr(&self, py: Python<'_>, obj: PyResult<T>) -> PyResult<*mut ffi::PyObject> {
133 obj.map(|obj| obj.into_py(py).into_ptr())
134 }
135}
136
137impl<T, E> UnknownReturnResultType<Result<T, E>> {
138 #[inline]
139 pub fn wrap<'py>(&self, _: Result<T, E>) -> Result<T, E>
140 where
141 T: IntoPyObject<'py>,
142 {
143 unreachable!("should be handled by IntoPyObjectConverter")
144 }
145}
146
147impl<T> UnknownReturnType<T> {
148 #[inline]
149 pub fn wrap<'py>(&self, _: T) -> T
150 where
151 T: IntoPyObject<'py>,
152 {
153 unreachable!("should be handled by IntoPyObjectConverter")
154 }
155
156 #[inline]
157 pub fn map_into_pyobject<'py>(&self, _: Python<'py>, _: PyResult<T>) -> PyResult<PyObject>
158 where
159 T: IntoPyObject<'py>,
160 {
161 unreachable!("should be handled by IntoPyObjectConverter")
162 }
163
164 #[inline]
165 pub fn map_into_ptr<'py>(&self, _: Python<'py>, _: PyResult<T>) -> PyResult<*mut ffi::PyObject>
166 where
167 T: IntoPyObject<'py>,
168 {
169 unreachable!("should be handled by IntoPyObjectConverter")
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn wrap_option() {
179 let a: Option<u8> = SomeWrap::wrap(42);
180 assert_eq!(a, Some(42));
181
182 let b: Option<u8> = SomeWrap::wrap(None);
183 assert_eq!(b, None);
184 }
185}