Add python 3 support to PyRustTypeBuilder.
This commit is contained in:
parent
00492e700c
commit
76e38e1a54
|
@ -90,9 +90,7 @@ pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonOb
|
|||
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python};
|
||||
pub use conversion::{FromPyObject, ToPyObject};
|
||||
pub use objectprotocol::{ObjectProtocol};
|
||||
#[cfg(feature="python27-sys")]
|
||||
pub use rustobject::{PyRustType, PyRustObject};
|
||||
#[cfg(feature="python27-sys")]
|
||||
pub use rustobject::typebuilder::PyRustTypeBuilder;
|
||||
|
||||
use std::ptr;
|
||||
|
@ -114,7 +112,6 @@ mod objects;
|
|||
mod objectprotocol;
|
||||
mod pythonrun;
|
||||
mod function;
|
||||
#[cfg(feature="python27-sys")]
|
||||
mod rustobject;
|
||||
|
||||
/// Private re-exports for macros. Do not use.
|
||||
|
@ -125,14 +122,13 @@ pub mod _detail {
|
|||
pub use abort_on_panic::PanicGuard;
|
||||
pub use err::from_owned_ptr_or_panic;
|
||||
pub use function::py_fn_impl;
|
||||
#[cfg(feature="python27-sys")]
|
||||
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.
|
||||
/// This is useful in macros to ensure that type inference doesn't set 'p == 'static.
|
||||
#[inline]
|
||||
pub unsafe fn bounded_assume_gil_acquired<T>(_bound: &T) -> super::Python {
|
||||
pub unsafe fn bounded_assume_gil_acquired<'p, T>(_bound: &'p T) -> super::Python<'p> {
|
||||
super::Python::assume_gil_acquired()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,7 +110,6 @@ impl <'p> PyModule<'p> {
|
|||
/// 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.
|
||||
#[cfg(feature="python27-sys")]
|
||||
pub fn add_type<T>(&self, name: &str) -> ::rustobject::typebuilder::PyRustTypeBuilder<'p, T>
|
||||
where T: 'p + Send {
|
||||
::rustobject::typebuilder::new_typebuilder_for_module(self, name)
|
||||
|
|
|
@ -265,6 +265,23 @@ impl <'p> ToPyObject<'p> for str {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts rust `String` to Python object:
|
||||
/// ASCII-only strings are converted to Python `str` objects;
|
||||
/// other strings are converted to Python `unicode` objects.
|
||||
///
|
||||
/// Note that `str::ObjectType` differs based on Python version:
|
||||
/// In Python 2.7, it is `PyObject` (`object` is the common base class of `str` and `unicode`).
|
||||
/// In Python 3.x, it is `PyUnicode`.
|
||||
impl <'p> ToPyObject<'p> for String {
|
||||
type ObjectType = <str as ToPyObject<'p>>::ObjectType;
|
||||
|
||||
#[inline]
|
||||
fn to_py_object(&self, py: Python<'p>) -> Self::ObjectType {
|
||||
<str as ToPyObject>::to_py_object(self, py)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Allows extracting strings from Python objects.
|
||||
/// Accepts Python `str` and `unicode` objects.
|
||||
/// In Python 2.7, `str` is expected to be UTF-8 encoded.
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use std::marker;
|
||||
use python::PythonObject;
|
||||
use python::{Python, PythonObject};
|
||||
use objects::{PyObject, PyTuple, PyType};
|
||||
use super::typebuilder::TypeMember;
|
||||
use ffi;
|
||||
|
@ -108,12 +108,17 @@ pub unsafe fn py_method_impl<'p, T, R>(
|
|||
|
||||
impl <'p, T> TypeMember<'p, T> for MethodDescriptor<T> where T: PythonObject<'p> {
|
||||
#[inline]
|
||||
fn into_descriptor(self, ty: &PyType<'p>, _name: &str) -> PyObject<'p> {
|
||||
fn to_descriptor(&self, ty: &PyType<'p>, _name: &str) -> PyObject<'p> {
|
||||
unsafe {
|
||||
err::from_owned_ptr_or_panic(ty.python(),
|
||||
ffi::PyDescr_NewMethod(ty.as_type_ptr(), self.0))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_box(self, _py: Python<'p>) -> Box<TypeMember<'p, T> + 'p> {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -198,11 +203,16 @@ pub unsafe fn py_class_method_impl<'p, R>(
|
|||
|
||||
impl <'p, T> TypeMember<'p, T> for ClassMethodDescriptor where T: PythonObject<'p> {
|
||||
#[inline]
|
||||
fn into_descriptor(self, ty: &PyType<'p>, _name: &str) -> PyObject<'p> {
|
||||
fn to_descriptor(&self, ty: &PyType<'p>, _name: &str) -> PyObject<'p> {
|
||||
unsafe {
|
||||
err::from_owned_ptr_or_panic(ty.python(),
|
||||
ffi::PyDescr_NewClassMethod(ty.as_type_ptr(), self.0))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_box(self, _py: Python<'p>) -> Box<TypeMember<'p, T> + 'p> {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,17 +58,22 @@ impl <'p> PythonBaseObject<'p> for PyObject<'p> {
|
|||
|
||||
unsafe fn alloc(ty: &PyType<'p>, _init_val: ()) -> PyResult<'p, PyObject<'p>> {
|
||||
let py = ty.python();
|
||||
let ptr = ((*ty.as_type_ptr()).tp_alloc.unwrap())(ty.as_type_ptr(), 0);
|
||||
let ptr = ffi::PyType_GenericAlloc(ty.as_type_ptr(), 0);
|
||||
err::result_from_owned_ptr(py, ptr)
|
||||
}
|
||||
|
||||
unsafe fn dealloc(ptr: *mut ffi::PyObject) {
|
||||
// Unfortunately, there is no PyType_GenericFree, so
|
||||
// we have to manually un-do the work of PyType_GenericAlloc:
|
||||
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 {
|
||||
if ffi::PyType_IS_GC(ty) != 0 {
|
||||
ffi::PyObject_GC_Del(ptr as *mut libc::c_void);
|
||||
} else {
|
||||
ffi::PyObject_Free(ptr as *mut libc::c_void);
|
||||
}
|
||||
// For heap types, PyType_GenericAlloc calls INCREF on the type objects,
|
||||
// so we need to call DECREF here:
|
||||
if ffi::PyType_HasFeature(ty, ffi::Py_TPFLAGS_HEAPTYPE) != 0 {
|
||||
ffi::Py_DECREF(ty as *mut ffi::PyObject);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,29 +17,60 @@
|
|||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use std::{ptr, marker};
|
||||
use std::ffi::{CStr, CString};
|
||||
use libc;
|
||||
use ffi;
|
||||
use python::{Python, ToPythonPointer, PythonObject};
|
||||
use conversion::ToPyObject;
|
||||
use objects::{PyObject, PyType, PyString, PyModule, PyDict};
|
||||
use err::{self, PyResult};
|
||||
use objectprotocol::ObjectProtocol;
|
||||
use super::{PythonBaseObject, PyRustObject, PyRustType};
|
||||
|
||||
#[repr(C)]
|
||||
#[must_use]
|
||||
pub struct PyRustTypeBuilder<'p, T, B = PyObject<'p>> where T: 'static + Send, B: PythonBaseObject<'p> {
|
||||
// In Python 2.7, we can create a new PyHeapTypeObject and fill it.
|
||||
|
||||
/// The python type object under construction.
|
||||
#[cfg(feature="python27-sys")]
|
||||
type_obj: PyType<'p>,
|
||||
target_module: Option<PyModule<'p>>,
|
||||
/// The full PyHeapTypeObject under construction.
|
||||
#[cfg(feature="python27-sys")]
|
||||
ht: *mut ffi::PyHeapTypeObject,
|
||||
|
||||
// In Python 3.x with PEP 384, we prepare the relevant
|
||||
// information and then create the type in `finish()`.
|
||||
|
||||
/// Name of the type to be created
|
||||
#[cfg(feature="python3-sys")]
|
||||
name: CString,
|
||||
/// Flags of the type to be created
|
||||
#[cfg(feature="python3-sys")]
|
||||
flags: libc::c_uint,
|
||||
/// Slots to use when creating the type
|
||||
#[cfg(feature="python3-sys")]
|
||||
slots: Vec<ffi::PyType_Slot>,
|
||||
/// Maintains owned reference for base type object
|
||||
#[cfg(feature="python3-sys")]
|
||||
tp_base: Option<PyType<'p>>,
|
||||
/// List of future type members
|
||||
#[cfg(feature="python3-sys")]
|
||||
members: Vec<(String, Box<TypeMember<'p, PyRustObject<'p, T, B>> + 'p>)>,
|
||||
|
||||
/// The documentation string.
|
||||
doc_str: Option<CString>,
|
||||
/// The module to which the new type should be added.
|
||||
target_module: Option<PyModule<'p>>,
|
||||
/// Whether PyTypeBuilder::base() might be called
|
||||
can_change_base: bool,
|
||||
py: Python<'p>,
|
||||
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 }
|
||||
}
|
||||
|
||||
|
@ -63,6 +94,7 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send {
|
|||
///
|
||||
/// py: proof that the GIL is held by the current thread.
|
||||
/// name: name of the new type
|
||||
#[cfg(feature="python27-sys")]
|
||||
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);
|
||||
|
@ -71,24 +103,51 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send {
|
|||
}
|
||||
debug_assert!(ffi::Py_REFCNT(obj) == 1);
|
||||
let ht = obj as *mut ffi::PyHeapTypeObject;
|
||||
// flags must be set first, before the GC traverses the object
|
||||
(*ht).ht_type.tp_flags = ffi::Py_TPFLAGS_DEFAULT | ffi::Py_TPFLAGS_HEAPTYPE;
|
||||
(*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)),
|
||||
doc_str: None,
|
||||
target_module: None,
|
||||
ht: ht,
|
||||
can_change_base: true,
|
||||
py: py,
|
||||
phantom: marker::PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new type builder.
|
||||
///
|
||||
/// py: proof that the GIL is held by the current thread.
|
||||
/// name: name of the new type
|
||||
#[cfg(feature="python3-sys")]
|
||||
pub fn new(py: Python<'p>, name: &str) -> PyRustTypeBuilder<'p, T> {
|
||||
PyRustTypeBuilder {
|
||||
name: CString::new(name).unwrap(),
|
||||
flags: ffi::Py_TPFLAGS_DEFAULT as libc::c_uint,
|
||||
slots: Vec::new(),
|
||||
tp_base: None,
|
||||
members: Vec::new(),
|
||||
target_module: None,
|
||||
doc_str: None,
|
||||
can_change_base: true,
|
||||
py: py,
|
||||
phantom: marker::PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the base class that this type is inheriting from.
|
||||
#[cfg(feature="python27-sys")]
|
||||
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>
|
||||
{
|
||||
assert!(self.can_change_base,
|
||||
"base() must be called before any members are added to the type");
|
||||
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();
|
||||
|
@ -96,60 +155,93 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send {
|
|||
}
|
||||
PyRustTypeBuilder {
|
||||
type_obj: self.type_obj,
|
||||
doc_str: self.doc_str,
|
||||
target_module: self.target_module,
|
||||
ht: self.ht,
|
||||
can_change_base: false,
|
||||
py: self.py,
|
||||
phantom: marker::PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the base class that this type is inheriting from.
|
||||
#[cfg(feature="python3-sys")]
|
||||
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>
|
||||
{
|
||||
// Ensure we can't change the base after any callbacks are registered.
|
||||
assert!(self.can_change_base && self.members.len() == 0,
|
||||
"base() must be called before any members are added to the type");
|
||||
let base_type_obj: &PyType = base_type;
|
||||
PyRustTypeBuilder {
|
||||
name: self.name,
|
||||
flags: self.flags,
|
||||
slots: self.slots,
|
||||
tp_base: Some(base_type_obj.clone()),
|
||||
members: Vec::new(),
|
||||
target_module: self.target_module,
|
||||
doc_str: self.doc_str,
|
||||
can_change_base: false,
|
||||
py: self.py,
|
||||
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();
|
||||
#[cfg(feature="python27-sys")]
|
||||
fn dict(&self) -> PyDict<'p> {
|
||||
unsafe {
|
||||
if (*self.ht).ht_type.tp_dict.is_null() {
|
||||
(*self.ht).ht_type.tp_dict = PyDict::new(py).steal_ptr();
|
||||
(*self.ht).ht_type.tp_dict = PyDict::new(self.py).steal_ptr();
|
||||
}
|
||||
PyDict::unchecked_downcast_from(PyObject::from_borrowed_ptr(py, (*self.ht).ht_type.tp_dict))
|
||||
PyDict::unchecked_downcast_from(PyObject::from_borrowed_ptr(self.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);
|
||||
}
|
||||
PyRustTypeBuilder { doc_str: Some(CString::new(doc_str).unwrap()), .. self }
|
||||
}
|
||||
|
||||
/// Adds a new member to the type.
|
||||
#[cfg(feature="python27-sys")]
|
||||
pub fn add<M>(mut self, name: &str, val: M) -> Self
|
||||
where M: TypeMember<'p, PyRustObject<'p, T, B>> {
|
||||
self.can_change_base = false;
|
||||
self.dict().set_item(name, val.to_descriptor(&self.type_obj, name)).unwrap();
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds a new member to the type.
|
||||
pub fn add<M>(self, name: &str, val: M) -> Self
|
||||
#[cfg(feature="python3-sys")]
|
||||
pub fn add<M>(mut 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.can_change_base = false;
|
||||
self.members.push((name.to_owned(), val.into_box(self.py)));
|
||||
self
|
||||
}
|
||||
|
||||
/// Finalize construction of the new type.
|
||||
#[cfg(feature="python27-sys")]
|
||||
pub fn finish(self) -> PyResult<'p, PyRustType<'p, T, B>> {
|
||||
let py = self.type_obj.python();
|
||||
let py = self.py;
|
||||
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>);
|
||||
if let Some(s) = self.doc_str {
|
||||
(*self.ht).ht_type.tp_doc = copy_str_to_py_malloc_heap(&s);
|
||||
}
|
||||
try!(err::error_on_minusone(py, ffi::PyType_Ready(self.type_obj.as_type_ptr())))
|
||||
}
|
||||
if let Some(m) = self.target_module {
|
||||
// Set module name for new type
|
||||
if let Ok(mod_name) = m.name() {
|
||||
try!(self.type_obj.as_object().setattr("__module__", mod_name));
|
||||
}
|
||||
// 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()));
|
||||
|
@ -160,21 +252,127 @@ impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: PythonBa
|
|||
})
|
||||
}
|
||||
|
||||
/// Finalize construction of the new type.
|
||||
#[cfg(feature="python3-sys")]
|
||||
pub fn finish(mut self) -> PyResult<'p, PyRustType<'p, T, B>> {
|
||||
// push some more slots
|
||||
self.slots.push(ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_dealloc,
|
||||
pfunc: tp_dealloc_callback::<T, B> as ffi::destructor as *mut libc::c_void
|
||||
});
|
||||
if let Some(s) = self.doc_str {
|
||||
self.slots.push(ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_doc,
|
||||
pfunc: copy_str_to_py_malloc_heap(&s) as *mut libc::c_void
|
||||
});
|
||||
}
|
||||
if let Some(base_type) = self.tp_base {
|
||||
self.slots.push(ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_base,
|
||||
pfunc: base_type.as_type_ptr() as *mut libc::c_void
|
||||
});
|
||||
}
|
||||
|
||||
let type_obj = try!(unsafe { create_type_from_slots(
|
||||
self.py, &self.name, PyRustObject::<T, B>::size(),
|
||||
self.flags, &mut self.slots) });
|
||||
for (name, member) in self.members {
|
||||
let descr = member.to_descriptor(&type_obj, &name);
|
||||
try!(type_obj.as_object().setattr(name, descr));
|
||||
}
|
||||
if let Some(m) = self.target_module {
|
||||
// Set module name for new type
|
||||
if let Ok(mod_name) = m.name() {
|
||||
try!(type_obj.as_object().setattr("__module__", mod_name));
|
||||
}
|
||||
// Register the new type in the target module
|
||||
unsafe {
|
||||
try!(err::error_on_minusone(self.py,
|
||||
ffi::PyDict_SetItemString(
|
||||
m.dict().as_object().as_ptr(),
|
||||
self.name.as_ptr(),
|
||||
type_obj.as_object().as_ptr())
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(PyRustType {
|
||||
type_obj: type_obj,
|
||||
phantom: marker::PhantomData
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn copy_str_to_py_malloc_heap(s: &CStr) -> *mut libc::c_char {
|
||||
copy_to_py_malloc_heap(s.to_bytes_with_nul()) as *mut libc::c_char
|
||||
}
|
||||
|
||||
fn copy_to_py_malloc_heap(s: &[u8]) -> *mut u8 {
|
||||
unsafe {
|
||||
let p = ffi::PyObject_Malloc(s.len() as libc::size_t) as *mut u8;
|
||||
if p.is_null() {
|
||||
panic!("Out of memory")
|
||||
}
|
||||
ptr::copy_nonoverlapping(s.as_ptr(), p, s.len());
|
||||
p
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="python3-sys")]
|
||||
unsafe fn create_type_from_slots<'p>(
|
||||
py: Python<'p>,
|
||||
name: &CStr,
|
||||
basicsize: usize,
|
||||
flags: libc::c_uint,
|
||||
slots: &mut Vec<ffi::PyType_Slot>
|
||||
) -> PyResult<'p, PyType<'p>>
|
||||
{
|
||||
// ensure the necessary slots are set:
|
||||
if !slots.iter().any(|s| s.slot == ffi::Py_tp_new) {
|
||||
slots.push(ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_new,
|
||||
pfunc: disabled_tp_new_callback as ffi::newfunc as *mut libc::c_void
|
||||
});
|
||||
}
|
||||
slots.push(ffi::PyType_Slot::default()); // sentinel
|
||||
let mut spec = ffi::PyType_Spec {
|
||||
name: name.as_ptr(),
|
||||
basicsize: basicsize as libc::c_int,
|
||||
itemsize: 0,
|
||||
flags: flags,
|
||||
slots: slots.as_mut_ptr()
|
||||
};
|
||||
err::result_cast_from_owned_ptr(py,
|
||||
ffi::PyType_FromSpec(&mut spec))
|
||||
}
|
||||
|
||||
/// 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>;
|
||||
/// Convert the type member into a python object
|
||||
/// that can be stored in the type dict.
|
||||
fn to_descriptor(&self, ty: &PyType<'p>, name: &str) -> PyObject<'p>;
|
||||
|
||||
/// Put the type member into a box with lifetime `'p` so that
|
||||
/// it can be used at a later point in time.
|
||||
///
|
||||
/// `PyRustTypeBuilder:add()` may use this function to store the member,
|
||||
/// with `into_descriptor()` being called from the `finish()` method.
|
||||
fn into_box(self, py: Python<'p>) -> Box<TypeMember<'p, T> + '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()
|
||||
fn to_descriptor(&self, ty: &PyType<'p>, _name: &str) -> PyObject<'p> {
|
||||
self.to_py_object(ty.python()).into_object()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_box(self, py: Python<'p>) -> Box<TypeMember<'p, T> + 'p> {
|
||||
Box::new(self.into_py_object(py).into_object())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue