Skip to content

Commit

Permalink
Failed
Browse files Browse the repository at this point in the history
  • Loading branch information
kngwyu committed Feb 2, 2020
1 parent 7531b9f commit 5d13505
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 78 deletions.
21 changes: 4 additions & 17 deletions pyo3-derive-backend/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,23 +382,10 @@ fn impl_class(
const FLAGS: usize = #(#flags)|* | #extended;

#[inline]
fn type_object() -> std::ptr::NonNull<pyo3::ffi::PyTypeObject> {
use std::ptr::NonNull;
use pyo3::type_object::LazyTypeObject;
static TYPE_OBJECT: LazyTypeObject = LazyTypeObject::new();
TYPE_OBJECT.get_or_init(|| {
// automatically initialize the class on-demand
let gil = pyo3::Python::acquire_gil();
let py = gil.python();
let boxed = pyo3::pyclass::create_type_object::<Self>(py, Self::MODULE)?;
Ok(unsafe { NonNull::new_unchecked(Box::into_raw(boxed)) })
})
.unwrap_or_else(|e| {
let gil = Python::acquire_gil();
let py = gil.python();
e.print(py);
panic!("An error occurred while initializing class {}", Self::NAME)
})
fn type_object() -> &'static pyo3::ffi::PyTypeObject {
use pyo3::derive_utils::LazyPyType;
static TYPE_OBJECT: LazyPyType = LazyPyType::new();
TYPE_OBJECT.get::<#cls>()
}
}

Expand Down
28 changes: 28 additions & 0 deletions src/derive_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::pyclass::PyClass;
use crate::pyclass_init::PyClassInitializer;
use crate::types::{PyAny, PyDict, PyModule, PyTuple};
use crate::{ffi, GILPool, IntoPy, PyObject, Python};
use once_cell::sync::OnceCell;
use std::ptr;

/// Description of a python parameter; used for `parse_args()`.
Expand Down Expand Up @@ -199,3 +200,30 @@ impl<T: PyClass, I: Into<PyClassInitializer<T>>> IntoPyNewResult<T, I> for PyRes
self
}
}

/// Type used to store type objects of PyClass
#[doc(hidden)]
pub struct LazyPyType(OnceCell<&'static ffi::PyTypeObject>);

impl LazyPyType {
pub const fn new() -> Self {
Self(OnceCell::new())
}

pub fn get<T: PyClass>(&self) -> &'static ffi::PyTypeObject {
self.0.get_or_init(|| {
let gil = Python::acquire_gil();
let py = gil.python();
Box::leak(
crate::pyclass::create_type_object::<T>(py, T::MODULE).unwrap_or_else(|e| {
e.print(py);
panic!("An error occurred while initializing class {}", T::NAME)
}),
)
});
*res
}
}

/// Since LazyPyType is used as global variable, Sync is necessary.
unsafe impl Sync for LazyPyType {}
9 changes: 4 additions & 5 deletions src/err.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,10 @@ impl PyErr {
let null_terminated_name =
CString::new(name).expect("Failed to initialize nul terminated exception name");

NonNull::new_unchecked(ffi::PyErr_NewException(
null_terminated_name.as_ptr() as *mut c_char,
base,
dict,
) as *mut ffi::PyTypeObject)
let new_exc =
ffi::PyErr_NewException(null_terminated_name.as_ptr() as *mut c_char, base, dict);

NonNull::new_unchecked(new_exc as *mut _)
}
}

Expand Down
37 changes: 30 additions & 7 deletions src/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ use crate::type_object::PyTypeObject;
use crate::types::{PyAny, PyTuple};
use crate::Python;
use crate::{AsPyPointer, ToPyObject};
use std::ffi::CStr;
use std::os::raw::c_char;
use std::{self, ops};
use once_cell::sync::OnceCell;
use std::{ffi::CStr, ops, os::raw::c_char, ptr::NonNull};

