Split rustobject module.
This commit is contained in:
parent
ba0643c11c
commit
6e1fc35177
|
@ -16,6 +16,7 @@
|
|||
// 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
|
||||
|
@ -87,11 +88,13 @@ pub use ffi::Py_ssize_t;
|
|||
pub use err::{PyErr, PyResult};
|
||||
pub use objects::*;
|
||||
pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject, ToPythonPointer};
|
||||
pub use pythonrun::{GILGuard, prepare_freethreaded_python};
|
||||
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python};
|
||||
pub use conversion::{FromPyObject, ToPyObject};
|
||||
pub use objectprotocol::{ObjectProtocol};
|
||||
#[cfg(feature="python27-sys")]
|
||||
pub use rustobject::{PyRustTypeBuilder, PyRustType, PyRustObject};
|
||||
pub use rustobject::{PyRustType, PyRustObject};
|
||||
#[cfg(feature="python27-sys")]
|
||||
pub use rustobject::typebuilder::PyRustTypeBuilder;
|
||||
|
||||
/// Constructs a `&'static CStr` literal.
|
||||
macro_rules! cstr(
|
||||
|
|
|
@ -123,9 +123,9 @@ impl <'p> PyModule<'p> {
|
|||
/// 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.
|
||||
#[cfg(feature="python27-sys")]
|
||||
pub fn add_type<T>(&self, name: &str) -> ::rustobject::PyRustTypeBuilder<'p, T>
|
||||
pub fn add_type<T>(&self, name: &str) -> ::rustobject::typebuilder::PyRustTypeBuilder<'p, T>
|
||||
where T: 'p + Send {
|
||||
::rustobject::new_typebuilder_for_module(self, name)
|
||||
::rustobject::typebuilder::new_typebuilder_for_module(self, name)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
|
||||
use std::sync::{Once, ONCE_INIT};
|
||||
use ffi;
|
||||
use python::Python;
|
||||
use python::{Python, ToPythonPointer};
|
||||
use objects::PyObject;
|
||||
|
||||
static START: Once = ONCE_INIT;
|
||||
|
||||
|
@ -89,8 +90,34 @@ impl GILGuard {
|
|||
}
|
||||
|
||||
/// Retrieves the marker type that proves that the GIL was acquired.
|
||||
#[inline]
|
||||
pub fn python<'p>(&'p self) -> Python<'p> {
|
||||
unsafe { Python::assume_gil_acquired() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Mutex-like wrapper object for data that is protected by the python GIL.
|
||||
pub struct GILProtected<T> {
|
||||
data: T
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for GILProtected<T> { }
|
||||
unsafe impl<T: Send> Sync for GILProtected<T> { }
|
||||
|
||||
impl <T> GILProtected<T> {
|
||||
#[inline]
|
||||
pub const fn new(data: T) -> GILProtected<T> {
|
||||
GILProtected { data: data }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get<'p>(&'p self, py: Python<'p>) -> &'p T {
|
||||
&self.data
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_inner(self) -> T {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
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);
|
||||
}
|
||||
|
||||
*/
|
||||
|
|
@ -19,10 +19,14 @@
|
|||
use libc;
|
||||
use ffi;
|
||||
use python::{Python, ToPythonPointer, PythonObject};
|
||||
use conversion::ToPyObject;
|
||||
use objects::{PyObject, PyType, PyString, PyModule, PyDict};
|
||||
use std::{mem, ops, ptr, marker};
|
||||
use err::{self, PyResult};
|
||||
|
||||
pub mod typebuilder;
|
||||
mod method;
|
||||
|
||||
/// A PythonObject that is usable as a base type with PyTypeBuilder::base().
|
||||
pub trait PythonBaseObject<'p> : PythonObject<'p> {
|
||||
/// Gets the size of the object, in bytes.
|
||||
|
@ -57,7 +61,14 @@ impl <'p> PythonBaseObject<'p> for PyObject<'p> {
|
|||
}
|
||||
|
||||
unsafe fn dealloc(ptr: *mut ffi::PyObject) {
|
||||
((*ffi::Py_TYPE(ptr)).tp_free.unwrap())(ptr as *mut libc::c_void);
|
||||
let ty = ffi::Py_TYPE(ptr);
|
||||
((*ty).tp_free.unwrap())(ptr as *mut libc::c_void);
|
||||
// For heap types, tp_alloc calls INCREF on the type objects,
|
||||
// but tp_free points directly to the memory deallocator and does not call DECREF.
|
||||
// So we'll do that manually here:
|
||||
if ((*ty).tp_flags & ffi::Py_TPFLAGS_HEAPTYPE) != 0 {
|
||||
ffi::Py_DECREF(ty as *mut ffi::PyObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,14 +77,13 @@ impl <'p> PythonBaseObject<'p> for PyObject<'p> {
|
|||
/// 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<'p, T, B = PyObject<'p>> where T: 'p, B: PythonBaseObject<'p> {
|
||||
pub struct PyRustObject<'p, T, B = PyObject<'p>> where T: 'static, B: PythonBaseObject<'p> {
|
||||
obj: PyObject<'p>,
|
||||
/// The PyRustObject acts like a shared reference to the contained T.
|
||||
t: marker::PhantomData<&'p T>,
|
||||
b: marker::PhantomData<B>
|
||||
t: marker::PhantomData<&'p (T, B)>
|
||||
}
|
||||
|
||||
impl <'p, T, B> PyRustObject<'p, T, B> where T: 'p, B: PythonBaseObject<'p> {
|
||||
impl <'p, T, B> PyRustObject<'p, T, B> where T: 'static + Send, B: PythonBaseObject<'p> {
|
||||
#[inline] // this function can usually be reduced to a compile-time constant
|
||||
fn offset() -> usize {
|
||||
let align = mem::min_align_of::<T>();
|
||||
|
@ -98,7 +108,7 @@ impl <'p, T, B> PyRustObject<'p, T, B> where T: 'p, B: PythonBaseObject<'p> {
|
|||
}
|
||||
}
|
||||
|
||||
impl <'p, T, B> PythonBaseObject<'p> for PyRustObject<'p, T, B> where T: 'p + Send, B: PythonBaseObject<'p> {
|
||||
impl <'p, T, B> PythonBaseObject<'p> for PyRustObject<'p, T, B> where T: 'static + Send, B: PythonBaseObject<'p> {
|
||||
#[inline]
|
||||
fn size() -> usize {
|
||||
PyRustObject::<T, B>::offset() + mem::size_of::<T>()
|
||||
|
@ -120,18 +130,17 @@ impl <'p, T, B> PythonBaseObject<'p> for PyRustObject<'p, T, B> where T: 'p + Se
|
|||
}
|
||||
}
|
||||
|
||||
impl <'p, T, B> Clone for PyRustObject<'p, T, B> where T: 'p + Send, B: PythonBaseObject<'p> {
|
||||
impl <'p, T, B> Clone for PyRustObject<'p, T, B> where T: 'static + Send, B: PythonBaseObject<'p> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
PyRustObject {
|
||||
obj: self.obj.clone(),
|
||||
t: marker::PhantomData,
|
||||
b: marker::PhantomData
|
||||
t: marker::PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <'p, T, B> ToPythonPointer for PyRustObject<'p, T, B> where T: 'p + Send, B: PythonBaseObject<'p> {
|
||||
impl <'p, T, B> ToPythonPointer for PyRustObject<'p, T, B> where T: 'static + Send, B: PythonBaseObject<'p> {
|
||||
#[inline]
|
||||
fn as_ptr(&self) -> *mut ffi::PyObject {
|
||||
self.obj.as_ptr()
|
||||
|
@ -143,7 +152,7 @@ impl <'p, T, B> ToPythonPointer for PyRustObject<'p, T, B> where T: 'p + Send, B
|
|||
}
|
||||
}
|
||||
|
||||
impl <'p, T, B> PythonObject<'p> for PyRustObject<'p, T, B> where T: 'p + Send, B: PythonBaseObject<'p> {
|
||||
impl <'p, T, B> PythonObject<'p> for PyRustObject<'p, T, B> where T: 'static + Send, B: PythonBaseObject<'p> {
|
||||
#[inline]
|
||||
fn as_object(&self) -> &PyObject<'p> {
|
||||
&self.obj
|
||||
|
@ -160,8 +169,7 @@ impl <'p, T, B> PythonObject<'p> for PyRustObject<'p, T, B> where T: 'p + Send,
|
|||
unsafe fn unchecked_downcast_from(obj: PyObject<'p>) -> Self {
|
||||
PyRustObject {
|
||||
obj: obj,
|
||||
t: marker::PhantomData,
|
||||
b: marker::PhantomData
|
||||
t: marker::PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,124 +260,3 @@ impl <'p, T> PythonObject<'p> for PyRustType<'p, T> where T: 'p + Send {
|
|||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[must_use]
|
||||
pub struct PyRustTypeBuilder<'p, T, B = PyObject<'p>> where T: 'p + Send, B: PythonBaseObject<'p> {
|
||||
type_obj: PyType<'p>,
|
||||
target_module: Option<PyModule<'p>>,
|
||||
ht: *mut ffi::PyHeapTypeObject,
|
||||
phantom: marker::PhantomData<&'p (B, T)>
|
||||
}
|
||||
|
||||
pub fn new_typebuilder_for_module<'p, T>(m: &PyModule<'p>, name: &str) -> PyRustTypeBuilder<'p, T>
|
||||
where T: 'p + Send {
|
||||
let b = PyRustTypeBuilder::new(m.python(), name);
|
||||
if let Ok(mod_name) = m.name() {
|
||||
b.dict().set_item("__module__", mod_name).ok();
|
||||
}
|
||||
PyRustTypeBuilder { target_module: Some(m.clone()), .. b }
|
||||
}
|
||||
|
||||
unsafe extern "C" fn disabled_tp_new_callback
|
||||
(subtype: *mut ffi::PyTypeObject, args: *mut ffi::PyObject, kwds: *mut ffi::PyObject)
|
||||
-> *mut ffi::PyObject {
|
||||
ffi::PyErr_SetString(ffi::PyExc_TypeError,
|
||||
b"Cannot initialize rust object from python.\0" as *const u8 as *const libc::c_char);
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn tp_dealloc_callback<'p, T, B>(obj: *mut ffi::PyObject)
|
||||
where T: 'p + Send, B: PythonBaseObject<'p> {
|
||||
abort_on_panic!({
|
||||
PyRustObject::<T, B>::dealloc(obj)
|
||||
});
|
||||
}
|
||||
|
||||
impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'p + Send {
|
||||
/// Create a new type builder.
|
||||
pub fn new(py: Python<'p>, name: &str) -> PyRustTypeBuilder<'p, T> {
|
||||
unsafe {
|
||||
let obj = (ffi::PyType_Type.tp_alloc.unwrap())(&mut ffi::PyType_Type, 0);
|
||||
if obj.is_null() {
|
||||
panic!("Out of memory")
|
||||
}
|
||||
let ht = obj as *mut ffi::PyHeapTypeObject;
|
||||
(*ht).ht_name = PyString::new(py, name.as_bytes()).steal_ptr();
|
||||
(*ht).ht_type.tp_name = ffi::PyString_AS_STRING((*ht).ht_name);
|
||||
(*ht).ht_type.tp_flags = ffi::Py_TPFLAGS_DEFAULT | ffi::Py_TPFLAGS_HEAPTYPE;
|
||||
(*ht).ht_type.tp_new = Some(disabled_tp_new_callback);
|
||||
PyRustTypeBuilder {
|
||||
type_obj: PyType::unchecked_downcast_from(PyObject::from_owned_ptr(py, obj)),
|
||||
target_module: None,
|
||||
ht: ht,
|
||||
phantom: marker::PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base<T2, B2>(self, base_type: &PyRustType<'p, T2, B2>)
|
||||
-> PyRustTypeBuilder<'p, T, PyRustObject<'p, T2, B2>>
|
||||
where T2: 'p + Send, B2: PythonBaseObject<'p>
|
||||
{
|
||||
unsafe {
|
||||
ffi::Py_XDECREF((*self.ht).ht_type.tp_base as *mut ffi::PyObject);
|
||||
(*self.ht).ht_type.tp_base = base_type.as_type_ptr();
|
||||
ffi::Py_INCREF(base_type.as_ptr());
|
||||
}
|
||||
PyRustTypeBuilder {
|
||||
type_obj: self.type_obj,
|
||||
target_module: self.target_module,
|
||||
ht: self.ht,
|
||||
phantom: marker::PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dict(&self) -> PyDict<'p> {
|
||||
let py = self.type_obj.python();
|
||||
unsafe {
|
||||
if (*self.ht).ht_type.tp_dict.is_null() {
|
||||
(*self.ht).ht_type.tp_dict = PyDict::new(py).steal_ptr();
|
||||
}
|
||||
PyDict::unchecked_downcast_from(PyObject::from_borrowed_ptr(py, (*self.ht).ht_type.tp_dict))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'p + Send, B: PythonBaseObject<'p> {
|
||||
|
||||
pub fn finish(self) -> PyResult<'p, PyRustType<'p, T, B>> {
|
||||
let py = self.type_obj.python();
|
||||
unsafe {
|
||||
(*self.ht).ht_type.tp_basicsize = PyRustObject::<T, B>::size() as ffi::Py_ssize_t;
|
||||
(*self.ht).ht_type.tp_dealloc = Some(tp_dealloc_callback::<T, B>);
|
||||
try!(err::error_on_minusone(py, ffi::PyType_Ready(self.type_obj.as_type_ptr())))
|
||||
}
|
||||
if let Some(m) = self.target_module {
|
||||
// Register the new type in the target module
|
||||
let name = unsafe { PyObject::from_borrowed_ptr(py, (*self.ht).ht_name) };
|
||||
try!(m.dict().set_item(name, self.type_obj.as_object()));
|
||||
}
|
||||
Ok(PyRustType {
|
||||
type_obj: self.type_obj,
|
||||
phantom: marker::PhantomData
|
||||
})
|
||||
}
|
||||
|
||||
/// Set the doc string on the type being built.
|
||||
pub fn doc(self, doc_str: &str) -> Self {
|
||||
unsafe {
|
||||
if !(*self.ht).ht_type.tp_doc.is_null() {
|
||||
ffi::PyObject_Free((*self.ht).ht_type.tp_doc as *mut libc::c_void);
|
||||
}
|
||||
// ht_type.tp_doc must be allocated with PyObject_Malloc
|
||||
let p = ffi::PyObject_Malloc((doc_str.len() + 1) as libc::size_t);
|
||||
(*self.ht).ht_type.tp_doc = p as *const libc::c_char;
|
||||
if p.is_null() {
|
||||
panic!("Out of memory")
|
||||
}
|
||||
ptr::copy_nonoverlapping(doc_str.as_ptr(), p as *mut u8, doc_str.len() + 1);
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
use libc;
|
||||
use ffi;
|
||||
use python::{Python, ToPythonPointer, PythonObject};
|
||||
use conversion::ToPyObject;
|
||||
use objects::{PyObject, PyType, PyString, PyModule, PyDict};
|
||||
use std::{mem, ops, ptr, marker};
|
||||
use err::{self, PyResult};
|
||||
use super::{PythonBaseObject, PyRustObject, PyRustType};
|
||||
|
||||
#[repr(C)]
|
||||
#[must_use]
|
||||
pub struct PyRustTypeBuilder<'p, T, B = PyObject<'p>> where T: 'static + Send, B: PythonBaseObject<'p> {
|
||||
type_obj: PyType<'p>,
|
||||
target_module: Option<PyModule<'p>>,
|
||||
ht: *mut ffi::PyHeapTypeObject,
|
||||
phantom: marker::PhantomData<&'p (B, T)>
|
||||
}
|
||||
|
||||
pub fn new_typebuilder_for_module<'p, T>(m: &PyModule<'p>, name: &str) -> PyRustTypeBuilder<'p, T>
|
||||
where T: 'static + Send {
|
||||
let b = PyRustTypeBuilder::new(m.python(), name);
|
||||
if let Ok(mod_name) = m.name() {
|
||||
b.dict().set_item("__module__", mod_name).ok();
|
||||
}
|
||||
PyRustTypeBuilder { target_module: Some(m.clone()), .. b }
|
||||
}
|
||||
|
||||
unsafe extern "C" fn disabled_tp_new_callback
|
||||
(subtype: *mut ffi::PyTypeObject, args: *mut ffi::PyObject, kwds: *mut ffi::PyObject)
|
||||
-> *mut ffi::PyObject {
|
||||
ffi::PyErr_SetString(ffi::PyExc_TypeError,
|
||||
b"Cannot initialize rust object from python.\0" as *const u8 as *const libc::c_char);
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn tp_dealloc_callback<'p, T, B>(obj: *mut ffi::PyObject)
|
||||
where T: 'static + Send, B: PythonBaseObject<'p> {
|
||||
abort_on_panic!({
|
||||
PyRustObject::<T, B>::dealloc(obj)
|
||||
});
|
||||
}
|
||||
|
||||
impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send {
|
||||
/// Create a new type builder.
|
||||
///
|
||||
/// py: proof that the GIL is held by the current thread.
|
||||
/// name: name of the new type
|
||||
pub fn new(py: Python<'p>, name: &str) -> PyRustTypeBuilder<'p, T> {
|
||||
unsafe {
|
||||
let obj = (ffi::PyType_Type.tp_alloc.unwrap())(&mut ffi::PyType_Type, 0);
|
||||
if obj.is_null() {
|
||||
panic!("Out of memory")
|
||||
}
|
||||
debug_assert!(ffi::Py_REFCNT(obj) == 1);
|
||||
let ht = obj as *mut ffi::PyHeapTypeObject;
|
||||
(*ht).ht_name = PyString::new(py, name.as_bytes()).steal_ptr();
|
||||
(*ht).ht_type.tp_name = ffi::PyString_AS_STRING((*ht).ht_name);
|
||||
(*ht).ht_type.tp_flags = ffi::Py_TPFLAGS_DEFAULT | ffi::Py_TPFLAGS_HEAPTYPE;
|
||||
(*ht).ht_type.tp_new = Some(disabled_tp_new_callback);
|
||||
PyRustTypeBuilder {
|
||||
type_obj: PyType::unchecked_downcast_from(PyObject::from_owned_ptr(py, obj)),
|
||||
target_module: None,
|
||||
ht: ht,
|
||||
phantom: marker::PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the base class that this type is inheriting from.
|
||||
pub fn base<T2, B2>(self, base_type: &PyRustType<'p, T2, B2>)
|
||||
-> PyRustTypeBuilder<'p, T, PyRustObject<'p, T2, B2>>
|
||||
where T2: 'static + Send, B2: PythonBaseObject<'p>
|
||||
{
|
||||
unsafe {
|
||||
ffi::Py_XDECREF((*self.ht).ht_type.tp_base as *mut ffi::PyObject);
|
||||
(*self.ht).ht_type.tp_base = base_type.as_type_ptr();
|
||||
ffi::Py_INCREF(base_type.as_ptr());
|
||||
}
|
||||
PyRustTypeBuilder {
|
||||
type_obj: self.type_obj,
|
||||
target_module: self.target_module,
|
||||
ht: self.ht,
|
||||
phantom: marker::PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: PythonBaseObject<'p> {
|
||||
|
||||
/// Retrieves the type dictionary of the type being built.
|
||||
pub fn dict(&self) -> PyDict<'p> {
|
||||
let py = self.type_obj.python();
|
||||
unsafe {
|
||||
if (*self.ht).ht_type.tp_dict.is_null() {
|
||||
(*self.ht).ht_type.tp_dict = PyDict::new(py).steal_ptr();
|
||||
}
|
||||
PyDict::unchecked_downcast_from(PyObject::from_borrowed_ptr(py, (*self.ht).ht_type.tp_dict))
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the doc string on the type being built.
|
||||
pub fn doc(self, doc_str: &str) -> Self {
|
||||
unsafe {
|
||||
if !(*self.ht).ht_type.tp_doc.is_null() {
|
||||
ffi::PyObject_Free((*self.ht).ht_type.tp_doc as *mut libc::c_void);
|
||||
}
|
||||
// ht_type.tp_doc must be allocated with PyObject_Malloc
|
||||
let p = ffi::PyObject_Malloc((doc_str.len() + 1) as libc::size_t);
|
||||
(*self.ht).ht_type.tp_doc = p as *const libc::c_char;
|
||||
if p.is_null() {
|
||||
panic!("Out of memory")
|
||||
}
|
||||
ptr::copy_nonoverlapping(doc_str.as_ptr(), p as *mut u8, doc_str.len() + 1);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds a new member to the type.
|
||||
pub fn add<M>(self, name: &str, val: M) -> Self
|
||||
where M: TypeMember<'p, PyRustObject<'p, T, B>> {
|
||||
self.dict().set_item(name, val.into_descriptor(&self.type_obj, name)).unwrap();
|
||||
self
|
||||
}
|
||||
|
||||
/// Finalize construction of the new type.
|
||||
pub fn finish(self) -> PyResult<'p, PyRustType<'p, T, B>> {
|
||||
let py = self.type_obj.python();
|
||||
unsafe {
|
||||
(*self.ht).ht_type.tp_basicsize = PyRustObject::<T, B>::size() as ffi::Py_ssize_t;
|
||||
(*self.ht).ht_type.tp_dealloc = Some(tp_dealloc_callback::<T, B>);
|
||||
try!(err::error_on_minusone(py, ffi::PyType_Ready(self.type_obj.as_type_ptr())))
|
||||
}
|
||||
if let Some(m) = self.target_module {
|
||||
// Register the new type in the target module
|
||||
let name = unsafe { PyObject::from_borrowed_ptr(py, (*self.ht).ht_name) };
|
||||
try!(m.dict().set_item(name, self.type_obj.as_object()));
|
||||
}
|
||||
Ok(PyRustType {
|
||||
type_obj: self.type_obj,
|
||||
phantom: marker::PhantomData
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Represents something that can be added as a member to a python class/type.
|
||||
///
|
||||
/// T: type of rust class used for instances of the python class/type.
|
||||
pub trait TypeMember<'p, T> where T: PythonObject<'p> {
|
||||
fn into_descriptor(self, ty: &PyType<'p>, name: &str) -> PyObject<'p>;
|
||||
}
|
||||
|
||||
// TODO: does this cause trouble for coherence?
|
||||
impl <'p, T, S> TypeMember<'p, T> for S where T: PythonObject<'p>, S: ToPyObject<'p> {
|
||||
#[inline]
|
||||
fn into_descriptor(self, ty: &PyType<'p>, name: &str) -> PyObject<'p> {
|
||||
self.into_py_object(ty.python()).into_object()
|
||||
}
|
||||
}
|
||||
|
||||
impl <'p, T> TypeMember<'p, T> for fn(&T) where T: PythonObject<'p> {
|
||||
fn into_descriptor(self, ty: &PyType<'p>, name: &str) -> PyObject<'p> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -32,7 +32,22 @@ fn rustobject_calls_drop() {
|
|||
fn rustobject_no_init_from_python() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let t = PyRustTypeBuilder::<i32>::new(py, "TypeWithDrop").finish().unwrap();
|
||||
let t = PyRustTypeBuilder::<i32>::new(py, "MyType").finish().unwrap();
|
||||
assert!(t.call(&NoArgs, None).is_err());
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn rustobject_heaptype_refcount() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let t = 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();
|
||||
let inst = t.create_instance(1, ());
|
||||
assert_eq!(old_refcnt + 1, t.as_object().get_refcnt());
|
||||
drop(inst);
|
||||
assert_eq!(old_refcnt, t.as_object().get_refcnt());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue