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
9pub 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
54pub 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}