Reduce size of compiled code for methods

This commit is contained in:
Tim Robinson 2020-10-21 16:55:09 +01:00
parent 32dc93e389
commit 95636f1ba7
2 changed files with 45 additions and 25 deletions

View file

@ -5,11 +5,13 @@
use crate::err::{PyErr, PyResult};
use crate::exceptions::PyOverflowError;
use crate::ffi::{self, Py_hash_t};
use crate::IntoPyPointer;
use crate::panic::PanicException;
use crate::{GILPool, IntoPyPointer};
use crate::{IntoPy, PyObject, Python};
use std::isize;
use std::any::Any;
use std::os::raw::c_int;
use std::panic::UnwindSafe;
use std::panic::{AssertUnwindSafe, UnwindSafe};
use std::{isize, panic};
/// A type which can be the return type of a python C-API callback
pub trait PyCallbackOutput: Copy {
@ -234,30 +236,33 @@ macro_rules! callback_body {
#[doc(hidden)]
pub unsafe fn handle_panic<F, R>(body: F) -> R
where
F: FnOnce(Python) -> crate::PyResult<R> + UnwindSafe,
F: FnOnce(Python) -> PyResult<R> + UnwindSafe,
R: PyCallbackOutput,
{
let pool = crate::GILPool::new();
let unwind_safe_py = std::panic::AssertUnwindSafe(pool.python());
let result =
match std::panic::catch_unwind(move || -> crate::PyResult<_> { body(*unwind_safe_py) }) {
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",
)))
}
let pool = GILPool::new();
let unwind_safe_py = AssertUnwindSafe(pool.python());
let panic_result = panic::catch_unwind(move || -> PyResult<_> {
let py = *unwind_safe_py;
body(py)
});
panic_result_into_callback_output(pool.python(), panic_result)
}
fn panic_result_into_callback_output<R>(
py: Python,
panic_result: Result<PyResult<R>, Box<dyn Any + Send + 'static>>,
) -> R
where
R: PyCallbackOutput,
{
let py_result = match panic_result {
Ok(py_result) => py_result,
Err(panic_err) => Err(PanicException::from_panic(panic_err)),
};
result.unwrap_or_else(|e| {
e.restore(pool.python());
crate::callback::callback_error()
py_result.unwrap_or_else(|py_err| {
py_err.restore(py);
R::ERR_VALUE
})
}

View file

@ -1,4 +1,6 @@
use crate::exceptions::PyBaseException;
use crate::PyErr;
use std::any::Any;
pyo3_exception!(
"
@ -11,3 +13,16 @@ pyo3_exception!(
PanicException,
PyBaseException
);
impl PanicException {
// Try to format the error in the same way panic does
pub(crate) fn from_panic(e: Box<dyn Any + Send + 'static>) -> PyErr {
if let Some(string) = e.downcast_ref::<String>() {
Self::new_err((string.clone(),))
} else if let Some(s) = e.downcast_ref::<&str>() {
Self::new_err((s.to_string(),))
} else {
Self::new_err(("panic from Rust code",))
}
}
}