refactor PyTypeObject trait

This commit is contained in:
Nikolay Kim 2017-06-08 14:21:48 -07:00
parent 86c20bb139
commit ea8f11fa6d
6 changed files with 69 additions and 31 deletions

View File

@ -107,6 +107,27 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident, token: Option<syn::Ident>) ->
}
}
impl _pyo3::typeob::PyTypeObject for #cls {
#[inline(always)]
fn init_type(py: Python) {
static START: std::sync::Once = std::sync::ONCE_INIT;
START.call_once(|| {
let mut ty = <#cls as _pyo3::typeob::PyTypeInfo>::type_object();
if (ty.tp_flags & _pyo3::ffi::Py_TPFLAGS_READY) == 0 {
// automatically initialize the class on-demand
let to = _pyo3::typeob::initialize_type::<#cls>(
py, None, <#cls as _pyo3::typeob::PyTypeInfo>::type_name(), ty)
.expect(
format!("An error occurred while initializing class {}",
<#cls as _pyo3::typeob::PyTypeInfo>::type_name())
.as_ref());
py.release(to);
}
});
}
}
impl _pyo3::python::PyDowncastFrom for #cls
{
fn downcast_from<'a, 'p>(py: Python<'p>, ob: &'a _pyo3::PyObject)

View File

@ -52,24 +52,32 @@ macro_rules! py_exception {
pub fn new<T: $crate::IntoPyObject>(py: $crate::Python, args: T) -> $crate::PyErr {
$crate::PyErr::new::<$name, T>(py, args)
}
#[inline(always)]
fn type_object(py: $crate::Python) -> *mut $crate::ffi::PyTypeObject {
#[allow(non_upper_case_globals)]
static mut type_object: *mut $crate::ffi::PyTypeObject =
0 as *mut $crate::ffi::PyTypeObject;
unsafe {
if type_object.is_null() {
type_object = $crate::PyErr::new_type(
py, concat!(stringify!($module), ".", stringify!($name)),
Some(py.get_type::<$base>()), None).as_type_ptr();
}
type_object
}
}
}
impl $crate::PyTypeObject for $name {
#[inline(always)]
fn init_type(py: $crate::Python) {
let _ = $name::type_object(py);
}
#[inline]
fn type_object(py: $crate::Python) -> $crate::PyType {
unsafe {
#[allow(non_upper_case_globals)]
static mut type_object: *mut $crate::ffi::PyTypeObject = 0 as *mut $crate::ffi::PyTypeObject;
if type_object.is_null() {
type_object = $crate::PyErr::new_type(
py,
concat!(stringify!($module), ".", stringify!($name)),
Some(py.get_type::<$base>()), None).as_type_ptr();
}
$crate::PyType::from_type_ptr(py, type_object)
}
unsafe { $crate::PyType::from_type_ptr(py, $name::type_object(py)) }
}
}
};

View File

