Change `py_func!(py, f)` to `py_fn(f)`.

This commit is contained in:
Daniel Grunwald 2015-06-25 00:02:56 +02:00
parent 6e1fc35177
commit 5c74f55862
7 changed files with 128 additions and 121 deletions

View File

@ -4,12 +4,12 @@
#[macro_use] extern crate cpython;
use cpython::{PyObject, PyResult, PyModule, Python, PyTuple};
use cpython::{PyObject, PyResult,Python, PyTuple};
py_module_initializer!(hello, |py, m| {
py_module_initializer!(hello, |_py, m| {
try!(m.add("__doc__", "Module documentation string"));
try!(m.add("run", py_func!(py, run)));
try!(add_val(py, &m));
try!(m.add("run", py_fn!(run)));
try!(m.add("val", py_fn!(val)));
Ok(())
});
@ -25,8 +25,3 @@ fn val<'p>(_: Python<'p>, _: &PyTuple<'p>) -> PyResult<'p, i32> {
Ok(42)
}
// Workaround for Rust #24561
fn add_val<'p>(py: Python<'p>, m: &PyModule<'p>) -> PyResult<'p, ()> {
m.add("val", py_func!(py, val))
}

View File

@ -4,18 +4,16 @@
#[macro_use] extern crate cpython;
//use cpython::{PyObject, PyResult, PyModule, Python, PyTuple, PythonObject};
py_module_initializer!(inheritance, |_py, m| {
try!(m.add("__doc__", "Module documentation string"));
let B = try!(
let base_class = try!(
m.add_type::<()>("BaseClass")
.doc("Type doc string")
.finish());
for i in 1..10 {
try!(
m.add_type::<()>(&format!("C{}", i))
.base(&B)
.base(&base_class)
.doc(&format!("Derived class #{}", i))
.finish());
}

View File

@ -257,18 +257,6 @@ pub unsafe fn from_owned_ptr_or_panic(py : Python, p : *mut ffi::PyObject) -> Py
}
}
/// Construct PyObject from the result of a python FFI call that returns a borrowed reference.
/// Returns `Err(PyErr)` if the pointer is `null`.
/// Unsafe because the pointer might be invalid.
#[inline]
pub unsafe fn result_from_borrowed_ptr(py : Python, p : *mut ffi::PyObject) -> PyResult<PyObject> {
if p.is_null() {
Err(PyErr::fetch(py))
} else {
Ok(PyObject::from_borrowed_ptr(py, p))
}
}
pub unsafe fn result_cast_from_owned_ptr<'p, T>(py : Python<'p>, p : *mut ffi::PyObject) -> PyResult<'p, T>
where T: ::python::PythonObjectWithCheckedDowncast<'p>
{

View File

@ -16,7 +16,6 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#![feature(const_fn)]
#![feature(unsafe_no_drop_flag)] // crucial so that PyObject<'p> is binary compatible with *mut ffi::PyObject
#![feature(filling_drop)] // necessary to avoid segfault with unsafe_no_drop_flag
#![feature(optin_builtin_traits)] // for opting out of Sync/Send
@ -96,6 +95,8 @@ pub use rustobject::{PyRustType, PyRustObject};
#[cfg(feature="python27-sys")]
pub use rustobject::typebuilder::PyRustTypeBuilder;
use std::ptr;
/// Constructs a `&'static CStr` literal.
macro_rules! cstr(
($s: tt) => (
@ -122,12 +123,20 @@ pub mod _detail {
pub use libc;
pub use abort_on_panic::PanicGuard;
pub use err::from_owned_ptr_or_panic;
/// assume_gil_acquired(), but the returned Python<'p> is bounded by the scope
/// of the referenced variable.
/// This is useful in macros to ensure that type inference doesn't set 'p == 'static.
#[inline]
pub unsafe fn bounded_assume_gil_acquired<T>(_bound: &T) -> super::Python {
super::Python::assume_gil_acquired()
}
}
/// Expands to an `extern "C"` function that allows python to load
/// the rust code as a python extension module.
///
/// The macro takes three arguments:
/// Macro syntax: `py_module_initializer!($name, |$py, $m| $body)`
///
/// 1. The module name as a string literal.
/// 2. The name of the init function as an identifier.
@ -148,7 +157,7 @@ pub mod _detail {
///
/// py_module_initializer!(example, |py, m| {
/// try!(m.add("__doc__", "Module documentation string"));
/// try!(m.add("run", py_func!(py, run)));
/// try!(m.add("run", py_fn!(run)));
/// Ok(())
/// });
///
@ -174,18 +183,42 @@ pub mod _detail {
#[macro_export]
#[cfg(feature="python27-sys")]
macro_rules! py_module_initializer {
($name: ident, $init: expr) => ( interpolate_idents! {
($name: ident, |$py_id: ident, $m_id: ident| $body: expr) => ( interpolate_idents! {
#[[no_mangle]]
#[allow(non_snake_case)]
pub extern "C" fn [ init $name ]() {
let _guard = $crate::_detail::PanicGuard::with_message(
concat!("Rust panic in ", stringify!($name), " module initializer"));
let py = unsafe { $crate::Python::assume_gil_acquired() };
let name = unsafe { ::std::ffi::CStr::from_ptr(concat!(stringify!($name), "\0").as_ptr() as *const _) };
match $crate::PyModule::_init(py, name, $init) {
Ok(()) => (),
Err(e) => e.restore()
pub unsafe extern "C" fn [ init $name ]() {
// Nest init function so that $body isn't in unsafe context
fn init<'pmisip>($py_id: $crate::Python<'pmisip>, $m_id: &$crate::PyModule<'pmisip>) -> $crate::PyResult<'pmisip, ()> {
$body
}
let name = concat!(stringify!($name), "\0").as_ptr() as *const _;
$crate::py_module_initializer_impl(name, init)
}
})
}
#[doc(hidden)]
#[cfg(feature="python27-sys")]
pub unsafe fn py_module_initializer_impl(
name: *const libc::c_char,
init: for<'p> fn(Python<'p>, &PyModule<'p>) -> PyResult<'p, ()>
) {
abort_on_panic!({
let py = Python::assume_gil_acquired();
let module = ffi::Py_InitModule(name, ptr::null_mut());
if module.is_null() { return; }
let module = match PyObject::from_borrowed_ptr(py, module).cast_into::<PyModule>() {
Ok(m) => m,
Err(e) => {
PyErr::from(e).restore();
return;
}
};
match init(py, &module) {
Ok(()) => (),
Err(e) => e.restore()
}
})
}
@ -193,13 +226,14 @@ macro_rules! py_module_initializer {
#[macro_export]
#[cfg(feature="python3-sys")]
macro_rules! py_module_initializer {
($name: ident, $init: expr) => ( interpolate_idents! {
($name: ident, |$py_id: ident, $m_id: ident| $body: expr) => ( interpolate_idents! {
#[[no_mangle]]
#[allow(non_snake_case)]
pub extern "C" fn [ PyInit_ $name ]() -> *mut $crate::_detail::ffi::PyObject {
let _guard = $crate::_detail::PanicGuard::with_message(
concat!("Rust panic in ", stringify!($name), " module initializer"));
let py = unsafe { $crate::Python::assume_gil_acquired() };
pub unsafe extern "C" fn [ PyInit_ $name ]() -> *mut $crate::_detail::ffi::PyObject {
// Nest init function so that $body isn't in unsafe context
fn init<'pmisip>($py_id: $crate::Python<'pmisip>, $m_id: &$crate::PyModule<'pmisip>) -> $crate::PyResult<'pmisip, ()> {
$body
}
static mut module_def: $crate::_detail::ffi::PyModuleDef = $crate::_detail::ffi::PyModuleDef {
m_base: $crate::_detail::ffi::PyModuleDef_HEAD_INIT,
m_name: 0 as *const _,
@ -213,15 +247,36 @@ macro_rules! py_module_initializer {
};
// We can't convert &'static str to *const c_char within a static initializer,
// so we'll do it here in the module initialization:
unsafe {
module_def.m_name = concat!(stringify!($name), "\0").as_ptr() as *const _;
module_def.m_name = concat!(stringify!($name), "\0").as_ptr() as *const _;
$crate::py_module_initializer_impl(&mut module_def, init)
}
})
}
#[doc(hidden)]
#[cfg(feature="python3-sys")]
pub unsafe fn py_module_initializer_impl(
def: *mut ffi::PyModuleDef,
init: for<'p> fn(Python<'p>, &PyModule<'p>) -> PyResult<'p, ()>
) -> *mut ffi::PyObject {
abort_on_panic!({
let py = Python::assume_gil_acquired();
let module = ffi::PyModule_Create(def);
if module.is_null() { return module; }
let module = match PyObject::from_owned_ptr(py, module).cast_into::<PyModule>() {
Ok(m) => m,
Err(e) => {
PyErr::from(e).restore();
return ptr::null_mut();
}
match $crate::PyModule::_init(py, unsafe { &mut module_def }, $init) {
Ok(m) => $crate::ToPythonPointer::steal_ptr(m),
Err(e) => {
e.restore();
return ::std::ptr::null_mut();
}
};
match init(py, &module) {
Ok(()) => module.steal_ptr(),
Err(e) => {
e.restore();
return ptr::null_mut();
}
}
})
@ -229,27 +284,26 @@ macro_rules! py_module_initializer {
/// Creates a python callable object that invokes a Rust function.
///
/// Arguments:
/// As arguments, takes the name of a rust function with the signature
/// `<'p>(Python<'p>, &PyTuple<'p>) -> PyResult<'p, T>`
/// for some `T` that implements `ToPyObject`.
///
/// Returns a type that implements `ToPyObject` by producing a python callable.
///
/// 1. The `Python<'p>` marker, to ensure this macro is only used while holding the GIL.
/// 2. A Rust function with the signature `<'p>(Python<'p>, &PyTuple<'p>) -> PyResult<'p, T>`
/// for some `T` that implements `ToPyObject`.
///
/// See `py_module_initializer!` for example usage.
///
/// # Panic
/// May panic when python runs out of memory.
#[macro_export]
macro_rules! py_func {
($py: expr, $f: expr) => ({
unsafe extern "C" fn wrap_py_func
(_slf: *mut $crate::_detail::ffi::PyObject, args: *mut $crate::_detail::ffi::PyObject)
-> *mut $crate::_detail::ffi::PyObject {
let _guard = $crate::_detail::PanicGuard::with_message("Rust panic in py_func!");
let py = $crate::Python::assume_gil_acquired();
macro_rules! py_fn {
($f: ident) => ( interpolate_idents! {{
unsafe extern "C" fn [ wrap_ $f ](
_slf: *mut $crate::_detail::ffi::PyObject,
args: *mut $crate::_detail::ffi::PyObject)
-> *mut $crate::_detail::ffi::PyObject
{
let _guard = $crate::_detail::PanicGuard::with_message("Rust panic in py_fn!");
let py = $crate::_detail::bounded_assume_gil_acquired(&args);
let args = $crate::PyObject::from_borrowed_ptr(py, args);
let args: &$crate::PyTuple = $crate::PythonObject::unchecked_downcast_borrow_from(&args);
match $f(py, args) {
let args = <$crate::PyTuple as $crate::PythonObject>::unchecked_downcast_from(args);
match $f(py, &args) {
Ok(val) => {
let obj = $crate::ToPyObject::into_py_object(val, py);
return $crate::ToPythonPointer::steal_ptr(obj);
@ -260,18 +314,34 @@ macro_rules! py_func {
}
}
}
static mut method_def: $crate::_detail::ffi::PyMethodDef = $crate::_detail::ffi::PyMethodDef {
static mut [ method_def_ $f ]: $crate::_detail::ffi::PyMethodDef = $crate::_detail::ffi::PyMethodDef {
//ml_name: bytes!(stringify!($f), "\0"),
ml_name: b"<rust function>\0" as *const u8 as *const $crate::_detail::libc::c_char,
ml_meth: Some(wrap_py_func),
ml_meth: Some([ wrap_ $f ]),
ml_flags: $crate::_detail::ffi::METH_VARARGS,
ml_doc: 0 as *const $crate::_detail::libc::c_char
};
let py: Python = $py;
unsafe {
let obj = $crate::_detail::ffi::PyCFunction_New(&mut method_def, ::std::ptr::null_mut());
$crate::_detail::from_owned_ptr_or_panic(py, obj)
}
})
unsafe { $crate::PyRustFunctionHandle::new(&mut [ method_def_ $f ]) }
}})
}
#[doc(hidden)]
pub struct PyRustFunctionHandle(*mut ffi::PyMethodDef);
impl PyRustFunctionHandle {
#[inline]
pub unsafe fn new(p: *mut ffi::PyMethodDef) -> PyRustFunctionHandle {
PyRustFunctionHandle(p)
}
}
impl <'p> ToPyObject<'p> for PyRustFunctionHandle {
type ObjectType = PyObject<'p>;
fn to_py_object(&self, py: Python<'p>) -> PyObject<'p> {
unsafe {
err::from_owned_ptr_or_panic(py, ffi::PyCFunction_New(self.0, ptr::null_mut()))
}
}
}

View File

@ -44,29 +44,6 @@ impl <'p> PyModule<'p> {
}
}
// Helper method for module_initializer!() macro, do not use directly!
#[doc(hidden)]
#[cfg(feature="python27-sys")]
pub fn _init<F>(py: Python<'p>, name: &CStr, init: F) -> PyResult<'p, ()>
where F: FnOnce(Python<'p>, &PyModule<'p>) -> PyResult<'p, ()> {
let module = try!(unsafe {
err::result_from_borrowed_ptr(py, ffi::Py_InitModule(name.as_ptr(), std::ptr::null_mut()))
});
let module = try!(module.cast_into::<PyModule>());
init(py, &module)
}
#[doc(hidden)]
#[cfg(feature="python3-sys")]
pub fn _init<F>(py: Python<'p>, def: *mut ffi::PyModuleDef, init: F) -> PyResult<'p, PyModule<'p>>
where F: FnOnce(Python<'p>, &PyModule<'p>) -> PyResult<'p, ()> {
let module: PyModule = try!(unsafe {
err::result_cast_from_owned_ptr(py, ffi::PyModule_Create(def))
});
try!(init(py, &module));
Ok(module)
}
/// Return the dictionary object that implements modules namespace;
/// this object is the same as the __dict__ attribute of the module object.
pub fn dict(&self) -> PyDict<'p> {

View File

@ -70,6 +70,7 @@ pub struct GILGuard {
/// GILGuard is not Send because the GIL must be released
/// by the same thread that acquired it.
impl !Send for GILGuard {}
impl !Sync for GILGuard {}
/// The Drop implementation for GILGuard will release the GIL.
impl Drop for GILGuard {
@ -106,7 +107,7 @@ unsafe impl<T: Send> Sync for GILProtected<T> { }
impl <T> GILProtected<T> {
#[inline]
pub const fn new(data: T) -> GILProtected<T> {
pub fn new(data: T) -> GILProtected<T> {
GILProtected { data: data }
}

View File

@ -1,24 +1,2 @@
use std::ptr;
use std::cell::RefCell;
use python::Python;
use pythonrun::{GILProtected};
use objects::{PyObject, PyType};
use ffi;
use super::PyRustType;
use super::typebuilder::PyRustTypeBuilder;
/*
struct MethodDescriptor<'p> {
ty: PyType<'p>,
name: PyObject<'p>
// d_method
}
static METHOD_DESCRIPTOR: GILProtected<RefCell<Option<SendablePyObject>>> = GILProtected::new(RefCell::new(None));
fn get_method_descriptor_type<'p>(py: Python<'p>) -> PyRustType<'p, MethodDescriptor<'p>> {
METHOD_DESCRIPTOR.get(py);
}
*/