1use crate::err::{PyErr, PyResult};
4use crate::exceptions::PyOverflowError;
5use crate::ffi::{self, Py_hash_t};
6use crate::{BoundObject, IntoPyObject, PyObject, Python};
7use std::os::raw::c_int;
8
9pub trait PyCallbackOutput: Copy {
11 const ERR_VALUE: Self;
13}
14
15impl PyCallbackOutput for *mut ffi::PyObject {
16 const ERR_VALUE: Self = std::ptr::null_mut();
17}
18
19impl PyCallbackOutput for std::os::raw::c_int {
20 const ERR_VALUE: Self = -1;
21}
22
23impl PyCallbackOutput for ffi::Py_ssize_t {
24 const ERR_VALUE: Self = -1;
25}
26
27pub trait IntoPyCallbackOutput<'py, Target> {
29 fn convert(self, py: Python<'py>) -> PyResult<Target>;
30}
31
32impl<'py, T, E, U> IntoPyCallbackOutput<'py, U> for Result<T, E>
33where
34 T: IntoPyCallbackOutput<'py, U>,
35 E: Into<PyErr>,
36{
37 #[inline]
38 fn convert(self, py: Python<'py>) -> PyResult<U> {
39 match self {
40 Ok(v) => v.convert(py),
41 Err(e) => Err(e.into()),
42 }
43 }
44}
45
46impl<'py, T> IntoPyCallbackOutput<'py, *mut ffi::PyObject> for T
47where
48 T: IntoPyObject<'py>,
49{
50 #[inline]
51 fn convert(self, py: Python<'py>) -> PyResult<*mut ffi::PyObject> {
52 self.into_pyobject(py)
53 .map(BoundObject::into_ptr)
54 .map_err(Into::into)
55 }
56}
57
58impl IntoPyCallbackOutput<'_, Self> for *mut ffi::PyObject {
59 #[inline]
60 fn convert(self, _: Python<'_>) -> PyResult<Self> {
61 Ok(self)
62 }
63}
64
65impl IntoPyCallbackOutput<'_, std::os::raw::c_int> for () {
66 #[inline]
67 fn convert(self, _: Python<'_>) -> PyResult<std::os::raw::c_int> {
68 Ok(0)
69 }
70}
71
72impl IntoPyCallbackOutput<'_, std::os::raw::c_int> for bool {
73 #[inline]
74 fn convert(self, _: Python<'_>) -> PyResult<std::os::raw::c_int> {
75 Ok(self as c_int)
76 }
77}
78
79impl IntoPyCallbackOutput<'_, ()> for () {
80 #[inline]
81 fn convert(self, _: Python<'_>) -> PyResult<()> {
82 Ok(())
83 }
84}
85
86impl IntoPyCallbackOutput<'_, ffi::Py_ssize_t> for usize {
87 #[inline]
88 fn convert(self, _py: Python<'_>) -> PyResult<ffi::Py_ssize_t> {
89 self.try_into().map_err(|_err| PyOverflowError::new_err(()))
90 }
91}
92
93impl IntoPyCallbackOutput<'_, bool> for bool {
96 #[inline]
97 fn convert(self, _: Python<'_>) -> PyResult<bool> {
98 Ok(self)
99 }
100}
101
102impl IntoPyCallbackOutput<'_, usize> for usize {
103 #[inline]
104 fn convert(self, _: Python<'_>) -> PyResult<usize> {
105 Ok(self)
106 }
107}
108
109impl<'py, T> IntoPyCallbackOutput<'py, PyObject> for T
110where
111 T: IntoPyObject<'py>,
112{
113 #[inline]
114 fn convert(self, py: Python<'py>) -> PyResult<PyObject> {
115 self.into_pyobject(py)
116 .map(BoundObject::into_any)
117 .map(BoundObject::unbind)
118 .map_err(Into::into)
119 }
120}
121
122pub trait WrappingCastTo<T> {
123 fn wrapping_cast(self) -> T;
124}
125
126macro_rules! wrapping_cast {
127 ($from:ty, $to:ty) => {
128 impl WrappingCastTo<$to> for $from {
129 #[inline]
130 fn wrapping_cast(self) -> $to {
131 self as $to
132 }
133 }
134 };
135}
136wrapping_cast!(u8, Py_hash_t);
137wrapping_cast!(u16, Py_hash_t);
138wrapping_cast!(u32, Py_hash_t);
139wrapping_cast!(usize, Py_hash_t);
140wrapping_cast!(u64, Py_hash_t);
141wrapping_cast!(i8, Py_hash_t);
142wrapping_cast!(i16, Py_hash_t);
143wrapping_cast!(i32, Py_hash_t);
144wrapping_cast!(isize, Py_hash_t);
145wrapping_cast!(i64, Py_hash_t);
146
147pub struct HashCallbackOutput(Py_hash_t);
148
149impl IntoPyCallbackOutput<'_, Py_hash_t> for HashCallbackOutput {
150 #[inline]
151 fn convert(self, _py: Python<'_>) -> PyResult<Py_hash_t> {
152 let hash = self.0;
153 if hash == -1 {
154 Ok(-2)
155 } else {
156 Ok(hash)
157 }
158 }
159}
160
161impl<T> IntoPyCallbackOutput<'_, HashCallbackOutput> for T
162where
163 T: WrappingCastTo<Py_hash_t>,
164{
165 #[inline]
166 fn convert(self, _py: Python<'_>) -> PyResult<HashCallbackOutput> {
167 Ok(HashCallbackOutput(self.wrapping_cast()))
168 }
169}
170
171#[doc(hidden)]
172#[inline]
173pub fn convert<'py, T, U>(py: Python<'py>, value: T) -> PyResult<U>
174where
175 T: IntoPyCallbackOutput<'py, U>,
176{
177 value.convert(py)
178}