Don't flatten the rustobject module + started implementing the py_class!() macro.

This commit is contained in:
Daniel Grunwald 2016-03-06 06:29:43 +01:00
parent 506443210a
commit acc5712536
11 changed files with 335 additions and 52 deletions

View file

@ -51,6 +51,13 @@ stamps/test-custom_type: custom_type.out
@grep "a() was called with self=42" custom_type.out >/dev/null @grep "a() was called with self=42" custom_type.out >/dev/null
endif endif
custom_class.out: custom_class.so
python$(PY) -c "import custom_class; custom_class.MyType(42).a()" 2>&1 | tee $@
all: stamps/test-custom_class
stamps/test-custom_class: custom_class.out
@grep "a() was called with self=42" custom_class.out >/dev/null
all: inheritance.so all: inheritance.so

View file

@ -0,0 +1,33 @@
#![crate_type = "dylib"]
#![feature(const_fn)]
#![feature(trace_macros)]
#[macro_use] extern crate cpython;
use cpython::{Python, PyObject, PyRustObject, PyRustType, PyResult, GILProtected};
use std::cell::RefCell;
static MY_TYPE: GILProtected<RefCell<Option<PyRustType<i32>>>> = GILProtected::new(RefCell::new(None));
py_module_initializer!(custom_type, initcustom_type, PyInit_custom_type, |py, m| {
try!(m.add(py, "__doc__", "Module documentation string"));
try!(m.add_class::<MyType>(py));
Ok(())
});
trace_macros!(true);
py_class!(class MyType, data: i32, |py| {
});
fn new(py: Python, arg: i32) -> PyResult<PyRustObject<i32>> {
Ok(MY_TYPE.get(py).borrow().as_ref().unwrap().create_instance(py, arg, ()))
}
fn a(py: Python, slf: &PyRustObject<i32>) -> PyResult<PyObject> {
println!("a() was called with self={:?}", slf.get(py));
Ok(py.None())
}

View file

@ -3,7 +3,8 @@
#[macro_use] extern crate cpython; #[macro_use] extern crate cpython;
use cpython::{Python, PyObject, PyRustObject, PyRustType, PyResult, GILProtected}; use cpython::{Python, PyObject, PyResult, GILProtected};
use cpython::rustobject::{PyRustType, PyRustObject};
use std::cell::RefCell; use std::cell::RefCell;
static MY_TYPE: GILProtected<RefCell<Option<PyRustType<i32>>>> = GILProtected::new(RefCell::new(None)); static MY_TYPE: GILProtected<RefCell<Option<PyRustType<i32>>>> = GILProtected::new(RefCell::new(None));

View file

