From 5c74f55862e0b87121b5e2bbc78d4150a01225e5 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 25 Jun 2015 00:02:56 +0200 Subject: [PATCH] Change `py_func!(py, f)` to `py_fn(f)`. --- extensions/hello.rs | 13 +-- extensions/inheritance.rs | 6 +- src/err.rs | 12 --- src/lib.rs | 170 +++++++++++++++++++++++++++----------- src/objects/module.rs | 23 ------ src/pythonrun.rs | 3 +- src/rustobject/method.rs | 22 ----- 7 files changed, 128 insertions(+), 121 deletions(-) diff --git a/extensions/hello.rs b/extensions/hello.rs index 4bf2b358..78a66f40 100644 --- a/extensions/hello.rs +++ b/extensions/hello.rs @@ -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)) -} - diff --git a/extensions/inheritance.rs b/extensions/inheritance.rs index fc093d54..1aa03d4a 100644 --- a/extensions/inheritance.rs +++ b/extensions/inheritance.rs @@ -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()); } diff --git a/src/err.rs b/src/err.rs index 47d1ecfc..8ddcf426 100644 --- a/src/err.rs +++ b/src/err.rs @@ -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 { - 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> { diff --git a/src/lib.rs b/src/lib.rs index cee432e0..497eacdb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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(_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::() { + 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::() { + 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"\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())) + } + } } diff --git a/src/objects/module.rs b/src/objects/module.rs index a45423b3..8ce0a9cf 100644 --- a/src/objects/module.rs +++ b/src/objects/module.rs @@ -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(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::()); - init(py, &module) - } - - #[doc(hidden)] - #[cfg(feature="python3-sys")] - pub fn _init(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 moduleā€˜s namespace; /// this object is the same as the __dict__ attribute of the module object. pub fn dict(&self) -> PyDict<'p> { diff --git a/src/pythonrun.rs b/src/pythonrun.rs index 35df534e..716f18fa 100644 --- a/src/pythonrun.rs +++ b/src/pythonrun.rs @@ -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 Sync for GILProtected { } impl GILProtected { #[inline] - pub const fn new(data: T) -> GILProtected { + pub fn new(data: T) -> GILProtected { GILProtected { data: data } } diff --git a/src/rustobject/method.rs b/src/rustobject/method.rs index 47fb0418..6713c8a9 100644 --- a/src/rustobject/method.rs +++ b/src/rustobject/method.rs @@ -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>> = GILProtected::new(RefCell::new(None)); - -fn get_method_descriptor_type<'p>(py: Python<'p>) -> PyRustType<'p, MethodDescriptor<'p>> { - METHOD_DESCRIPTOR.get(py); -} - -*/