Splitted PyTypeCreate of PyTypeObject to remove specialization

This commit is contained in:
konstin 2018-10-03 22:12:22 +02:00
parent 71c584a110
commit 5100676497
10 changed files with 64 additions and 80 deletions

View File

@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* `IntoPyDictPointer` was replace by `IntoPyDict` which doesn't convert `PyDict` itself anymore and returns a `PyDict` instead of `*mut PyObject`.
* `PyTuple::new` now takes an `IntoIterator` instead of a slice
* Updated to syn 0.15
* Splitted `PyTypeObject` into `PyTypeObject` without the create method and `PyTypeCreate` with requires `PyObjectAlloc<Self> + PyTypeInfo + Sized`.
### Fixed

View File

@ -9,7 +9,6 @@ To define python custom class, rust struct needs to be annotated with `#[pyclass
# extern crate pyo3;
# use pyo3::prelude::*;
#[pyclass]
struct MyClass {
num: i32,

View File

@ -127,7 +127,7 @@ fn impl_class(
FREELIST = Box::into_raw(Box::new(
::pyo3::freelist::FreeList::with_capacity(#freelist)));
<#cls as ::pyo3::typeob::PyTypeObject>::init_type();
<#cls as ::pyo3::typeob::PyTypeCreate>::init_type();
}
&mut *FREELIST
}
@ -204,27 +204,6 @@ fn impl_class(
}
}
impl ::pyo3::typeob::PyTypeObject for #cls {
#[inline]
fn init_type() {
static START: ::std::sync::Once = ::std::sync::ONCE_INIT;
START.call_once(|| {
let ty = unsafe{<#cls as ::pyo3::typeob::PyTypeInfo>::type_object()};
if (ty.tp_flags & ::pyo3::ffi::Py_TPFLAGS_READY) == 0 {
let gil = ::pyo3::Python::acquire_gil();
let py = gil.python();
// automatically initialize the class on-demand
::pyo3::typeob::initialize_type::<#cls>(py, None)
.map_err(|e| e.print(py))
.expect(format!("An error occurred while initializing class {}",
<#cls as ::pyo3::typeob::PyTypeInfo>::NAME).as_ref());
}
});
}
}
// TBH I'm not sure what exactely this does and I'm sure there's a better way,
// but for now it works and it only safe code and it is required to return custom
// objects, so for now I'm keeping it

View File

@ -363,7 +363,7 @@ pub type allocfunc =
unsafe extern "C" fn(arg1: *mut PyTypeObject, arg2: Py_ssize_t) -> *mut PyObject;
#[repr(C)]
#[derive(Copy)]
#[derive(Copy, Clone)]
pub struct PyTypeObject {
pub ob_refcnt: Py_ssize_t,
pub ob_type: *mut PyTypeObject,
@ -416,13 +416,6 @@ pub struct PyTypeObject {
pub tp_version_tag: c_uint,
}
impl Clone for PyTypeObject {
#[inline]
fn clone(&self) -> PyTypeObject {
*self
}
}
#[cfg(py_sys_config = "Py_TRACE_REFS")]
pub const PyTypeObject_INIT: PyTypeObject = PyTypeObject {
_ob_next: ::std::ptr::null_mut(),

View File

@ -14,6 +14,7 @@ use python::{IntoPyPointer, Python, ToPyPointer};
use pythonrun;
use typeob::{PyTypeInfo, PyTypeObject};
use types::PyObjectRef;
use typeob::PyTypeCreate;
pub struct PyToken(PhantomData<Rc<()>>);
@ -175,7 +176,7 @@ where
F: FnOnce(::PyToken) -> T,
T: PyTypeObject + PyTypeInfo,
{
let ob = <T as PyTypeObject>::create(py)?;
let ob = <T as PyTypeCreate>::create(py)?;
ob.init(f)?;
let ob = unsafe { Py::from_owned_ptr(ob.into_ptr()) };
@ -189,7 +190,7 @@ where
F: FnOnce(::PyToken) -> T,
T: PyTypeObject + PyTypeInfo,
{
let ob = <T as PyTypeObject>::create(py)?;
let ob = <T as PyTypeCreate>::create(py)?;
ob.init(f)?;
unsafe { Ok(py.from_owned_ptr(ob.into_ptr())) }
@ -202,7 +203,7 @@ where
F: FnOnce(::PyToken) -> T,
T: PyTypeObject + PyTypeInfo,
{
let ob = <T as PyTypeObject>::create(py)?;
let ob = <T as PyTypeCreate>::create(py)?;
ob.init(f)?;
unsafe { Ok(py.mut_from_owned_ptr(ob.into_ptr())) }

View File

@ -12,7 +12,8 @@ use std;
use std::ffi::CString;
use std::marker::PhantomData;
use std::os::raw::c_int;
use typeob::{PyObjectAlloc, PyTypeInfo, PyTypeObject};
use typeob::PyTypeCreate;
use typeob::{PyTypeInfo, PyTypeObject};
use types::{PyDict, PyModule, PyObjectRef, PyType};
/// Marker type that indicates that the GIL is currently held.
@ -253,7 +254,7 @@ impl<'p> Python<'p> {
pub fn init<T, F>(self, f: F) -> PyResult<Py<T>>
where
F: FnOnce(PyToken) -> T,
T: PyTypeInfo + PyObjectAlloc<T>,
T: PyTypeCreate,
{
Py::new(self, f)
}
@ -264,7 +265,7 @@ impl<'p> Python<'p> {
pub fn init_ref<T, F>(self, f: F) -> PyResult<&'p T>
where
F: FnOnce(PyToken) -> T,
T: PyTypeInfo + PyObjectAlloc<T>,
T: PyTypeCreate,
{
Py::new_ref(self, f)
}
@ -275,7 +276,7 @@ impl<'p> Python<'p> {
pub fn init_mut<T, F>(self, f: F) -> PyResult<&'p mut T>
where
F: FnOnce(PyToken) -> T,
T: PyTypeInfo + PyObjectAlloc<T>,
T: PyTypeCreate,
{
Py::new_mut(self, f)
}

View File

@ -217,7 +217,7 @@ where
default unsafe fn alloc(_py: Python) -> PyResult<*mut ffi::PyObject> {
// TODO: remove this
T::init_type();
<T as PyTypeCreate>::init_type();
let tp_ptr = T::type_object();
let alloc = (*tp_ptr).tp_alloc.unwrap_or(ffi::PyType_GenericAlloc);
@ -256,20 +256,42 @@ where
}
}
/// Trait implemented by Python object types that have a corresponding type object.
/// Python object types that have a corresponding type object.
pub trait PyTypeObject {
/// Initialize type object
fn init_type();
/// Retrieves the type object for this Python object type.
fn type_object() -> Py<PyType>;
}
/// Python object types that have a corresponding type object and be
/// instanciated with [Self::create()]
pub trait PyTypeCreate: PyObjectAlloc<Self> + PyTypeInfo + Sized {
#[inline]
fn init_type() {
let type_object = unsafe { *<Self as PyTypeInfo>::type_object() };
if (type_object.tp_flags & ffi::Py_TPFLAGS_READY) == 0 {
// automatically initialize the class on-demand
let gil = Python::acquire_gil();
let py = gil.python();
initialize_type::<Self>(py, None).unwrap_or_else(|_| {
panic!("An error occurred while initializing class {}", Self::NAME)
});
}
}
#[inline]
fn type_object() -> Py<PyType> {
<Self as PyTypeObject>::init_type();
PyType::new::<Self>()
}
/// Create PyRawObject which can be initialized with rust value
#[must_use]
fn create(py: Python) -> PyResult<PyRawObject>
where
Self: Sized + PyObjectAlloc<Self> + PyTypeInfo,
{
fn create(py: Python) -> PyResult<PyRawObject> {
<Self as PyTypeObject>::init_type();
unsafe {
@ -284,29 +306,18 @@ pub trait PyTypeObject {
}
}
impl<T> PyTypeCreate for T where T: PyObjectAlloc<Self> + PyTypeInfo + Sized {}
impl<T> PyTypeObject for T
where
T: PyObjectAlloc<T> + PyTypeInfo,
T: PyTypeCreate,
{
#[inline]
default fn init_type() {
unsafe {
if ((*<T>::type_object()).tp_flags & ffi::Py_TPFLAGS_READY) == 0 {
// automatically initialize the class on-demand
let gil = Python::acquire_gil();
let py = gil.python();
initialize_type::<T>(py, None).unwrap_or_else(|_| {
panic!("An error occurred while initializing class {}", T::NAME)
});
}
}
fn init_type() {
<T as PyTypeCreate>::init_type()
}
#[inline]
default fn type_object() -> Py<PyType> {
<T as PyTypeObject>::init_type();
PyType::new::<T>()
fn type_object() -> Py<PyType> {
<T as PyTypeCreate>::type_object()
}
}

View File

@ -125,7 +125,7 @@ macro_rules! pyobject_native_type_convert(
}
}
impl<$($type_param,)*> $crate::typeob::PyTypeObject for $name {
impl<$($type_param,)*> $crate::typeob::PyTypeCreate for $name {
#[inline]
fn init_type() {}

View File

@ -10,8 +10,8 @@ use ffi;
use instance::{Py, PyObjectWithToken};
use object::PyObject;
use python::{Python, ToPyPointer};
use types::PyObjectRef;
use types::exceptions;
use types::PyObjectRef;
/// Represents a Python `string`.
#[repr(transparent)]
@ -72,7 +72,7 @@ impl PyString {
Ok(s) => Ok(Cow::Borrowed(s)),
Err(e) => Err(PyErr::from_instance(
exceptions::UnicodeDecodeError::new_utf8(self.py(), self.as_bytes(), e)?,
))
)),
}
}
@ -120,12 +120,12 @@ impl PyBytes {
#[cfg(test)]
mod test {
use std::borrow::Cow;
use conversion::{FromPyObject, ToPyObject, PyTryFrom};
use instance::AsPyRef;
use python::Python;
use object::PyObject;
use super::PyString;
use conversion::{FromPyObject, PyTryFrom, ToPyObject};
use instance::AsPyRef;
use object::PyObject;
use python::Python;
use std::borrow::Cow;
#[test]
fn test_non_bmp() {

View File

@ -88,7 +88,7 @@ impl PyString {
Ok(s) => Ok(Cow::Borrowed(s)),
Err(e) => Err(PyErr::from_instance(
exceptions::UnicodeDecodeError::new_utf8(self.py(), self.as_bytes(), e)?,
))
)),
}
}
@ -156,9 +156,8 @@ impl PyUnicode {
unsafe {
// PyUnicode_AsUTF8String would return null if the pointer did not reference a valid
// unicode object, but because we have a valid PyUnicode, assume success
let data: Py<PyBytes> = Py::from_owned_ptr(
ffi::PyUnicode_AsUTF8String(self.0.as_ptr()),
);
let data: Py<PyBytes> =
Py::from_owned_ptr(ffi::PyUnicode_AsUTF8String(self.0.as_ptr()));
let buffer = ffi::PyBytes_AsString(data.as_ptr()) as *const u8;
let length = ffi::PyBytes_Size(data.as_ptr()) as usize;
debug_assert!(!buffer.is_null());
@ -175,7 +174,7 @@ impl PyUnicode {
Ok(s) => Ok(Cow::Borrowed(s)),
Err(e) => Err(PyErr::from_instance(
exceptions::UnicodeDecodeError::new_utf8(self.py(), self.as_bytes(), e)?,
))
)),
}
}
@ -205,12 +204,12 @@ impl std::convert::From<Py<PyUnicode>> for Py<PyString> {
#[cfg(test)]
mod test {
use std::borrow::Cow;
use conversion::{FromPyObject, ToPyObject, PyTryFrom};
use instance::AsPyRef;
use python::Python;
use object::PyObject;
use super::PyString;
use conversion::{FromPyObject, PyTryFrom, ToPyObject};
use instance::AsPyRef;
use object::PyObject;
use python::Python;
use std::borrow::Cow;
#[test]
fn test_non_bmp() {