@ -20,7 +20,7 @@ use std::{mem, ptr};
use python::{Python, PythonObject}; use python::{Python, PythonObject};
use objects::{PyObject, PyTuple, PyDict, PyString, exc}; use objects::{PyObject, PyTuple, PyDict, PyString, exc};
use conversion::ToPyObject; use conversion::ToPyObject;
use rustobject::typebuilder; use rustobject::{PyRustTypeBuilder, TypeConstructor};
use ffi; use ffi;
use err::{self, PyResult}; use err::{self, PyResult};
@ -173,7 +173,7 @@ impl ToPyObject for PyFn {
} }
} }
unsafe impl typebuilder::TypeConstructor for PyFn { unsafe impl TypeConstructor for PyFn {
fn tp_new(&self) -> ffi::newfunc { fn tp_new(&self) -> ffi::newfunc {
unsafe { unsafe {
mem::transmute::<ffi::PyCFunction, ffi::newfunc>((*self.0).ml_meth.unwrap()) mem::transmute::<ffi::PyCFunction, ffi::newfunc>((*self.0).ml_meth.unwrap())

View file

@ -93,12 +93,10 @@ extern crate python3_sys as ffi;
pub use ffi::Py_ssize_t; pub use ffi::Py_ssize_t;
pub use err::{PyErr, PyResult}; pub use err::{PyErr, PyResult};
pub use objects::*; pub use objects::*;
pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject, PyClone, PyDrop}; pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectDowncastError, PythonObjectWithTypeObject, PyClone, PyDrop};
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python}; pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python};
pub use conversion::{ExtractPyObject, ToPyObject}; pub use conversion::{ExtractPyObject, ToPyObject};
pub use objectprotocol::{ObjectProtocol}; pub use objectprotocol::{ObjectProtocol};
pub use rustobject::{PyRustType, PyRustObject};
pub use rustobject::typebuilder::PyRustTypeBuilder;
#[cfg(feature="python27-sys")] #[cfg(feature="python27-sys")]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
@ -128,7 +126,7 @@ mod objectprotocol;
mod pythonrun; mod pythonrun;
pub mod argparse; pub mod argparse;
mod function; mod function;
mod rustobject; pub mod rustobject;
/// Private re-exports for macros. Do not use. /// Private re-exports for macros. Do not use.
#[doc(hidden)] #[doc(hidden)]
@ -142,7 +140,6 @@ pub mod _detail {
pub use abort_on_panic::PanicGuard; pub use abort_on_panic::PanicGuard;
pub use err::from_owned_ptr_or_panic; pub use err::from_owned_ptr_or_panic;
pub use function::{get_kwargs, result_to_ptr, py_fn_impl}; pub use function::{get_kwargs, result_to_ptr, py_fn_impl};
pub use rustobject::method::{py_method_impl, py_class_method_impl};
/// assume_gil_acquired(), but the returned Python<'p> is bounded by the scope /// assume_gil_acquired(), but the returned Python<'p> is bounded by the scope
/// of the referenced variable. /// of the referenced variable.

View file

@ -109,9 +109,9 @@ impl PyModule {
/// This is a convenience function that creates a new `PyRustTypeBuilder` and /// This is a convenience function that creates a new `PyRustTypeBuilder` and
/// sets `new_type.__module__` to this module's name. /// sets `new_type.__module__` to this module's name.
/// The new type will be added to this module when `finish()` is called on the builder. /// The new type will be added to this module when `finish()` is called on the builder.
pub fn add_type<'p, T>(&self, py: Python<'p>, name: &str) -> ::rustobject::typebuilder::PyRustTypeBuilder<'p, T> pub fn add_type<'p, T>(&self, py: Python<'p>, name: &str) -> ::rustobject::PyRustTypeBuilder<'p, T>
where T: 'static + Send { where T: 'static + Send {
::rustobject::typebuilder::new_typebuilder_for_module(py, self, name) ::rustobject::new_typebuilder_for_module(py, self, name)
} }
} }

235
src/rustobject/class.rs Normal file
View file

@ -0,0 +1,235 @@
// Copyright (c) 2016 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
use python::{self, Python};
use objects::PyType;
use err::PyResult;
/// Trait implemented by the types produced by the `py_class!()` macro.
pub trait PythonObjectFromPyClassMacro : python::PythonObjectWithTypeObject {
fn initialize(py: Python) -> PyResult<PyType>;
}
/**
# Example
```
#[macro_use] extern crate cpython;
use cpython::Python;
py_class!(pub class MyType, data: i32, |py| {
});
fn main() {
let gil = Python::acquire_gil();
let py = gil.python();
let type_obj = py.get_type::<MyType>();
MyType::create_instance(py, 42);
}
``` */
#[macro_export]
macro_rules! py_class {
(pub class $name:ident, $data_name:ident : $data_ty:ty, |$py: ident| { $( $body:tt )* }) => (
pub struct $name($crate::rustobject::PyRustObject<$data_ty>);
py_class_impl!($name, $data_name: $data_ty,
($data_name: $data_ty),
($data_name, ()),
|$py| { $( $body )* });
);
(pub class $name:ident($base:ty), $data_name:ident : $data_ty:ty, |$py: ident| { $( $body:tt )* }) => (
pub struct $name($crate::rustobject::PyRustObject<$data_ty, $base>);
py_class_impl!($name, $data_name: $data_ty,
($data_name: $data_ty, base_data: <$base as $crate::rustobject::BaseObject>::InitType),
($data_name, base_data),
|$py| { $( $body )* });
);
(class $name:ident, $data_name:ident : $data_ty:ty, |$py: ident| { $( $body:tt )* }) => (
struct $name($crate::rustobject::PyRustObject<$data_ty>);
py_class_impl!($name, $data_name: $data_ty,
($data_name: $data_ty),
($data_name, ()),
|$py| { $( $body )* });
);
(class $name:ident($base:ty), $data_name:ident : $data_ty:ty, |$py: ident| { $( $body:tt )* }) => (
struct $name($crate::rustobject::PyRustObject<$data_ty, $base>);
py_class_impl!($name, $data_name: $data_ty,
($data_name: $data_ty, base_data: <$base as $crate::rustobject::BaseObject>::InitType),
($data_name, base_data),
|$py| { $( $body )* });
);
}
#[macro_export]
#[doc(hidden)]
macro_rules! py_class_impl {
(
$name:ident,
$data_name:ident : $data_ty:ty,
( $( $param_name:ident : $param_ty:ty ),* ),
$init_val:expr,
|$py: ident| { $( $body:tt )* }
) => (
impl $name {
pub fn $data_name<'a>(&'a self, py: $crate::Python<'a>) -> &'a $data_ty {
self.0.get(py)
}
pub fn create_instance(py: $crate::Python, $( $param_name : $param_ty ),* ) -> $name {
// hide statics in create_instance to avoid name conflicts
static mut type_ptr: *mut $crate::_detail::ffi::PyTypeObject = 0 as *mut _;
static mut init_active: bool = false;
py_class_impl_py_object!($name, type_ptr);
impl $crate::rustobject::PythonObjectFromPyClassMacro for $name {
fn initialize(py: Python) -> $crate::PyResult<$crate::PyType> {
unsafe {
if !type_ptr.is_null() {
return Ok(py.get_type::<$name>());
}
assert!(!init_active, "Reentrancy detected: already initializing class $name");
init_active = true;
let result = init(py);
if let Ok(ref ty) = result {
type_ptr = ty.as_type_ptr();
}
init_active = false;
result
}
}
}
fn init($py: Python) -> $crate::PyResult<$crate::PyType> {
let b = $crate::rustobject::PyRustTypeBuilder::<$name>::new(
$py, stringify!($name));
//let b = b.base(); TODO inheritance
//py_class_parse_body!($py, b, $( $body )* );
///b.finish()
unimplemented!()
}
py_class_create_instance_impl!(py, $name, $init_val)
}
}
);
}
#[macro_export]
#[doc(hidden)]
macro_rules! py_class_create_instance_impl {
($py: expr, $name: ident, $data: expr) => {{
let type_obj = $py.get_type::<$name>();
let obj = unsafe { $crate::rustobject::BaseObject::alloc($py, &type_obj, $data) };
$crate::PyDrop::release_ref(type_obj, $py);
$name(obj.expect("Allocation failed"))
}}
}
#[macro_export]
#[doc(hidden)]
macro_rules! py_class_impl_py_object {
($name:ident, $type_obj:expr) => (
impl $crate::PythonObject for $name {
#[inline]
fn as_object(&self) -> &$crate::PyObject {
$crate::PythonObject::as_object(&self.0)
}
#[inline]
fn into_object(self) -> $crate::PyObject {
$crate::PythonObject::into_object(self.0)
}
/// Unchecked downcast from PyObject to Self.
/// Undefined behavior if the input object does not have the expected type.
#[inline]
unsafe fn unchecked_downcast_from(obj: $crate::PyObject) -> Self {
$name($crate::PythonObject::unchecked_downcast_from(obj))
}
/// Unchecked downcast from PyObject to Self.
/// Undefined behavior if the input object does not have the expected type.
#[inline]
unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a $crate::PyObject) -> &'a Self {
::std::mem::transmute(obj)
}
}
impl $crate::PythonObjectWithCheckedDowncast for $name {
fn downcast_from<'p>(py: $crate::Python<'p>, obj: $crate::PyObject) -> Result<$name, $crate::PythonObjectDowncastError<'p>> {
unsafe {
if $crate::_detail::ffi::PyObject_TypeCheck(obj.as_ptr(), type_ptr) != 0 {
Ok($name($crate::PythonObject::unchecked_downcast_from(obj)))
} else {
Err($crate::PythonObjectDowncastError(py))
}
}
}
fn downcast_borrow_from<'a, 'p>(py: $crate::Python<'p>, obj: &'a $crate::PyObject) -> Result<&'a $name, $crate::PythonObjectDowncastError<'p>> {
unsafe {
if $crate::_detail::ffi::PyObject_TypeCheck(obj.as_ptr(), type_ptr) != 0 {
Ok(::std::mem::transmute(obj))
} else {
Err($crate::PythonObjectDowncastError(py))
}
}
}
}
impl $crate::PythonObjectWithTypeObject for $name {
fn type_object(py: $crate::Python) -> $crate::PyType {
unsafe {
if type_ptr.is_null() {
// automatically initialize the class on-demand
<$name as $crate::rustobject::PythonObjectFromPyClassMacro>::initialize(py).unwrap()
} else {
$crate::PyType::from_type_ptr(py, type_ptr)
}
}
}
}
impl $crate::ToPyObject for $name {
type ObjectType = $name;
#[inline]
fn to_py_object(&self, py: $crate::Python) -> $name {
$crate::PyClone::clone_ref(self, py)
}
#[inline]
fn into_py_object(self, _py: $crate::Python) -> $name {
self
}
#[inline]
fn with_borrowed_ptr<F, R>(&self, _py: $crate::Python, f: F) -> R
where F: FnOnce(*mut $crate::_detail::ffi::PyObject) -> R
{
f($crate::PythonObject::as_object(&self.0).as_ptr())
}
}
)
}
#[macro_export]
#[doc(hidden)]
macro_rules! py_class_parse_body {
() => (
);
}

