1use crate::err::{PyErr, PyResult};
4use crate::exceptions::PyOverflowError;
5use crate::ffi::{self, Py_hash_t};
6use crate::{BoundObject, IntoPyObject, Py, PyAny, Python};
7use core::ffi::c_int;
8
9pub trait PyCallbackOutput: Copy + py_callback_output::Sealed {
11 const ERR_VALUE: Self;
13}
14
15mod py_callback_output {
17 use core::ffi::c_int;
18
19 use pyo3_ffi::Py_ssize_t;
20
21 use crate::ffi::PyObject;
22
23 pub trait Sealed {}
24
25 impl Sealed for *mut PyObject {}
26 impl Sealed for c_int {}
27 impl Sealed for Py_ssize_t {}
28}
29
30impl PyCallbackOutput for *mut ffi::PyObject {
31 const ERR_VALUE: Self = core::ptr::null_mut();
32}
33
34impl PyCallbackOutput for core::ffi::c_int {
35 const ERR_VALUE: Self = -1;
36}
37
38impl PyCallbackOutput for ffi::Py_ssize_t {
39 const ERR_VALUE: Self = -1;
40}
41
42pub trait IntoPyCallbackOutput<'py, Target>: into_py_callback_output::Sealed<'py, Target> {
44 fn convert(self, py: Python<'py>) -> PyResult<Target>;
45}
46
47mod into_py_callback_output {
49 use pyo3_ffi::Py_hash_t;
50
51 use crate::{
52 ffi,
53 impl_::callback::{HashCallbackOutput, IntoPyCallbackOutput, WrappingCastTo},
54 IntoPyObject, Py, PyAny, PyErr,
55 };
56
57 pub trait Sealed<'py, Target> {}
58
59 impl<'py, T: IntoPyObject<'py>> Sealed<'py, *mut ffi::PyObject> for T {}
60 impl<'py, T: IntoPyCallbackOutput<'py, U>, E: Into<PyErr>, U> Sealed<'py, U> for Result<T, E> {}
61 impl Sealed<'_, Self> for *mut ffi::PyObject {}
62 impl Sealed<'_, core::ffi::c_int> for () {}
63 impl Sealed<'_, core::ffi::c_int> for bool {}
64 impl Sealed<'_, ()> for () {}
65 impl Sealed<'_, ffi::Py_ssize_t> for usize {}
66 impl Sealed<'_, bool> for bool {}
67 impl Sealed<'_, usize> for usize {}
68 impl<'py, T: IntoPyObject<'py>> Sealed<'py, Py<PyAny>> for T {}
69 impl Sealed<'_, Py_hash_t> for HashCallbackOutput {}
70 impl<T: WrappingCastTo<Py_hash_t>> Sealed<'_, HashCallbackOutput> for T {}
71}
72
73impl<'py, T, E, U> IntoPyCallbackOutput<'py, U> for Result<T, E>
74where
75 T: IntoPyCallbackOutput<'py, U>,
76 E: Into<PyErr>,
77{
78 #[inline]
79 fn convert(self, py: Python<'py>) -> PyResult<U> {
80 match self {
81 Ok(v) => v.convert(py),
82 Err(e) => Err(e.into()),
83 }
84 }
85}
86
87impl<'py, T> IntoPyCallbackOutput<'py, *mut ffi::PyObject> for T
88where
89 T: IntoPyObject<'py>,
90{
91 #[inline]
92 fn convert(self, py: Python<'py>) -> PyResult<*mut ffi::PyObject> {
93 self.into_pyobject(py)
94 .map(BoundObject::into_ptr)
95 .map_err(Into::into)
96 }
97}
98
99impl IntoPyCallbackOutput<'_, Self> for *mut ffi::PyObject {
100 #[inline]
101 fn convert(self, _: Python<'_>) -> PyResult<Self> {
102 Ok(self)
103 }
104}
105
106impl IntoPyCallbackOutput<'_, core::ffi::c_int> for () {
107 #[inline]
108 fn convert(self, _: Python<'_>) -> PyResult<core::ffi::c_int> {
109 Ok(0)
110 }
111}
112
113impl IntoPyCallbackOutput<'_, core::ffi::c_int> for bool {
114 #[inline]
115 fn convert(self, _: Python<'_>) -> PyResult<core::ffi::c_int> {
116 Ok(self as c_int)
117 }
118}
119
120impl IntoPyCallbackOutput<'_, ()> for () {
121 #[inline]
122 fn convert(self, _: Python<'_>) -> PyResult<()> {
123 Ok(())
124 }
125}
126
127impl IntoPyCallbackOutput<'_, ffi::Py_ssize_t> for usize {
128 #[inline]
129 fn convert(self, _py: Python<'_>) -> PyResult<ffi::Py_ssize_t> {
130 self.try_into().map_err(|_err| PyOverflowError::new_err(()))
131 }
132}
133
134impl IntoPyCallbackOutput<'_, bool> for bool {
137 #[inline]
138 fn convert(self, _: Python<'_>) -> PyResult<bool> {
139 Ok(self)
140 }
141}
142
143impl IntoPyCallbackOutput<'_, usize> for usize {
144 #[inline]
145 fn convert(self, _: Python<'_>) -> PyResult<usize> {
146 Ok(self)
147 }
148}
149
150impl<'py, T> IntoPyCallbackOutput<'py, Py<PyAny>> for T
151where
152 T: IntoPyObject<'py>,
153{
154 #[inline]
155 fn convert(self, py: Python<'py>) -> PyResult<Py<PyAny>> {
156 self.into_pyobject(py)
157 .map(BoundObject::into_any)
158 .map(BoundObject::unbind)
159 .map_err(Into::into)
160 }
161}
162
163pub trait WrappingCastTo<T>: wrapping_cast_to::Sealed<T> {
164 fn wrapping_cast(self) -> T;
165}
166
167mod wrapping_cast_to {
169 pub trait Sealed<T> {}
170}
171
172macro_rules! wrapping_cast {
173 ($from:ty, $to:ty) => {
174 impl WrappingCastTo<$to> for $from {
175 #[inline]
176 fn wrapping_cast(self) -> $to {
177 self as $to
178 }
179 }
180 impl wrapping_cast_to::Sealed<$to> for $from {}
181 };
182}
183wrapping_cast!(u8, Py_hash_t);
184wrapping_cast!(u16, Py_hash_t);
185wrapping_cast!(u32, Py_hash_t);
186wrapping_cast!(usize, Py_hash_t);
187wrapping_cast!(u64, Py_hash_t);
188wrapping_cast!(i8, Py_hash_t);
189wrapping_cast!(i16, Py_hash_t);
190wrapping_cast!(i32, Py_hash_t);
191wrapping_cast!(isize, Py_hash_t);
192wrapping_cast!(i64, Py_hash_t);
193
194pub struct HashCallbackOutput(Py_hash_t);
195
196impl IntoPyCallbackOutput<'_, Py_hash_t> for HashCallbackOutput {
197 #[inline]
198 fn convert(self, _py: Python<'_>) -> PyResult<Py_hash_t> {
199 let hash = self.0;
200 if hash == -1 {
201 Ok(-2)
202 } else {
203 Ok(hash)
204 }
205 }
206}
207
208impl<T> IntoPyCallbackOutput<'_, HashCallbackOutput> for T
209where
210 T: WrappingCastTo<Py_hash_t>,
211{
212 #[inline]
213 fn convert(self, _py: Python<'_>) -> PyResult<HashCallbackOutput> {
214 Ok(HashCallbackOutput(self.wrapping_cast()))
215 }
216}
217
218#[doc(hidden)]
219#[inline]
220pub fn convert<'py, T, U>(py: Python<'py>, value: T) -> PyResult<U>
221where
222 T: IntoPyCallbackOutput<'py, U>,
223{
224 value.convert(py)
225}