pyo3/src/callback.rs

302 lines
6.8 KiB
Rust
Raw Normal View History

2017-05-17 06:43:39 +00:00
/// Utilities for a Python callable object that invokes a Rust function.
use std::os::raw::c_int;
2017-05-25 03:31:51 +00:00
use std::{any, mem, ptr, isize, io, panic};
2017-05-17 06:43:39 +00:00
use libc;
2017-05-25 03:31:51 +00:00
use pyptr::Py;
use python::{Python, IntoPythonPointer};
2017-05-26 22:33:34 +00:00
use objects::exc;
2017-05-25 05:43:07 +00:00
use conversion::IntoPyObject;
2017-05-17 06:43:39 +00:00
use ffi::{self, Py_hash_t};
use err::{PyErr, PyResult};
pub trait CallbackConverter<S> {
type R;
fn convert(S, Python) -> Self::R;
fn error_value() -> Self::R;
}
pub struct PyObjectCallbackConverter;
impl <S> CallbackConverter<S> for PyObjectCallbackConverter
2017-05-25 05:43:07 +00:00
where S: IntoPyObject
2017-05-17 06:43:39 +00:00
{
type R = *mut ffi::PyObject;
fn convert(val: S, py: Python) -> *mut ffi::PyObject {
2017-05-25 03:31:51 +00:00
val.into_object(py).into_ptr()
2017-05-17 06:43:39 +00:00
}
#[inline]
fn error_value() -> *mut ffi::PyObject {
ptr::null_mut()
}
}
pub struct BoolCallbackConverter;
2017-05-17 06:43:39 +00:00
impl CallbackConverter<bool> for BoolCallbackConverter {
2017-05-17 06:43:39 +00:00
type R = c_int;
#[inline]
fn convert(val: bool, _py: Python) -> c_int {
val as c_int
}
#[inline]
fn error_value() -> c_int {
-1
}
}
pub struct LenResultConverter;
impl CallbackConverter<usize> for LenResultConverter {
type R = isize;
fn convert(val: usize, py: Python) -> isize {
if val <= (isize::MAX as usize) {
val as isize
} else {
2017-05-25 03:31:51 +00:00
PyErr::new_lazy_init(py.get_ptype::<exc::OverflowError>(), None).restore(py);
2017-05-17 06:43:39 +00:00
-1
}
}
#[inline]
fn error_value() -> isize {
-1
}
}
pub struct UnitCallbackConverter;
impl CallbackConverter<()> for UnitCallbackConverter {
type R = c_int;
#[inline]
fn convert(_: (), _: Python) -> c_int {
0
}
#[inline]
fn error_value() -> c_int {
-1
}
}
pub struct IterNextResultConverter;
impl <T> CallbackConverter<Option<T>>
for IterNextResultConverter
2017-05-25 05:43:07 +00:00
where T: IntoPyObject
2017-05-17 06:43:39 +00:00
{
type R = *mut ffi::PyObject;
fn convert(val: Option<T>, py: Python) -> *mut ffi::PyObject {
match val {
2017-05-25 03:31:51 +00:00
Some(val) => val.into_object(py).into_ptr(),
2017-05-17 06:43:39 +00:00
None => unsafe {
ffi::PyErr_SetNone(ffi::PyExc_StopIteration);
ptr::null_mut()
}
}
}
#[inline]
fn error_value() -> *mut ffi::PyObject {
ptr::null_mut()
}
}
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 HashConverter;
impl <T> CallbackConverter<T> for HashConverter
where T: WrappingCastTo<Py_hash_t>
{
type R = Py_hash_t;
#[inline]
fn convert(val: T, _py: Python) -> Py_hash_t {
let hash = val.wrapping_cast();
if hash == -1 {
-2
} else {
hash
}
}
#[inline]
fn error_value() -> Py_hash_t {
-1
}
}
2017-05-25 03:31:51 +00:00
pub unsafe fn handle<'p, F, T, C>(location: &str, _c: C, f: F) -> C::R
2017-05-22 05:22:45 +00:00
where F: FnOnce(Python<'p>) -> PyResult<T>,
2017-05-17 06:43:39 +00:00
F: panic::UnwindSafe,
2017-05-25 05:43:07 +00:00
C: CallbackConverter<T>
{
let guard = AbortOnDrop(location);
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
match f(py) {
Ok(val) => {
C::convert(val, py)
}
Err(e) => {
e.restore(py);
C::error_value()
}
}
});
let ret = match ret {
Ok(r) => r,
Err(ref err) => {
handle_panic(Python::assume_gil_acquired(), err);
C::error_value()
}
};
mem::forget(guard);
ret
}
#[allow(unused_mut)]
pub unsafe fn cb_unary<Slf, F, T, C>(location: &str,
slf: *mut ffi::PyObject, _c: C, f: F) -> C::R
where F: for<'p> FnOnce(Python<'p>, &'p mut Slf) -> PyResult<T>,
2017-05-25 05:43:07 +00:00
F: panic::UnwindSafe,
Slf: ::typeob::PyTypeInfo,
2017-05-17 06:43:39 +00:00
C: CallbackConverter<T>
{
let guard = AbortOnDrop(location);
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
let mut slf: Py<Slf> = Py::from_borrowed_ptr(py, slf);
match f(py, slf.as_mut()) {
Ok(val) => {
C::convert(val, py)
}
Err(e) => {
e.restore(py);
C::error_value()
}
}
});
let ret = match ret {
Ok(r) => r,
Err(ref err) => {
handle_panic(Python::assume_gil_acquired(), err);
C::error_value()
}
};
mem::forget(guard);
ret
}
#[allow(unused_mut)]
2017-05-26 22:33:34 +00:00
pub unsafe fn cb_unary_unit<Slf, F>(location: &str, slf: *mut ffi::PyObject, f: F) -> c_int
where F: for<'p> FnOnce(Python<'p>, &'p mut Slf) -> c_int,
F: panic::UnwindSafe,
Slf: ::typeob::PyTypeInfo,
{
let guard = AbortOnDrop(location);
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
let mut slf: Py<Slf> = Py::from_borrowed_ptr(py, slf);
2017-05-26 22:33:34 +00:00
f(py, slf.as_mut())
2017-05-17 06:43:39 +00:00
});
let ret = match ret {
Ok(r) => r,
Err(ref err) => {
handle_panic(Python::assume_gil_acquired(), err);
2017-05-26 22:33:34 +00:00
-1
2017-05-17 06:43:39 +00:00
}
};
mem::forget(guard);
ret
}
2017-05-26 23:51:33 +00:00
pub unsafe fn cb_meth<F, R>(location: &str, f: F) -> *mut ffi::PyObject
where F: for<'p> FnOnce(Python<'p>) -> *mut ffi::PyObject,
F: panic::UnwindSafe
{
let guard = AbortOnDrop(location);
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
f(py)
});
let ret = match ret {
Ok(r) => r,
Err(ref err) => {
handle_panic(Python::assume_gil_acquired(), err);
ptr::null_mut()
}
};
mem::forget(guard);
ret
}
#[inline]
pub unsafe fn cb_convert<C, T>(_c: C, py: Python, value: PyResult<T>) -> C::R
where C: CallbackConverter<T>
{
match value {
Ok(val) => C::convert(val, py),
Err(e) => {
e.restore(py);
C::error_value()
}
}
}
pub fn handle_panic(_py: Python, _panic: &any::Any) {
2017-05-17 06:43:39 +00:00
unsafe {
2017-05-25 03:31:51 +00:00
ffi::PyErr_SetString(ffi::PyExc_SystemError, "Rust panic\0".as_ptr() as *const i8);
2017-05-17 06:43:39 +00:00
}
}
pub struct AbortOnDrop<'a>(pub &'a str);
impl <'a> Drop for AbortOnDrop<'a> {
fn drop(&mut self) {
use std::io::Write;
let _ = writeln!(&mut io::stderr(), "Cannot unwind out of {}", self.0);
unsafe { libc::abort() }
}
}