# callback.rs - source
Source of the Rust file `/home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/pyo3-0.13.2/src/callback.rs`.
Keywords: rust, rustlang, rust-lang

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263

    // Copyright (c) 2017-present PyO3 Project and Contributors

    //! Utilities for a Python callable object that invokes a Rust function.

    use crate::err::{PyErr, PyResult};
    use crate::exceptions::PyOverflowError;
    use crate::ffi::{self, Py_hash_t};
    use crate::IntoPyPointer;
    use crate::{IntoPy, PyObject, Python};
    use std::isize;
    use std::os::raw::c_int;

    /// A type which can be the return type of a python C-API callback
    pub trait PyCallbackOutput: Copy {
        /// The error value to return to python if the callback raised an exception
        const ERR_VALUE: Self;
    }

    impl PyCallbackOutput for *mut ffi::PyObject {
        const ERR_VALUE: Self = std::ptr::null_mut();
    }

    impl PyCallbackOutput for std::os::raw::c_int {
        const ERR_VALUE: Self = -1;
    }

    impl PyCallbackOutput for ffi::Py_ssize_t {
        const ERR_VALUE: Self = -1;
    }

    impl PyCallbackOutput for () {
        const ERR_VALUE: Self = ();
    }

    /// Convert the result of callback function into the appropriate return value.
    pub trait IntoPyCallbackOutput<Target> {
        fn convert(self, py: Python) -> PyResult<Target>;
    }

    impl<T, E, U> IntoPyCallbackOutput<U> for Result<T, E>
    where
        T: IntoPyCallbackOutput<U>,
        E: Into<PyErr>,
    {
        fn convert(self, py: Python) -> PyResult<U> {
            self.map_err(Into::into).and_then(|t| t.convert(py))
        }
    }

    impl<T> IntoPyCallbackOutput<*mut ffi::PyObject> for T
    where
        T: IntoPy<PyObject>,
    {
        fn convert(self, py: Python) -> PyResult<*mut ffi::PyObject> {
            Ok(self.into_py(py).into_ptr())
        }
    }

    impl IntoPyCallbackOutput<Self> for *mut ffi::PyObject {
        fn convert(self, _: Python) -> PyResult<Self> {
            Ok(self)
        }
    }

    impl IntoPyCallbackOutput<std::os::raw::c_int> for () {
        fn convert(self, _: Python) -> PyResult<std::os::raw::c_int> {
            Ok(0)
        }
    }

    impl IntoPyCallbackOutput<std::os::raw::c_int> for bool {
        fn convert(self, _: Python) -> PyResult<std::os::raw::c_int> {
            Ok(self as c_int)
        }
    }

    impl IntoPyCallbackOutput<()> for () {
        fn convert(self, _: Python) -> PyResult<()> {
            Ok(())
        }
    }

    impl IntoPyCallbackOutput<ffi::Py_ssize_t> for usize {
        #[inline]
        fn convert(self, _py: Python) -> PyResult<ffi::Py_ssize_t> {
            if self <= (isize::MAX as usize) {
                Ok(self as isize)
            } else {
                Err(PyOverflowError::new_err(()))
            }
        }
    }

    // Converters needed for `#[pyproto]` implementations

    impl IntoPyCallbackOutput<bool> for bool {
        fn convert(self, _: Python) -> PyResult<bool> {
            Ok(self)
        }
    }

    impl IntoPyCallbackOutput<usize> for usize {
        fn convert(self, _: Python) -> PyResult<usize> {
            Ok(self)
        }
    }

    impl<T> IntoPyCallbackOutput<PyObject> for T
    where
        T: IntoPy<PyObject>,
    {
        fn convert(self, py: Python) -> PyResult<PyObject> {
            Ok(self.into_py(py))
        }
    }

    pub trait WrappingCastTo<T> {
        fn wrapping_cast(self) -> T;
    }

    macro_rules! wrapping_cast {
        ($from:ty, $to:ty) => {
            impl WrappingCastTo<$to> for $from {
                #[inline]
                fn wrapping_cast(self) -> $to {
                    self as $to
                }
            }
        };
    }
    wrapping_cast!(u8, Py_hash_t);
    wrapping_cast!(u16, Py_hash_t);
    wrapping_cast!(u32, Py_hash_t);
    wrapping_cast!(usize, Py_hash_t);
    wrapping_cast!(u64, Py_hash_t);
    wrapping_cast!(i8, Py_hash_t);
    wrapping_cast!(i16, Py_hash_t);
    wrapping_cast!(i32, Py_hash_t);
    wrapping_cast!(isize, Py_hash_t);
    wrapping_cast!(i64, Py_hash_t);

    pub struct HashCallbackOutput(Py_hash_t);

    impl IntoPyCallbackOutput<Py_hash_t> for HashCallbackOutput {
        #[inline]
        fn convert(self, _py: Python) -> PyResult<Py_hash_t> {
            let hash = self.0;
            if hash == -1 {
                Ok(-2)
            } else {
                Ok(hash)
            }
        }
    }

    impl<T> IntoPyCallbackOutput<HashCallbackOutput> for T
    where
        T: WrappingCastTo<Py_hash_t>,
    {
        #[inline]
        fn convert(self, _py: Python) -> PyResult<HashCallbackOutput> {
            Ok(HashCallbackOutput(self.wrapping_cast()))
        }
    }

    #[doc(hidden)]
    #[inline]
    pub fn convert<T, U>(py: Python, value: T) -> PyResult<U>
    where
        T: IntoPyCallbackOutput<U>,
    {
        value.convert(py)
    }

    #[doc(hidden)]
    #[inline]
    pub fn callback_error<T>() -> T
    where
        T: PyCallbackOutput,
    {
        T::ERR_VALUE
    }

    /// Use this macro for all internal callback functions which Python will call.
    ///
    /// It sets up the GILPool and converts the output into a Python object. It also restores
    /// any python error returned as an Err variant from the body.
    ///
    /// Finally, any panics inside the callback body will be caught and translated into PanicExceptions.
    ///
    /// # Safety
    /// This macro assumes the GIL is held. (It makes use of unsafe code, so usage of it is only
    /// possible inside unsafe blocks.)
    #[doc(hidden)]
    #[macro_export]
    macro_rules! callback_body {
        ($py:ident, $body:expr) => {{
            $crate::callback_body_without_convert!($py, $crate::callback::convert($py, $body))
        }};
    }

    /// Variant of the above which does not perform the callback conversion. This allows the callback
    /// conversion to be done manually in the case where lifetimes might otherwise cause issue.
    ///
    /// For example this pyfunction:
    ///
    /// ```ignore
    /// fn foo(&self) -> &Bar {
    ///     &self.bar
    /// }
    /// ```
    ///
    /// It is wrapped in proc macros with callback_body_without_convert like so:
    ///
    /// ```ignore
    /// pyo3::callback_body_without_convert!(py, {
    ///     let _slf = #slf;
    ///     pyo3::callback::convert(py, #foo)
    /// })
    /// ```
    ///
    /// If callback_body was used instead:
    ///
    /// ```ignore
    /// pyo3::callback_body!(py, {
    ///     let _slf = #slf;
    ///     #foo
    /// })
    /// ```
    ///
    /// Then this will fail to compile, because the result of #foo borrows _slf, but _slf drops when
    /// the block passed to the macro ends.
    #[doc(hidden)]
    #[macro_export]
    macro_rules! callback_body_without_convert {
        ($py:ident, $body:expr) => {{
            let pool = $crate::GILPool::new();
            let unwind_safe_py = std::panic::AssertUnwindSafe(pool.python());
            let result = match std::panic::catch_unwind(move || -> $crate::PyResult<_> {
                let $py = *unwind_safe_py;
                $body
            }) {
                Ok(result) => result,
                Err(e) => {
                    // Try to format the error in the same way panic does
                    if let Some(string) = e.downcast_ref::<String>() {
                        Err($crate::panic::PanicException::new_err((string.clone(),)))
                    } else if let Some(s) = e.downcast_ref::<&str>() {
                        Err($crate::panic::PanicException::new_err((s.to_string(),)))
                    } else {
                        Err($crate::panic::PanicException::new_err((
                            "panic from Rust code",
                        )))
                    }
                }
            };

            result.unwrap_or_else(|e| {
                e.restore(pool.python());
                $crate::callback::callback_error()
            })
        }};
    }