View file

@ -76,9 +76,9 @@ macro_rules! py_method_wrap {
/// # Example /// # Example
/// ``` /// ```
/// #[macro_use] extern crate cpython; /// #[macro_use] extern crate cpython;
/// use cpython::{Python, PythonObject, PyResult, PyErr, ObjectProtocol, /// use cpython::{Python, PythonObject, PyResult, PyErr, ObjectProtocol};
/// PyRustObject, PyRustTypeBuilder};
/// use cpython::{exc}; /// use cpython::{exc};
/// use cpython::rustobject::{PyRustObject, PyRustTypeBuilder};
/// ///
/// fn mul(py: Python, slf: &PyRustObject<i32>, arg: i32) -> PyResult<i32> { /// fn mul(py: Python, slf: &PyRustObject<i32>, arg: i32) -> PyResult<i32> {
/// match slf.get(py).checked_mul(arg) { /// match slf.get(py).checked_mul(arg) {
@ -106,7 +106,7 @@ macro_rules! py_method {
$f(py, slf, args, kwargs) $f(py, slf, args, kwargs)
}); });
unsafe { unsafe {
$crate::_detail::py_method_impl::py_method_impl( $crate::rustobject::py_method_impl::py_method_impl(
py_method_def!($f, 0, wrap), $f) py_method_def!($f, 0, wrap), $f)
} }
}); });
@ -124,6 +124,7 @@ macro_rules! py_method {
}) })
} }
/// Return value of `py_method!()` macro.
pub struct MethodDescriptor<T>(*mut ffi::PyMethodDef, marker::PhantomData<fn(&T)>); pub struct MethodDescriptor<T>(*mut ffi::PyMethodDef, marker::PhantomData<fn(&T)>);
#[doc(hidden)] #[doc(hidden)]
@ -148,15 +149,15 @@ pub mod py_method_impl {
#[doc(hidden)] #[doc(hidden)]
macro_rules! py_method_call_impl { macro_rules! py_method_call_impl {
( $def:expr, $f:ident ( ) ) ( $def:expr, $f:ident ( ) )
=> { $crate::_detail::py_method_impl::py_method_impl_0($def, $f) }; => { $crate::rustobject::py_method_impl::py_method_impl_0($def, $f) };
( $def:expr, $f:ident ( $n1:ident : $t1:ty ) ) ( $def:expr, $f:ident ( $n1:ident : $t1:ty ) )
=> { $crate::_detail::py_method_impl::py_method_impl_1($def, $f) }; => { $crate::rustobject::py_method_impl::py_method_impl_1($def, $f) };
( $def:expr, $f:ident ( $n1:ident : $t1:ty, $n2:ident : $t2:ty ) ) ( $def:expr, $f:ident ( $n1:ident : $t1:ty, $n2:ident : $t2:ty ) )
=> { $crate::_detail::py_method_impl::py_method_impl_2($def, $f) }; => { $crate::rustobject::py_method_impl::py_method_impl_2($def, $f) };
( $def:expr, $f:ident ( $n1:ident : $t1:ty, $n2:ident : $t2:ty, $n3:ident : $t3:ty ) ) ( $def:expr, $f:ident ( $n1:ident : $t1:ty, $n2:ident : $t2:ty, $n3:ident : $t3:ty ) )
=> { $crate::_detail::py_method_impl::py_method_impl_3($def, $f) }; => { $crate::rustobject::py_method_impl::py_method_impl_3($def, $f) };
( $def:expr, $f:ident ( $n1:ident : $t1:ty, $n2:ident : $t2:ty, $n3:ident : $t3:ty, $n4:ident : $t4:ty ) ) ( $def:expr, $f:ident ( $n1:ident : $t1:ty, $n2:ident : $t2:ty, $n3:ident : $t3:ty, $n4:ident : $t4:ty ) )
=> { $crate::_detail::py_method_impl::py_method_impl_4($def, $f) }; => { $crate::rustobject::py_method_impl::py_method_impl_4($def, $f) };
} }
pub unsafe fn py_method_impl_0<T, R>( pub unsafe fn py_method_impl_0<T, R>(
@ -258,8 +259,8 @@ macro_rules! py_class_method_wrap {
/// # Example /// # Example
/// ``` /// ```
/// #[macro_use] extern crate cpython; /// #[macro_use] extern crate cpython;
/// use cpython::{Python, PythonObject, PyResult, ObjectProtocol, PyType, /// use cpython::{Python, PythonObject, PyResult, ObjectProtocol, PyType, NoArgs};
/// PyRustTypeBuilder, NoArgs}; /// use cpython::rustobject::PyRustTypeBuilder;
/// ///
/// fn method(py: Python, cls: &PyType) -> PyResult<i32> { /// fn method(py: Python, cls: &PyType) -> PyResult<i32> {
/// Ok(42) /// Ok(42)
@ -282,7 +283,7 @@ macro_rules! py_class_method {
$f(py, cls, args, kwargs) $f(py, cls, args, kwargs)
}); });
unsafe { unsafe {
$crate::_detail::py_class_method_impl( $crate::rustobject::py_class_method_impl(
py_method_def!($f, $crate::_detail::ffi::METH_CLASS, wrap)) py_method_def!($f, $crate::_detail::ffi::METH_CLASS, wrap))
} }
}); });
@ -292,15 +293,17 @@ macro_rules! py_class_method {
( $($pname : $ptype),* ) { $f( py, cls, $($pname),* ) }) ( $($pname : $ptype),* ) { $f( py, cls, $($pname),* ) })
}); });
unsafe { unsafe {
$crate::_detail::py_class_method_impl( $crate::rustobject::py_class_method_impl(
py_method_def!($f, $crate::_detail::ffi::METH_CLASS, wrap)) py_method_def!($f, $crate::_detail::ffi::METH_CLASS, wrap))
} }
}); });
} }
/// The return type of the `py_class_method!()` macro.
pub struct ClassMethodDescriptor(*mut ffi::PyMethodDef); pub struct ClassMethodDescriptor(*mut ffi::PyMethodDef);
#[inline] #[inline]
#[doc(hidden)]
pub unsafe fn py_class_method_impl(def: *mut ffi::PyMethodDef) -> ClassMethodDescriptor { pub unsafe fn py_class_method_impl(def: *mut ffi::PyMethodDef) -> ClassMethodDescriptor {
ClassMethodDescriptor(def) ClassMethodDescriptor(def)
} }

