Add support for Rust stable.

All functions that depend on PyObject having the same memory layout
as *mut ffi::PyObject should now be hidden behind #[cfg(feature="nightly")].
This commit is contained in:
Daniel Grunwald 2016-03-06 01:08:40 +01:00
parent ad7f43efc7
commit d705620502
10 changed files with 77 additions and 26 deletions

View File

@ -5,6 +5,7 @@ python:
- "3.4"
- "3.5"
env:
- RUST_VERSION=1.7
- RUST_VERSION=nightly
sudo: false
install:

View File

@ -34,7 +34,10 @@ build:
test: build
cargo test $(CARGO_FLAGS)
ifeq ($(NIGHTLY),1)
# ast-json output is only supported on nightly
python$(PY) tests/check_symbols.py
endif
doc: build
cargo doc --no-deps $(CARGO_FLAGS)

View File

@ -13,7 +13,7 @@ py_module_initializer!(hello, inithello, PyInit_hello, |py, m| {
fn run(py: Python, args: &PyTuple, kwargs: Option<&PyDict>) -> PyResult<PyObject> {
println!("Rust says: Hello Python!");
for arg in args.as_slice() {
for arg in args.iter(py) {
println!("Rust got {}", arg);
}
if let Some(kwargs) = kwargs {

View File

@ -199,7 +199,7 @@ impl PyErr {
Err(_) =>
match self.ptype.cast_as::<PyClass>(py) {
Ok(_) => py.get_type::<PyClass>(),
Err(_) => py.None().get_type().clone_ref(py)
Err(_) => py.None().get_type(py)
}
}
}
@ -209,7 +209,7 @@ impl PyErr {
pub fn get_type(&self, py: Python) -> PyType {
match self.ptype.cast_as::<PyType>(py) {
Ok(t) => t.clone_ref(py),
Err(_) => py.None().get_type().clone_ref(py)
Err(_) => py.None().get_type(py)
}
}

View File

@ -59,20 +59,27 @@ macro_rules! py_fn_wrap {
let _guard = $crate::_detail::PanicGuard::with_message(
concat!("Rust panic in py_fn!(", stringify!($f), ")"));
let $py: $crate::Python = $crate::_detail::bounded_assume_gil_acquired(&args);
let $args: &$crate::PyTuple = $crate::PyObject::borrow_from_ptr(&args).unchecked_cast_as();
let $kwargs: Option<&$crate::PyDict> = $crate::_detail::get_kwargs(&kwargs);
$crate::_detail::result_to_ptr($py, $body)
let args: $crate::PyTuple = $crate::PyObject::from_borrowed_ptr($py, args).unchecked_cast_into();
let kwargs: Option<$crate::PyDict> = $crate::_detail::get_kwargs($py, kwargs);
let ret = {
let $args = &args;
let $kwargs = kwargs.as_ref();
$crate::_detail::result_to_ptr($py, $body)
};
$crate::PyDrop::release_ref(args, $py);
$crate::PyDrop::release_ref(kwargs, $py);
ret
}
wrap::<()>
}};
}
#[inline]
pub unsafe fn get_kwargs(ptr: &*mut ffi::PyObject) -> Option<&PyDict> {
pub unsafe fn get_kwargs(py: Python, ptr: *mut ffi::PyObject) -> Option<PyDict> {
if ptr.is_null() {
None
} else {
Some(PyObject::borrow_from_ptr(ptr).unchecked_cast_as())
Some(PyObject::from_borrowed_ptr(py, ptr).unchecked_cast_into())
}
}

View File

@ -16,9 +16,12 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#![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 (#5016)
#![cfg_attr(feature="nightly", feature(
unsafe_no_drop_flag, filling_drop, // (#5016)
// ^ These two are crucial so that PyObject<'p> is binary compatible with
// `*mut ffi::PyObject`, which we use for efficient slice access and in
// some other cases.
const_fn, // for GILProtected::new (#24111)
shared, // for std::ptr::Shared (#27730)
))]

