Skip to content

Commit

Permalink
Splitted PyTypeCreate of PyTypeObject to remove specialization
Browse files Browse the repository at this point in the history
  • Loading branch information
konstin committed Oct 3, 2018
1 parent 71c584a commit 5100676
Show file tree
Hide file tree
Showing 10 changed files with 62 additions and 78 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 0 additions & 1 deletion guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
23 changes: 1 addition & 22 deletions pyo3-derive-backend/src/py_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand Down
9 changes: 1 addition & 8 deletions src/ffi2/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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(),
Expand Down
7 changes: 4 additions & 3 deletions src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<()>>);

Expand Down Expand Up @@ -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()) };
Expand All @@ -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())) }
Expand All @@ -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())) }
Expand Down
9 changes: 5 additions & 4 deletions src/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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)
}
Expand All @@ -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)
}
Expand All @@ -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)
}
Expand Down
59 changes: 35 additions & 24 deletions src/typeob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand All @@ -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()
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}

Expand Down
12 changes: 6 additions & 6 deletions src/types/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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)?,
))
)),
}
}

Expand Down Expand Up @@ -120,12 +120,12 @@ impl PyBytes {

#[cfg(test)]
mod test {
use std::borrow::Cow;
use conversion::{FromPyObject, ToPyObject, PyTryFrom};
use super::PyString;
use conversion::{FromPyObject, PyTryFrom, ToPyObject};
use instance::AsPyRef;
use python::Python;
use object::PyObject;
use super::PyString;
use python::Python;
use std::borrow::Cow;

#[test]
fn test_non_bmp() {
Expand Down
17 changes: 8 additions & 9 deletions src/types/string2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?,
))
)),
}
}

Expand Down Expand Up @@ -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());
Expand All @@ -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)?,
))
)),
}
}

Expand Down Expand Up @@ -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 super::PyString;
use conversion::{FromPyObject, PyTryFrom, ToPyObject};
use instance::AsPyRef;
use python::Python;
use object::PyObject;
use super::PyString;
use python::Python;
use std::borrow::Cow;

#[test]
fn test_non_bmp() {
Expand Down

0 comments on commit 5100676

Please sign in to comment.