View file

@ -24,15 +24,18 @@ use objects::{PyObject, PyType};
use std::{mem, ops, ptr, marker}; use std::{mem, ops, ptr, marker};
use err::{self, PyResult}; use err::{self, PyResult};
// note: because rustobject isn't public, these modules aren't visible mod typebuilder;
// outside the crate mod method;
pub mod typebuilder; mod class;
pub mod method;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
/// A PythonObject that is usable as a base type with PyTypeBuilder::base(). pub use self::typebuilder::*;
pub trait PythonBaseObject : PythonObject { pub use self::method::*;
pub use self::class::*;
/// A PythonObject that is usable as a base type with `PyRustTypeBuilder::base()`.
pub trait BaseObject : PythonObject {
/// Gets the size of the object, in bytes. /// Gets the size of the object, in bytes.
fn size() -> usize; fn size() -> usize;
@ -50,7 +53,7 @@ pub trait PythonBaseObject : PythonObject {
unsafe fn dealloc(py: Python, ptr: *mut ffi::PyObject); unsafe fn dealloc(py: Python, ptr: *mut ffi::PyObject);
} }
impl PythonBaseObject for PyObject { impl BaseObject for PyObject {
#[inline] #[inline]
fn size() -> usize { fn size() -> usize {
mem::size_of::<ffi::PyObject>() mem::size_of::<ffi::PyObject>()
@ -85,13 +88,13 @@ impl PythonBaseObject for PyObject {
/// Note that this type effectively acts like `Rc<T>`, /// Note that this type effectively acts like `Rc<T>`,
/// except that the reference counting is done by the Python runtime. /// except that the reference counting is done by the Python runtime.
#[repr(C)] #[repr(C)]
pub struct PyRustObject<T, B = PyObject> where T: 'static + Send, B: PythonBaseObject { pub struct PyRustObject<T, B = PyObject> where T: 'static + Send, B: BaseObject {
obj: PyObject, obj: PyObject,
/// The PyRustObject acts like a shared reference to the contained T. /// The PyRustObject acts like a shared reference to the contained T.
t: marker::PhantomData<&'static (T, B)> t: marker::PhantomData<&'static (T, B)>
} }
impl <T, B> PyRustObject<T, B> where T: 'static + Send, B: PythonBaseObject { impl <T, B> PyRustObject<T, B> where T: 'static + Send, B: BaseObject {
#[inline] // this function can usually be reduced to a compile-time constant #[inline] // this function can usually be reduced to a compile-time constant
fn offset() -> usize { fn offset() -> usize {
let align = mem::align_of::<T>(); let align = mem::align_of::<T>();
@ -124,7 +127,7 @@ impl <T, B> PyRustObject<T, B> where T: 'static + Send, B: PythonBaseObject {
} }
} }
impl <T, B> PythonBaseObject for PyRustObject<T, B> where T: 'static + Send, B: PythonBaseObject { impl <T, B> BaseObject for PyRustObject<T, B> where T: 'static + Send, B: BaseObject {
#[inline] #[inline]
fn size() -> usize { fn size() -> usize {
PyRustObject::<T, B>::offset() + mem::size_of::<T>() PyRustObject::<T, B>::offset() + mem::size_of::<T>()
@ -153,7 +156,7 @@ impl <T, B> PythonBaseObject for PyRustObject<T, B> where T: 'static + Send, B:
} }
} }
impl <T, B> ToPyObject for PyRustObject<T, B> where T: 'static + Send, B: PythonBaseObject { impl <T, B> ToPyObject for PyRustObject<T, B> where T: 'static + Send, B: BaseObject {
type ObjectType = PyObject; type ObjectType = PyObject;
#[inline] #[inline]
@ -173,7 +176,7 @@ impl <T, B> ToPyObject for PyRustObject<T, B> where T: 'static + Send, B: Python
} }
} }
impl <T, B> PythonObject for PyRustObject<T, B> where T: 'static + Send, B: PythonBaseObject { impl <T, B> PythonObject for PyRustObject<T, B> where T: 'static + Send, B: BaseObject {
#[inline] #[inline]
fn as_object(&self) -> &PyObject { fn as_object(&self) -> &PyObject {
&self.obj &self.obj
@ -206,21 +209,22 @@ impl <T, B> PythonObject for PyRustObject<T, B> where T: 'static + Send, B: Pyth
/// Serves as a Python type object, and can be used to construct /// Serves as a Python type object, and can be used to construct
/// `PyRustObject<T>` instances. /// `PyRustObject<T>` instances.
#[repr(C)] #[repr(C)]
pub struct PyRustType<T, B = PyObject> where T: 'static + Send, B: PythonBaseObject { pub struct PyRustType<T, B = PyObject> where T: 'static + Send, B: BaseObject {
type_obj: PyType, type_obj: PyType,
phantom: marker::PhantomData<&'static (B, T)> phantom: marker::PhantomData<&'static (B, T)>
} }
impl <T, B> PyRustType<T, B> where T: 'static + Send, B: PythonBaseObject { impl <T, B> PyRustType<T, B> where T: 'static + Send, B: BaseObject {
/// Creates a PyRustObject instance from a value. /// Creates a PyRustObject instance from a value.
pub fn create_instance(&self, py: Python, val: T, base_val: B::InitType) -> PyRustObject<T, B> { pub fn create_instance(&self, py: Python, val: T, base_val: B::InitType) -> PyRustObject<T, B> {
unsafe { unsafe {
PythonBaseObject::alloc(py, &self.type_obj, (val, base_val)).unwrap() BaseObject::alloc(py, &self.type_obj, (val, base_val))
.expect("Allocation failure")
} }
} }
} }
impl <T, B> ops::Deref for PyRustType<T, B> where T: 'static + Send, B: PythonBaseObject { impl <T, B> ops::Deref for PyRustType<T, B> where T: 'static + Send, B: BaseObject {
type Target = PyType; type Target = PyType;
#[inline] #[inline]
@ -229,7 +233,7 @@ impl <T, B> ops::Deref for PyRustType<T, B> where T: 'static + Send, B: PythonBa
} }
} }
impl <T, B> ToPyObject for PyRustType<T, B> where T: 'static + Send, B: PythonBaseObject { impl <T, B> ToPyObject for PyRustType<T, B> where T: 'static + Send, B: BaseObject {
type ObjectType = PyType; type ObjectType = PyType;
#[inline] #[inline]
@ -249,7 +253,7 @@ impl <T, B> ToPyObject for PyRustType<T, B> where T: 'static + Send, B: PythonBa
} }
} }
impl <T, B> PythonObject for PyRustType<T, B> where T: 'static + Send, B: PythonBaseObject { impl <T, B> PythonObject for PyRustType<T, B> where T: 'static + Send, B: BaseObject {
#[inline] #[inline]
fn as_object(&self) -> &PyObject { fn as_object(&self) -> &PyObject {
self.type_obj.as_object() self.type_obj.as_object()

View file

@ -18,7 +18,7 @@
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use {Python, NoArgs, PythonObject, PyRustTypeBuilder}; use {Python, NoArgs, PythonObject, rustobject};
#[test] #[test]
fn rustobject_calls_drop() { fn rustobject_calls_drop() {
@ -34,7 +34,8 @@ fn rustobject_calls_drop() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let t = PyRustTypeBuilder::<MyObj>::new(py, "TypeWithDrop").finish().unwrap(); let t = rustobject::PyRustTypeBuilder::<MyObj>::new(py, "TypeWithDrop")
.finish().unwrap();
let drop_called = Arc::new(AtomicBool::new(false)); let drop_called = Arc::new(AtomicBool::new(false));
let inst = t.create_instance(py, MyObj { drop_called: drop_called.clone() }, ()); let inst = t.create_instance(py, MyObj { drop_called: drop_called.clone() }, ());
@ -48,7 +49,8 @@ fn rustobject_calls_drop() {
fn no_init_from_python() { fn no_init_from_python() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let t = PyRustTypeBuilder::<i32>::new(py, "MyType").finish().unwrap(); let t = rustobject::PyRustTypeBuilder::<i32>::new(py, "MyType")
.finish().unwrap();
assert!(t.call(py, &NoArgs, None).is_err()); assert!(t.call(py, &NoArgs, None).is_err());
} }
@ -57,7 +59,8 @@ fn no_init_from_python() {
fn heaptype_refcount() { fn heaptype_refcount() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let t = PyRustTypeBuilder::<i32>::new(py, "MyType").finish().unwrap(); let t = rustobject::PyRustTypeBuilder::<i32>::new(py, "MyType")
.finish().unwrap();
// TODO: investigate why the refcnt isn't 1. // TODO: investigate why the refcnt isn't 1.
//assert_eq!(1, t.as_object().get_refcnt()); //assert_eq!(1, t.as_object().get_refcnt());
let old_refcnt = t.as_object().get_refcnt(py); let old_refcnt = t.as_object().get_refcnt(py);

View file

@ -20,16 +20,16 @@ use std::{ptr, mem, marker};
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use libc; use libc;
use ffi; use ffi;
use python::{Python, ToPythonPointer, PythonObject, PyClone}; use python::{self, Python, ToPythonPointer, PythonObject, PyClone};
use conversion::ToPyObject; use conversion::ToPyObject;
use objects::{PyObject, PyType, PyString, PyModule, PyDict}; use objects::{PyObject, PyType, PyString, PyModule, PyDict};
use err::{self, PyResult}; use err::{self, PyResult};
use objectprotocol::ObjectProtocol; use objectprotocol::ObjectProtocol;
use super::{PythonBaseObject, PyRustObject, PyRustType, method}; use super::{BaseObject, PyRustObject, PyRustType, method};
#[repr(C)] #[repr(C)]
#[must_use] #[must_use]
pub struct PyRustTypeBuilder<'p, T, B = PyObject> where T: 'static + Send, B: PythonBaseObject { pub struct PyRustTypeBuilder<'p, T, B = PyObject> where T: 'static + Send, B: BaseObject {
// In Python 2.7, we can create a new PyHeapTypeObject and fill it. // In Python 2.7, we can create a new PyHeapTypeObject and fill it.
/// The python type object under construction. /// The python type object under construction.
@ -84,7 +84,7 @@ unsafe extern "C" fn disabled_tp_new_callback
} }
unsafe extern "C" fn tp_dealloc_callback<T, B>(obj: *mut ffi::PyObject) unsafe extern "C" fn tp_dealloc_callback<T, B>(obj: *mut ffi::PyObject)
where T: 'static + Send, B: PythonBaseObject { where T: 'static + Send, B: BaseObject {
abort_on_panic!({ abort_on_panic!({
let py = Python::assume_gil_acquired(); let py = Python::assume_gil_acquired();
PyRustObject::<T, B>::dealloc(py, obj) PyRustObject::<T, B>::dealloc(py, obj)
@ -147,7 +147,7 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send {
/// Sets the base class that this type is inheriting from. /// Sets the base class that this type is inheriting from.
pub fn base<T2, B2>(self, base_type: &PyRustType<T2, B2>) pub fn base<T2, B2>(self, base_type: &PyRustType<T2, B2>)
-> PyRustTypeBuilder<'p, T, PyRustObject<T2, B2>> -> PyRustTypeBuilder<'p, T, PyRustObject<T2, B2>>
where T2: 'static + Send, B2: PythonBaseObject where T2: 'static + Send, B2: BaseObject
{ {
// Ensure we can't change the base after any callbacks are registered. // Ensure we can't change the base after any callbacks are registered.
assert!(self.can_change_base, assert!(self.can_change_base,
@ -155,7 +155,7 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send {
#[cfg(feature="python27-sys")] #[cfg(feature="python27-sys")]
fn base_impl<'p, T, T2, B2>(slf: PyRustTypeBuilder<'p, T>, base_type: &PyRustType<T2, B2>) fn base_impl<'p, T, T2, B2>(slf: PyRustTypeBuilder<'p, T>, base_type: &PyRustType<T2, B2>)
-> PyRustTypeBuilder<'p, T, PyRustObject<T2, B2>> -> PyRustTypeBuilder<'p, T, PyRustObject<T2, B2>>
where T: 'static + Send, T2: 'static + Send, B2: PythonBaseObject where T: 'static + Send, T2: 'static + Send, B2: BaseObject
{ {
unsafe { unsafe {
ffi::Py_XDECREF((*slf.ht).ht_type.tp_base as *mut ffi::PyObject); ffi::Py_XDECREF((*slf.ht).ht_type.tp_base as *mut ffi::PyObject);
@ -175,7 +175,7 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send {
#[cfg(feature="python3-sys")] #[cfg(feature="python3-sys")]
fn base_impl<'p, T, T2, B2>(slf: PyRustTypeBuilder<'p, T>, base_type: &PyRustType<T2, B2>) fn base_impl<'p, T, T2, B2>(slf: PyRustTypeBuilder<'p, T>, base_type: &PyRustType<T2, B2>)
-> PyRustTypeBuilder<'p, T, PyRustObject<T2, B2>> -> PyRustTypeBuilder<'p, T, PyRustObject<T2, B2>>
where T: 'static + Send, T2: 'static + Send, B2: PythonBaseObject where T: 'static + Send, T2: 'static + Send, B2: BaseObject
{ {
let base_type_obj: &PyType = base_type; let base_type_obj: &PyType = base_type;
return PyRustTypeBuilder { return PyRustTypeBuilder {
@ -195,7 +195,7 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send {
} }
} }
impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: PythonBaseObject { impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: BaseObject {
/// Retrieves the type dictionary of the type being built. /// Retrieves the type dictionary of the type being built.
#[cfg(feature="python27-sys")] #[cfg(feature="python27-sys")]