View File

@ -42,8 +42,8 @@ use err::PyResult;
/// on `PyObject` to convert to more specific object types.
///
/// Most of the interesting methods are provided by the [ObjectProtocol trait](trait.ObjectProtocol.html).
#[unsafe_no_drop_flag]
#[repr(C)]
#[cfg_attr(feature="nightly", unsafe_no_drop_flag)]
#[cfg_attr(feature="nightly", repr(C))]
pub struct PyObject {
// PyObject owns one reference to the *PyObject
// ptr is not null
@ -60,6 +60,7 @@ unsafe impl Sync for PyObject {}
/// Dropping a `PyObject` decrements the reference count on the object by 1.
impl Drop for PyObject {
#[inline]
#[cfg(feature="nightly")]
fn drop(&mut self) {
// TODO: remove `if` when #[unsafe_no_drop_flag] disappears
if unpack_shared(self.ptr) as usize != mem::POST_DROP_USIZE {
@ -67,6 +68,14 @@ impl Drop for PyObject {
unsafe { ffi::Py_DECREF(unpack_shared(self.ptr)); }
}
}
#[inline]
#[cfg(not(feature="nightly"))]
fn drop(&mut self) {
let _gil_guard = Python::acquire_gil();
unsafe { ffi::Py_DECREF(unpack_shared(self.ptr)); }
}
}
#[inline]
@ -198,6 +207,7 @@ impl PyObject {
/// Transmutes an FFI pointer to `&PyObject`.
/// Undefined behavior if the pointer is NULL or invalid.
#[inline]
#[cfg(feature="nightly")] // needs unsafe_no_drop_flag
pub unsafe fn borrow_from_ptr<'a>(ptr : &'a *mut ffi::PyObject) -> &'a PyObject {
debug_assert!(!ptr.is_null());
mem::transmute(ptr)
@ -206,6 +216,7 @@ impl PyObject {
/// Transmutes a slice of owned FFI pointers to `&[PyObject]`.
/// Undefined behavior if any pointer in the slice is NULL or invalid.
#[inline]
#[cfg(feature="nightly")] // needs unsafe_no_drop_flag
pub unsafe fn borrow_from_owned_ptr_slice<'a>(ptr : &'a [*mut ffi::PyObject]) -> &'a [PyObject] {
mem::transmute(ptr)
}
@ -217,12 +228,9 @@ impl PyObject {
}
/// Gets the Python type object for this object's type.
#[inline]
pub fn get_type(&self) -> &PyType {
pub fn get_type(&self, py: Python) -> PyType {
unsafe {
let t : &*mut ffi::PyTypeObject = &(*self.as_ptr()).ob_type;
let t : &*mut ffi::PyObject = mem::transmute(t);
PyObject::borrow_from_ptr(t).unchecked_cast_as()
PyType::from_type_ptr(py, (*self.as_ptr()).ob_type)
}
}
@ -291,6 +299,7 @@ impl PartialEq for PyObject {
impl Eq for PyObject { }
#[test]
#[cfg(feature="nightly")] // needs unsafe_no_drop_flag
fn test_sizeof() {
// should be a static_assert, but size_of is not a compile-time const
// these are necessary for the transmutes in this module

View File

@ -72,6 +72,7 @@ impl PyTuple {
}
#[inline]
#[cfg(feature="nightly")] // needs unsafe_no_drop_flag
pub fn as_slice<'a>(&'a self) -> &'a [PyObject] {
// This is safe because PyObject has the same memory layout as *mut ffi::PyObject,
// and because tuples are immutable.
@ -97,6 +98,7 @@ impl PyTuple {
}
}
#[cfg(feature="nightly")] // needs unsafe_no_drop_flag
impl ::std::ops::Index<usize> for PyTuple {
type Output = PyObject;
@ -106,6 +108,7 @@ impl ::std::ops::Index<usize> for PyTuple {
}
}
#[cfg(feature="nightly")] // needs unsafe_no_drop_flag
impl <'a> IntoIterator for &'a PyTuple {
type Item = &'a PyObject;
type IntoIter = slice::Iter<'a, PyObject>;

View File

@ -38,10 +38,19 @@ macro_rules! py_method_wrap {
let _guard = $crate::_detail::PanicGuard::with_message(
concat!("Rust panic in py_method!(", stringify!($f), ")"));
let $py: $crate::Python = $crate::_detail::bounded_assume_gil_acquired(&args);
let $slf: &$crate::PyObject = $crate::PyObject::borrow_from_ptr(&slf);
let $args: &$crate::PyTuple = $crate::PyObject::borrow_from_ptr(&args).unchecked_cast_as();
let $kwargs: Option<&$crate::PyDict> = $crate::_detail::get_kwargs(&kwargs);
$crate::_detail::result_to_ptr($py, $body)
let slf: $crate::PyObject = $crate::PyObject::from_borrowed_ptr($py, slf);
let args: $crate::PyTuple = $crate::PyObject::from_borrowed_ptr($py, args).unchecked_cast_into();
let kwargs: Option<$crate::PyDict> = $crate::_detail::get_kwargs($py, kwargs);
let ret = {
let $slf = &slf;
let $args = &args;
let $kwargs = kwargs.as_ref();
$crate::_detail::result_to_ptr($py, $body)
};
$crate::PyDrop::release_ref(slf, $py);
$crate::PyDrop::release_ref(args, $py);
$crate::PyDrop::release_ref(kwargs, $py);
ret
}
wrap::<()>
}};
@ -211,10 +220,19 @@ macro_rules! py_class_method_wrap {
let _guard = $crate::_detail::PanicGuard::with_message(
concat!("Rust panic in py_class_method!(", stringify!($f), ")"));
let $py: $crate::Python = $crate::_detail::bounded_assume_gil_acquired(&args);
let $slf: &$crate::PyType = $crate::PyObject::borrow_from_ptr(&slf).unchecked_cast_as();
let $args: &$crate::PyTuple = $crate::PyObject::borrow_from_ptr(&args).unchecked_cast_as();
let $kwargs: Option<&$crate::PyDict> = $crate::_detail::get_kwargs(&kwargs);
$crate::_detail::result_to_ptr($py, $body)
let slf: $crate::PyType = $crate::PyObject::from_borrowed_ptr($py, slf).unchecked_cast_into();
let args: $crate::PyTuple = $crate::PyObject::from_borrowed_ptr($py, args).unchecked_cast_into();
let kwargs: Option<$crate::PyDict> = $crate::_detail::get_kwargs($py, kwargs);
let ret = {
let $slf = &slf;
let $args = &args;
let $kwargs = kwargs.as_ref();
$crate::_detail::result_to_ptr($py, $body)
};
$crate::PyDrop::release_ref(slf, $py);
$crate::PyDrop::release_ref(args, $py);
$crate::PyDrop::release_ref(kwargs, $py);
ret
}
wrap::<()>
}};

View File

@ -140,8 +140,15 @@ impl <T, B> PythonBaseObject for PyRustObject<T, B> where T: 'static + Send, B:
}
unsafe fn dealloc(py: Python, obj: *mut ffi::PyObject) {
// drop_in_place() isn't available in 1.7 stable;
// it'll be stabilized in 1.8
#[cfg(not(feature="nightly"))]
use std::ptr::read as drop_ptr_target;
#[cfg(feature="nightly")]
use std::ptr::drop_in_place as drop_ptr_target;
let offset = PyRustObject::<T, B>::offset() as isize;
ptr::read_and_drop((obj as *mut u8).offset(offset) as *mut T);
drop_ptr_target((obj as *mut u8).offset(offset) as *mut T);
B::dealloc(py, obj)
}
}