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
use crate::{
exceptions::{PyBaseException, PyTypeError},
ffi,
type_object::PyTypeObject,
types::PyType,
AsPyPointer, 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 {
LazyTypeAndValue {
ptype: fn(Python) -> &PyType,
pvalue: Box<dyn FnOnce(Python) -> PyObject + Send + Sync>,
},
LazyValue {
ptype: Py<PyType>,
pvalue: Box<dyn FnOnce(Python) -> PyObject + Send + Sync>,
},
FfiTuple {
ptype: Option<PyObject>,
pvalue: Option<PyObject>,
ptraceback: Option<PyObject>,
},
Normalized(PyErrStateNormalized),
}
pub trait PyErrArguments: Send + Sync {
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::LazyTypeAndValue { ptype, pvalue } => {
let ty = ptype(py);
if unsafe { ffi::PyExceptionClass_Check(ty.as_ptr()) } == 0 {
Self::exceptions_must_derive_from_base_exception(py).into_ffi_tuple(py)
} else {
(
ptype(py).into_ptr(),
pvalue(py).into_ptr(),
std::ptr::null_mut(),
)
}
}
PyErrState::LazyValue { 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()),
}
}
#[inline]
pub(crate) fn exceptions_must_derive_from_base_exception(py: Python) -> Self {
PyErrState::LazyValue {
ptype: PyTypeError::type_object(py).into(),
pvalue: boxed_args("exceptions must derive from BaseException"),
}
}
}