@ -20,6 +20,9 @@ macro_rules! exc_type(
// pyobject_newtype!($name);
impl $crate::PyTypeObject for $name {
#[inline(always)]
fn init_type(_py: Python) {}
#[inline]
fn type_object(py: $crate::python::Python) -> $crate::PyType {
unsafe { PyType::from_type_ptr(py, ffi::$exc_name as *mut ffi::PyTypeObject) }

View File

@ -39,12 +39,10 @@ macro_rules! pyobject_nativetype(
fn size() -> usize {
$crate::std::mem::size_of::<ffi::PyObject>()
}
#[inline]
fn offset() -> isize {
0
}
#[inline]
fn type_name() -> &'static str {
stringify!($name)
@ -55,6 +53,16 @@ macro_rules! pyobject_nativetype(
}
}
impl $crate::typeob::PyTypeObject for $name {
#[inline(always)]
fn init_type(_py: Python) {}
#[inline]
fn type_object(py: $crate::Python) -> $crate::PyType {
unsafe { $crate::PyType::from_type_ptr(py, &mut $crate::ffi::$typeobject) }
}
}
pyobject_nativetype!($name, $checkfunction);
};

View File

@ -84,8 +84,7 @@ impl<T> PyObjectAlloc for T where T : PyTypeInfo {
/// must be of type `ty`.
unsafe fn alloc(py: Python, value: T::Type) -> PyResult<*mut ffi::PyObject> {
// TODO: remove this
let t = <T as PyTypeObject>::type_object(py);
py.release(t);
<T as PyTypeObject>::init_type(py);
let obj = ffi::PyType_GenericAlloc(
<Self as PyTypeInfo>::type_object(), 0);
@ -121,6 +120,9 @@ impl<T> PyObjectAlloc for T where T : PyTypeInfo {
/// Trait implemented by Python object types that have a corresponding type object.
pub trait PyTypeObject {
/// Initialize type object
fn init_type(py: Python);
/// Retrieves the type object for this Python object type.
fn type_object(py: Python) -> PyType;
@ -129,24 +131,28 @@ pub trait PyTypeObject {
impl<T> PyTypeObject for T where T: PyObjectAlloc + PyTypeInfo {
#[inline]
fn type_object(py: Python) -> PyType {
default fn init_type(py: Python) {
let mut ty = <T as PyTypeInfo>::type_object();
//return unsafe { PyType::from_type_ptr(py, ty) };
if (ty.tp_flags & ffi::Py_TPFLAGS_READY) != 0 {
unsafe { PyType::from_type_ptr(py, ty) }
} else {
if (ty.tp_flags & ffi::Py_TPFLAGS_READY) == 0 {
// automatically initialize the class on-demand
let to = initialize_type::<T>(
py, None, <T as PyTypeInfo>::type_name(), ty).expect(
format!("An error occurred while initializing class {}",
<T as PyTypeInfo>::type_name()).as_ref());
py.release(to);
unsafe { PyType::from_type_ptr(py, ty) }
}
}
#[inline]
default fn type_object(py: Python) -> PyType {
<T as PyTypeObject>::init_type(py);
unsafe { PyType::from_type_ptr(py, <T as PyTypeInfo>::type_object()) }
}
}
pub fn initialize_type<T>(py: Python, module_name: Option<&str>, type_name: &str,
type_object: &mut ffi::PyTypeObject) -> PyResult<PyType>
where T: PyObjectAlloc + PyTypeInfo
@ -294,27 +300,21 @@ fn py_class_method_defs<T>(py: Python, type_object: *mut ffi::PyTypeObject)
for def in <T as class::basic::PyObjectProtocolImpl>::methods() {
defs.set_item(py, def.ml_name, def.as_method_descr(py, type_object)?)?;
//defs.push(def.as_method_def())
}
for def in <T as class::async::PyAsyncProtocolImpl>::methods() {
defs.set_item(py, def.ml_name, def.as_method_descr(py, type_object)?)?;
//defs.push(def.as_method_def())
}
for def in <T as class::context::PyContextProtocolImpl>::methods() {
defs.set_item(py, def.ml_name, def.as_method_descr(py, type_object)?)?;
//defs.push(def.as_method_def())
}
for def in <T as class::mapping::PyMappingProtocolImpl>::methods() {
defs.set_item(py, def.ml_name, def.as_method_descr(py, type_object)?)?;
//defs.push(def.as_method_def())
}
for def in <T as class::number::PyNumberProtocolImpl>::methods() {
defs.set_item(py, def.ml_name, def.as_method_descr(py, type_object)?)?;
//defs.push(def.as_method_def())
}
for def in <T as class::descr::PyDescrProtocolImpl>::methods() {
defs.set_item(py, def.ml_name, def.as_method_descr(py, type_object)?)?;
//defs.push(def.as_method_def())
}
Ok((new, call, defs))

View File

@ -16,7 +16,6 @@ macro_rules! py_run {
($py:expr, $val:ident, $code:expr) => {{
let d = PyDict::new($py);
d.set_item($py, stringify!($val), &$val).unwrap();
//$py.run($code, None, Some(&d)).map_err(|e| e.print($py)).expect($code);
$py.run($code, None, Some(&d)).expect($code);
}}
}
@ -1136,5 +1135,4 @@ fn class_with_properties() {
py_run!(py, inst, "inst.DATA = 20");
py_run!(py, inst, "assert inst.get_num() == 20");
py_run!(py, inst, "assert inst.get_num() == inst.DATA");
}