Don't flatten the rustobject module + started implementing the py_class!() macro.
This commit is contained in:
parent
506443210a
commit
acc5712536
|
@ -51,6 +51,13 @@ stamps/test-custom_type: custom_type.out
|
|||
@grep "a() was called with self=42" custom_type.out >/dev/null
|
||||
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
|
||||
|
||||
|
||||
|
|
33
extensions/custom_class.rs
Normal file
33
extensions/custom_class.rs
Normal 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())
|
||||
}
|
||||
|
|
@ -3,7 +3,8 @@
|
|||
|
||||
#[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;
|
||||
|
||||
static MY_TYPE: GILProtected<RefCell<Option<PyRustType<i32>>>> = GILProtected::new(RefCell::new(None));
|
||||
|
|
|
@ -20,7 +20,7 @@ use std::{mem, ptr};
|
|||
use python::{Python, PythonObject};
|
||||
use objects::{PyObject, PyTuple, PyDict, PyString, exc};
|
||||
use conversion::ToPyObject;
|
||||
use rustobject::typebuilder;
|
||||
use rustobject::{PyRustTypeBuilder, TypeConstructor};
|
||||
use ffi;
|
||||
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 {
|
||||
unsafe {
|
||||
mem::transmute::<ffi::PyCFunction, ffi::newfunc>((*self.0).ml_meth.unwrap())
|
||||
|
|
|
@ -93,12 +93,10 @@ extern crate python3_sys as ffi;
|
|||
pub use ffi::Py_ssize_t;
|
||||
pub use err::{PyErr, PyResult};
|
||||
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 conversion::{ExtractPyObject, ToPyObject};
|
||||
pub use objectprotocol::{ObjectProtocol};
|
||||
pub use rustobject::{PyRustType, PyRustObject};
|
||||
pub use rustobject::typebuilder::PyRustTypeBuilder;
|
||||
|
||||
#[cfg(feature="python27-sys")]
|
||||
#[allow(non_camel_case_types)]
|
||||
|
@ -128,7 +126,7 @@ mod objectprotocol;
|
|||
mod pythonrun;
|
||||
pub mod argparse;
|
||||
mod function;
|
||||
mod rustobject;
|
||||
pub mod rustobject;
|
||||
|
||||
/// Private re-exports for macros. Do not use.
|
||||
#[doc(hidden)]
|
||||
|
@ -142,7 +140,6 @@ pub mod _detail {
|
|||
pub use abort_on_panic::PanicGuard;
|
||||
pub use err::from_owned_ptr_or_panic;
|
||||
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
|
||||
/// of the referenced variable.
|
||||
|
|
|
@ -109,9 +109,9 @@ impl PyModule {
|
|||
/// This is a convenience function that creates a new `PyRustTypeBuilder` and
|
||||
/// 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.
|
||||
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 {
|
||||
::rustobject::typebuilder::new_typebuilder_for_module(py, self, name)
|
||||
::rustobject::new_typebuilder_for_module(py, self, name)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
235
src/rustobject/class.rs
Normal file
235
src/rustobject/class.rs
Normal 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 {
|
||||
() => (
|
||||
);
|
||||
}
|
||||
|
|
@ -76,9 +76,9 @@ macro_rules! py_method_wrap {
|
|||
/// # Example
|
||||
/// ```
|
||||
/// #[macro_use] extern crate cpython;
|
||||
/// use cpython::{Python, PythonObject, PyResult, PyErr, ObjectProtocol,
|
||||
/// PyRustObject, PyRustTypeBuilder};
|
||||
/// use cpython::{Python, PythonObject, PyResult, PyErr, ObjectProtocol};
|
||||
/// use cpython::{exc};
|
||||
/// use cpython::rustobject::{PyRustObject, PyRustTypeBuilder};
|
||||
///
|
||||
/// fn mul(py: Python, slf: &PyRustObject<i32>, arg: i32) -> PyResult<i32> {
|
||||
/// match slf.get(py).checked_mul(arg) {
|
||||
|
@ -106,7 +106,7 @@ macro_rules! py_method {
|
|||
$f(py, slf, args, kwargs)
|
||||
});
|
||||
unsafe {
|
||||
$crate::_detail::py_method_impl::py_method_impl(
|
||||
$crate::rustobject::py_method_impl::py_method_impl(
|
||||
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)>);
|
||||
|
||||
#[doc(hidden)]
|
||||
|
@ -148,15 +149,15 @@ pub mod py_method_impl {
|
|||
#[doc(hidden)]
|
||||
macro_rules! py_method_call_impl {
|
||||
( $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 ) )
|
||||
=> { $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 ) )
|
||||
=> { $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 ) )
|
||||
=> { $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 ) )
|
||||
=> { $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>(
|
||||
|
@ -258,8 +259,8 @@ macro_rules! py_class_method_wrap {
|
|||
/// # Example
|
||||
/// ```
|
||||
/// #[macro_use] extern crate cpython;
|
||||
/// use cpython::{Python, PythonObject, PyResult, ObjectProtocol, PyType,
|
||||
/// PyRustTypeBuilder, NoArgs};
|
||||
/// use cpython::{Python, PythonObject, PyResult, ObjectProtocol, PyType, NoArgs};
|
||||
/// use cpython::rustobject::PyRustTypeBuilder;
|
||||
///
|
||||
/// fn method(py: Python, cls: &PyType) -> PyResult<i32> {
|
||||
/// Ok(42)
|
||||
|
@ -282,7 +283,7 @@ macro_rules! py_class_method {
|
|||
$f(py, cls, args, kwargs)
|
||||
});
|
||||
unsafe {
|
||||
$crate::_detail::py_class_method_impl(
|
||||
$crate::rustobject::py_class_method_impl(
|
||||
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),* ) })
|
||||
});
|
||||
unsafe {
|
||||
$crate::_detail::py_class_method_impl(
|
||||
$crate::rustobject::py_class_method_impl(
|
||||
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);
|
||||
|
||||
#[inline]
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn py_class_method_impl(def: *mut ffi::PyMethodDef) -> ClassMethodDescriptor {
|
||||
ClassMethodDescriptor(def)
|
||||
}
|
||||
|
|
|
@ -24,15 +24,18 @@ use objects::{PyObject, PyType};
|
|||
use std::{mem, ops, ptr, marker};
|
||||
use err::{self, PyResult};
|
||||
|
||||
// note: because rustobject isn't public, these modules aren't visible
|
||||
// outside the crate
|
||||
pub mod typebuilder;
|
||||
pub mod method;
|
||||
mod typebuilder;
|
||||
mod method;
|
||||
mod class;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
/// A PythonObject that is usable as a base type with PyTypeBuilder::base().
|
||||
pub trait PythonBaseObject : PythonObject {
|
||||
pub use self::typebuilder::*;
|
||||
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.
|
||||
fn size() -> usize;
|
||||
|
||||
|
@ -50,7 +53,7 @@ pub trait PythonBaseObject : PythonObject {
|
|||
unsafe fn dealloc(py: Python, ptr: *mut ffi::PyObject);
|
||||
}
|
||||
|
||||
impl PythonBaseObject for PyObject {
|
||||
impl BaseObject for PyObject {
|
||||
#[inline]
|
||||
fn size() -> usize {
|
||||
mem::size_of::<ffi::PyObject>()
|
||||
|
@ -85,13 +88,13 @@ impl PythonBaseObject for PyObject {
|
|||
/// Note that this type effectively acts like `Rc<T>`,
|
||||
/// except that the reference counting is done by the Python runtime.
|
||||
#[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,
|
||||
/// The PyRustObject acts like a shared reference to the contained T.
|
||||
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
|
||||
fn offset() -> usize {
|
||||
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]
|
||||
fn size() -> usize {
|
||||
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;
|
||||
|
||||
#[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]
|
||||
fn as_object(&self) -> &PyObject {
|
||||
&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
|
||||
/// `PyRustObject<T>` instances.
|
||||
#[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,
|
||||
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.
|
||||
pub fn create_instance(&self, py: Python, val: T, base_val: B::InitType) -> PyRustObject<T, B> {
|
||||
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;
|
||||
|
||||
#[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;
|
||||
|
||||
#[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]
|
||||
fn as_object(&self) -> &PyObject {
|
||||
self.type_obj.as_object()
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use {Python, NoArgs, PythonObject, PyRustTypeBuilder};
|
||||
use {Python, NoArgs, PythonObject, rustobject};
|
||||
|
||||
#[test]
|
||||
fn rustobject_calls_drop() {
|
||||
|
@ -34,7 +34,8 @@ fn rustobject_calls_drop() {
|
|||
|
||||
let gil = Python::acquire_gil();
|
||||
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 inst = t.create_instance(py, MyObj { drop_called: drop_called.clone() }, ());
|
||||
|
@ -48,7 +49,8 @@ fn rustobject_calls_drop() {
|
|||
fn no_init_from_python() {
|
||||
let gil = Python::acquire_gil();
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -57,7 +59,8 @@ fn no_init_from_python() {
|
|||
fn heaptype_refcount() {
|
||||
let gil = Python::acquire_gil();
|
||||
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.
|
||||
//assert_eq!(1, t.as_object().get_refcnt());
|
||||
let old_refcnt = t.as_object().get_refcnt(py);
|
||||
|
|
|
@ -20,16 +20,16 @@ use std::{ptr, mem, marker};
|
|||
use std::ffi::{CStr, CString};
|
||||
use libc;
|
||||
use ffi;
|
||||
use python::{Python, ToPythonPointer, PythonObject, PyClone};
|
||||
use python::{self, Python, ToPythonPointer, PythonObject, PyClone};
|
||||
use conversion::ToPyObject;
|
||||
use objects::{PyObject, PyType, PyString, PyModule, PyDict};
|
||||
use err::{self, PyResult};
|
||||
use objectprotocol::ObjectProtocol;
|
||||
use super::{PythonBaseObject, PyRustObject, PyRustType, method};
|
||||
use super::{BaseObject, PyRustObject, PyRustType, method};
|
||||
|
||||
#[repr(C)]
|
||||
#[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.
|
||||
|
||||
/// 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)
|
||||
where T: 'static + Send, B: PythonBaseObject {
|
||||
where T: 'static + Send, B: BaseObject {
|
||||
abort_on_panic!({
|
||||
let py = Python::assume_gil_acquired();
|
||||
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.
|
||||
pub fn base<T2, B2>(self, base_type: &PyRustType<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.
|
||||
assert!(self.can_change_base,
|
||||
|
@ -155,7 +155,7 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send {
|
|||
#[cfg(feature="python27-sys")]
|
||||
fn base_impl<'p, T, T2, B2>(slf: PyRustTypeBuilder<'p, T>, base_type: &PyRustType<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 {
|
||||
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")]
|
||||
fn base_impl<'p, T, T2, B2>(slf: PyRustTypeBuilder<'p, T>, base_type: &PyRustType<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;
|
||||
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.
|
||||
#[cfg(feature="python27-sys")]
|
||||
|
|
Loading…
Reference in a new issue