/// The boilerplate to convert between a rust type and a python exception
#[macro_export]
Expand Down Expand Up @@ -90,8 +89,8 @@ macro_rules! import_exception_type_object {
($module: expr, $name: ident) => {
unsafe impl $crate::type_object::PyTypeObject for $name {
fn type_object() -> $crate::Py<$crate::types::PyType> {
use $crate::type_object::LazyTypeObject;
static TYPE_OBJECT: LazyTypeObject = LazyTypeObject::new();
use $crate::exceptions::LazyException;
static TYPE_OBJECT: LazyException = LazyException::new();

let ptr = TYPE_OBJECT
.get_or_init(|| {
Expand Down Expand Up @@ -178,8 +177,8 @@ macro_rules! create_exception_type_object {
($module: ident, $name: ident, $base: ty) => {
unsafe impl $crate::type_object::PyTypeObject for $name {
fn type_object() -> $crate::Py<$crate::types::PyType> {
use $crate::type_object::LazyTypeObject;
static TYPE_OBJECT: LazyTypeObject = LazyTypeObject::new();
use $crate::exceptions::LazyException;
static TYPE_OBJECT: LazyException = LazyException::new();

let ptr = TYPE_OBJECT
.get_or_init(|| {
Expand All @@ -201,6 +200,30 @@ macro_rules! create_exception_type_object {
};
}

/// Type used to store type object pointers of exceptions
#[doc(hidden)]
#[derive(Default)]
pub struct LazyException(OnceCell<NonNull<ffi::PyTypeObject>>);

impl LazyException {
pub const fn new() -> Self {
Self(OnceCell::new())
}

pub fn get_or_init<F>(&self, constructor: F) -> PyResult<NonNull<ffi::PyTypeObject>>
where
F: Fn() -> PyResult<NonNull<ffi::PyTypeObject>>,
{
Ok(*self.0.get_or_try_init(constructor)?)
}
}

// This is necessary for making static `LazyException`s
//
// Type objects are shared between threads by the Python interpreter anyway, so it is no worse
// to allow sharing on the Rust side too.
unsafe impl Sync for LazyException {}

macro_rules! impl_native_exception (
($name:ident, $exc_name:ident) => (
pub struct $name;
Expand Down
7 changes: 5 additions & 2 deletions src/freelist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ where
{
unsafe fn alloc(_py: Python) -> *mut Self::ConcreteLayout {
if let Some(obj) = <Self as PyClassWithFreeList>::get_free_list().pop() {
ffi::PyObject_Init(obj, <Self as PyTypeInfo>::type_object().as_ptr() as *mut _);
ffi::PyObject_Init(
obj,
<Self as PyTypeInfo>::type_object() as *const _ as *mut _,
);
obj as _
} else {
crate::pyclass::default_alloc::<Self>() as _
Expand All @@ -90,7 +93,7 @@ where
}

if let Some(obj) = <Self as PyClassWithFreeList>::get_free_list().insert(obj) {
match Self::type_object().as_ref().tp_free {
match Self::type_object().tp_free {
Some(free) => free(obj as *mut c_void),
None => tp_free_fallback(obj),
}
Expand Down
19 changes: 8 additions & 11 deletions src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ use std::ptr::{self, NonNull};

#[inline]
pub(crate) unsafe fn default_alloc<T: PyTypeInfo>() -> *mut ffi::PyObject {
let tp_ptr = T::type_object().as_ptr();
let tp_ptr = T::type_object() as *const _ as *mut _;
if T::FLAGS & type_flags::EXTENDED != 0
&& <T::BaseType as PyTypeInfo>::ConcreteLayout::IS_NATIVE_TYPE
{
let base_tp = <T::BaseType as PyTypeInfo>::type_object();
if let Some(base_new) = base_tp.as_ref().tp_new {
if let Some(base_new) = base_tp.tp_new {
return base_new(tp_ptr, ptr::null_mut(), ptr::null_mut());
}
}
Expand Down Expand Up @@ -47,7 +47,7 @@ pub trait PyClassAlloc: PyTypeInfo + Sized {
return;
}

match Self::type_object().as_ref().tp_free {
match Self::type_object().tp_free {
Some(free) => free(obj as *mut c_void),
None => tp_free_fallback(obj),
}
Expand Down Expand Up @@ -253,17 +253,14 @@ where
}

#[cfg(not(Py_LIMITED_API))]
pub fn create_type_object<T>(
pub fn initialize_type_object<T>(
py: Python,
type_object: &mut ffi::PyTypeObject,
module_name: Option<&str>,
) -> PyResult<Box<ffi::PyTypeObject>>
) -> PyResult<()>
where
T: PyClass,
{
let mut boxed = Box::new(ffi::PyTypeObject_INIT);
let mut type_object = boxed.as_mut();
let base_type_object = <T::BaseType as PyTypeInfo>::type_object().as_ptr();

// PyPy will segfault if passed only a nul terminator as `tp_doc`.
// ptr::null() is OK though.
if T::DESCRIPTION == "\0" {
Expand All @@ -272,7 +269,7 @@ where
type_object.tp_doc = T::DESCRIPTION.as_ptr() as *const _;
};

type_object.tp_base = base_type_object;
type_object.tp_base = <T::BaseType as PyTypeInfo>::type_object() as *const _ as _;

let name = match module_name {
Some(module_name) => format!("{}.{}", module_name, T::NAME),
Expand Down Expand Up @@ -369,7 +366,7 @@ where
// register type object
unsafe {
if ffi::PyType_Ready(type_object) == 0 {
Ok(boxed)
Ok(())
} else {
PyErr::fetch(py).into()
}
Expand Down
38 changes: 4 additions & 34 deletions src/type_object.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
//! Python type object information

use crate::err::PyResult;
use crate::instance::Py;
use crate::pyclass_init::PyObjectInit;
use crate::types::{PyAny, PyType};
use crate::{ffi, AsPyPointer, Python};
use once_cell::sync::OnceCell;
use std::ptr::NonNull;

/// `T: PyObjectLayout<U>` represents that `T` is a concrete representaion of `U` in Python heap.
/// E.g., `PyClassShell` is a concrete representaion of all `pyclass`es, and `ffi::PyObject`
Expand Down Expand Up @@ -92,18 +88,18 @@ pub unsafe trait PyTypeInfo: Sized {
type Initializer: PyObjectInit<Self>;

/// PyTypeObject instance for this type, guaranteed to be global and initialized.
fn type_object() -> NonNull<ffi::PyTypeObject>;
fn type_object() -> &'static ffi::PyTypeObject;

/// Check if `*mut ffi::PyObject` is instance of this type
fn is_instance(object: &PyAny) -> bool {
unsafe {
ffi::PyObject_TypeCheck(object.as_ptr(), Self::type_object().as_ptr() as *mut _) != 0
ffi::PyObject_TypeCheck(object.as_ptr(), Self::type_object() as *const _ as _) != 0
}
}

/// Check if `*mut ffi::PyObject` is exact instance of this type
fn is_exact_instance(object: &PyAny) -> bool {
unsafe { (*object.as_ptr()).ob_type == Self::type_object().as_ptr() as *mut _ }
unsafe { (*object.as_ptr()).ob_type == Self::type_object() as *const _ as _ }
}
}

Expand All @@ -123,32 +119,6 @@ where
T: PyTypeInfo,
{
fn type_object() -> Py<PyType> {
unsafe { Py::from_borrowed_ptr(<Self as PyTypeInfo>::type_object().as_ptr() as *mut _) }
}
}

/// Type used to store type objects
pub struct LazyTypeObject {
cell: OnceCell<NonNull<ffi::PyTypeObject>>,
}

impl LazyTypeObject {
pub const fn new() -> Self {
Self {
cell: OnceCell::new(),
}
}

pub fn get_or_init<F>(&self, constructor: F) -> PyResult<NonNull<ffi::PyTypeObject>>
where
F: Fn() -> PyResult<NonNull<ffi::PyTypeObject>>,
{
Ok(*self.cell.get_or_try_init(constructor)?)
unsafe { Py::from_borrowed_ptr(<Self as PyTypeInfo>::type_object() as *const _ as _) }
}
}

// This is necessary for making static `LazyTypeObject`s
//
// Type objects are shared between threads by the Python interpreter anyway, so it is no worse
// to allow sharing on the Rust side too.
unsafe impl Sync for LazyTypeObject {}
4 changes: 2 additions & 2 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ macro_rules! pyobject_native_type_convert(
const MODULE: Option<&'static str> = $module;

#[inline]
fn type_object() -> std::ptr::NonNull<$crate::ffi::PyTypeObject> {
unsafe { std::ptr::NonNull::new_unchecked(&mut $typeobject as *mut _) }
fn type_object() -> &'static $crate::ffi::PyTypeObject {
unsafe { &$typeobject }
}

#[allow(unused_unsafe)]
Expand Down
Empty file modified tests/test_arithmetics.rs
100644 → 100755
Empty file.

0 comments on commit 5d13505

Please sign in to comment.