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
use crate::{
    exceptions::PyBaseException, ffi, types::PyType, IntoPy, IntoPyPointer, Py, PyObject, Python,
};

#[derive(Clone)]
pub(crate) struct PyErrStateNormalized {
    pub ptype: Py<PyType>,
    pub pvalue: Py<PyBaseException>,
    pub ptraceback: Option<PyObject>,
}

pub(crate) enum PyErrState {
    Lazy {
        ptype: Py<PyType>,
        pvalue: Box<dyn FnOnce(Python) -> PyObject + Send + Sync>,
    },
    FfiTuple {
        ptype: Option<PyObject>,
        pvalue: Option<PyObject>,
        ptraceback: Option<PyObject>,
    },
    Normalized(PyErrStateNormalized),
}

/// Helper conversion trait that allows to use custom arguments for lazy exception construction.
pub trait PyErrArguments: Send + Sync {
    /// Arguments for exception
    fn arguments(self, py: Python) -> PyObject;
}

impl<T> PyErrArguments for T
where
    T: IntoPy<PyObject> + Send + Sync,
{
    fn arguments(self, py: Python) -> PyObject {
        self.into_py(py)
    }
}

pub(crate) fn boxed_args(
    args: impl PyErrArguments + 'static,
) -> Box<dyn FnOnce(Python) -> PyObject + Send + Sync> {
    Box::new(|py| args.arguments(py))
}

impl PyErrState {
    pub(crate) fn into_ffi_tuple(
        self,
        py: Python,
    ) -> (*mut ffi::PyObject, *mut ffi::PyObject, *mut ffi::PyObject) {
        match self {
            PyErrState::Lazy { ptype, pvalue } => (
                ptype.into_ptr(),
                pvalue(py).into_ptr(),
                std::ptr::null_mut(),
            ),
            PyErrState::FfiTuple {
                ptype,
                pvalue,
                ptraceback,
            } => (ptype.into_ptr(), pvalue.into_ptr(), ptraceback.into_ptr()),
            PyErrState::Normalized(PyErrStateNormalized {
                ptype,
                pvalue,
                ptraceback,
            }) => (ptype.into_ptr(), pvalue.into_ptr(), ptraceback.into_ptr()),
        }
    }
}