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

View file

@ -1,4 +1,6 @@
use crate::exceptions::PyBaseException; use crate::exceptions::PyBaseException;
use crate::PyErr;
use std::any::Any;
pyo3_exception!( pyo3_exception!(
" "
@ -11,3 +13,16 @@ pyo3_exception!(
PanicException, PanicException,
PyBaseException 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",))
}
}
}