Merge pull request #758 from kngwyu/remove-oncecell
Lazy type objects without once_cell
This commit is contained in:
commit
6069ee1239
|
@ -29,7 +29,6 @@ parking_lot = { version = "0.10", features = ["nightly"] }
|
|||
paste = "0.1.6"
|
||||
pyo3cls = { path = "pyo3cls", version = "=0.9.0-alpha.1" }
|
||||
unindent = "0.1.4"
|
||||
once_cell = "1.3.1"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_approx_eq = "1.1.0"
|
||||
|
|
|
@ -43,10 +43,10 @@ unsafe impl pyo3::PyTypeInfo for MyClass {
|
|||
const FLAGS: usize = 0;
|
||||
|
||||
#[inline]
|
||||
fn type_object() -> std::ptr::NonNull<pyo3::ffi::PyTypeObject> {
|
||||
use pyo3::type_object::LazyTypeObject;
|
||||
static TYPE_OBJECT: LazyTypeObject = LazyTypeObject::new();
|
||||
TYPE_OBJECT.get_pyclass_type::<Self>()
|
||||
fn type_object() -> &'static pyo3::ffi::PyTypeObject {
|
||||
use pyo3::type_object::LazyStaticType;
|
||||
static TYPE_OBJECT: LazyStaticType = LazyStaticType::new();
|
||||
TYPE_OBJECT.get_or_init::<Self>()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -382,10 +382,10 @@ fn impl_class(
|
|||
const FLAGS: usize = #(#flags)|* | #extended;
|
||||
|
||||
#[inline]
|
||||
fn type_object() -> std::ptr::NonNull<pyo3::ffi::PyTypeObject> {
|
||||
use pyo3::type_object::LazyTypeObject;
|
||||
static TYPE_OBJECT: LazyTypeObject = LazyTypeObject::new();
|
||||
TYPE_OBJECT.get_pyclass_type::<Self>()
|
||||
fn type_object() -> &'static pyo3::ffi::PyTypeObject {
|
||||
use pyo3::type_object::LazyStaticType;
|
||||
static TYPE_OBJECT: LazyStaticType = LazyStaticType::new();
|
||||
TYPE_OBJECT.get_or_init::<Self>()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ use crate::types::{PyAny, PyTuple};
|
|||
use crate::Python;
|
||||
use crate::{AsPyPointer, ToPyObject};
|
||||
use std::ffi::CStr;
|
||||
use std::ops;
|
||||
use std::os::raw::c_char;
|
||||
use std::{self, ops};
|
||||
|
||||
/// The boilerplate to convert between a rust type and a python exception
|
||||
#[macro_export]
|
||||
|
@ -90,31 +90,26 @@ 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::type_object::LazyHeapType;
|
||||
static TYPE_OBJECT: LazyHeapType = LazyHeapType::new();
|
||||
|
||||
let ptr = TYPE_OBJECT
|
||||
.get_or_init(|| {
|
||||
let gil = $crate::Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let ptr = TYPE_OBJECT.get_or_init(|py| {
|
||||
let imp = py
|
||||
.import(stringify!($module))
|
||||
.expect(concat!("Can not import module: ", stringify!($module)));
|
||||
let cls = imp.get(stringify!($name)).expect(concat!(
|
||||
"Can not load exception class: {}.{}",
|
||||
stringify!($module),
|
||||
".",
|
||||
stringify!($name)
|
||||
));
|
||||
|
||||
let imp = py
|
||||
.import(stringify!($module))
|
||||
.expect(concat!("Can not import module: ", stringify!($module)));
|
||||
let cls = imp.get(stringify!($name)).expect(concat!(
|
||||
"Can not load exception class: {}.{}",
|
||||
stringify!($module),
|
||||
".",
|
||||
stringify!($name)
|
||||
));
|
||||
|
||||
unsafe {
|
||||
Ok(std::ptr::NonNull::new_unchecked(
|
||||
$crate::IntoPyPointer::into_ptr(cls) as *mut _,
|
||||
))
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
unsafe {
|
||||
std::ptr::NonNull::new_unchecked(
|
||||
$crate::IntoPyPointer::into_ptr(cls) as *mut _
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
unsafe { $crate::Py::from_borrowed_ptr(ptr.as_ptr() as *mut $crate::ffi::PyObject) }
|
||||
}
|
||||
|
@ -178,22 +173,17 @@ 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::type_object::LazyHeapType;
|
||||
static TYPE_OBJECT: LazyHeapType = LazyHeapType::new();
|
||||
|
||||
let ptr = TYPE_OBJECT
|
||||
.get_or_init(|| {
|
||||
let gil = $crate::Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
Ok($crate::PyErr::new_type(
|
||||
py,
|
||||
concat!(stringify!($module), ".", stringify!($name)),
|
||||
Some(py.get_type::<$base>()),
|
||||
None,
|
||||
))
|
||||
})
|
||||
.unwrap();
|
||||
let ptr = TYPE_OBJECT.get_or_init(|py| {
|
||||
$crate::PyErr::new_type(
|
||||
py,
|
||||
concat!(stringify!($module), ".", stringify!($name)),
|
||||
Some(py.get_type::<$base>()),
|
||||
None,
|
||||
)
|
||||
});
|
||||
|
||||
unsafe { $crate::Py::from_borrowed_ptr(ptr.as_ptr() as *mut $crate::ffi::PyObject) }
|
||||
}
|
||||
|
|
|
@ -177,23 +177,23 @@ mod bufferinfo {
|
|||
pub const PyBUF_WRITEABLE: c_int = PyBUF_WRITABLE;
|
||||
pub const PyBUF_FORMAT: c_int = 0x0004;
|
||||
pub const PyBUF_ND: c_int = 0x0008;
|
||||
pub const PyBUF_STRIDES: c_int = (0x0010 | PyBUF_ND);
|
||||
pub const PyBUF_C_CONTIGUOUS: c_int = (0x0020 | PyBUF_STRIDES);
|
||||
pub const PyBUF_F_CONTIGUOUS: c_int = (0x0040 | PyBUF_STRIDES);
|
||||
pub const PyBUF_ANY_CONTIGUOUS: c_int = (0x0080 | PyBUF_STRIDES);
|
||||
pub const PyBUF_INDIRECT: c_int = (0x0100 | PyBUF_STRIDES);
|
||||
pub const PyBUF_STRIDES: c_int = 0x0010 | PyBUF_ND;
|
||||
pub const PyBUF_C_CONTIGUOUS: c_int = 0x0020 | PyBUF_STRIDES;
|
||||
pub const PyBUF_F_CONTIGUOUS: c_int = 0x0040 | PyBUF_STRIDES;
|
||||
pub const PyBUF_ANY_CONTIGUOUS: c_int = 0x0080 | PyBUF_STRIDES;
|
||||
pub const PyBUF_INDIRECT: c_int = 0x0100 | PyBUF_STRIDES;
|
||||
|
||||
pub const PyBUF_CONTIG: c_int = (PyBUF_ND | PyBUF_WRITABLE);
|
||||
pub const PyBUF_CONTIG_RO: c_int = (PyBUF_ND);
|
||||
pub const PyBUF_CONTIG: c_int = PyBUF_ND | PyBUF_WRITABLE;
|
||||
pub const PyBUF_CONTIG_RO: c_int = PyBUF_ND;
|
||||
|
||||
pub const PyBUF_STRIDED: c_int = (PyBUF_STRIDES | PyBUF_WRITABLE);
|
||||
pub const PyBUF_STRIDED_RO: c_int = (PyBUF_STRIDES);
|
||||
pub const PyBUF_STRIDED: c_int = PyBUF_STRIDES | PyBUF_WRITABLE;
|
||||
pub const PyBUF_STRIDED_RO: c_int = PyBUF_STRIDES;
|
||||
|
||||
pub const PyBUF_RECORDS: c_int = (PyBUF_STRIDES | PyBUF_WRITABLE | PyBUF_FORMAT);
|
||||
pub const PyBUF_RECORDS_RO: c_int = (PyBUF_STRIDES | PyBUF_FORMAT);
|
||||
pub const PyBUF_RECORDS: c_int = PyBUF_STRIDES | PyBUF_WRITABLE | PyBUF_FORMAT;
|
||||
pub const PyBUF_RECORDS_RO: c_int = PyBUF_STRIDES | PyBUF_FORMAT;
|
||||
|
||||
pub const PyBUF_FULL: c_int = (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT);
|
||||
pub const PyBUF_FULL_RO: c_int = (PyBUF_INDIRECT | PyBUF_FORMAT);
|
||||
pub const PyBUF_FULL: c_int = PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT;
|
||||
pub const PyBUF_FULL_RO: c_int = PyBUF_INDIRECT | PyBUF_FORMAT;
|
||||
|
||||
pub const PyBUF_READ: c_int = 0x100;
|
||||
pub const PyBUF_WRITE: c_int = 0x200;
|
||||
|
@ -848,42 +848,42 @@ extern "C" {
|
|||
pub const Py_PRINT_RAW: c_int = 1; // No string quotes etc.
|
||||
|
||||
/// Set if the type object is dynamically allocated
|
||||
pub const Py_TPFLAGS_HEAPTYPE: c_ulong = (1 << 9);
|
||||
pub const Py_TPFLAGS_HEAPTYPE: c_ulong = 1 << 9;
|
||||
|
||||
/// Set if the type allows subclassing
|
||||
pub const Py_TPFLAGS_BASETYPE: c_ulong = (1 << 10);
|
||||
pub const Py_TPFLAGS_BASETYPE: c_ulong = 1 << 10;
|
||||
|
||||
/// Set if the type implements the vectorcall protocol (PEP 590)
|
||||
#[cfg(all(Py_3_8, not(Py_LIMITED_API)))]
|
||||
pub const _Py_TPFLAGS_HAVE_VECTORCALL: c_ulong = (1 << 11);
|
||||
pub const _Py_TPFLAGS_HAVE_VECTORCALL: c_ulong = 1 << 11;
|
||||
|
||||
/// Set if the type is 'ready' -- fully initialized
|
||||
pub const Py_TPFLAGS_READY: c_ulong = (1 << 12);
|
||||
pub const Py_TPFLAGS_READY: c_ulong = 1 << 12;
|
||||
|
||||
/// Set while the type is being 'readied', to prevent recursive ready calls
|
||||
pub const Py_TPFLAGS_READYING: c_ulong = (1 << 13);
|
||||
pub const Py_TPFLAGS_READYING: c_ulong = 1 << 13;
|
||||
|
||||
/// Objects support garbage collection (see objimp.h)
|
||||
pub const Py_TPFLAGS_HAVE_GC: c_ulong = (1 << 14);
|
||||
pub const Py_TPFLAGS_HAVE_GC: c_ulong = 1 << 14;
|
||||
|
||||
const Py_TPFLAGS_HAVE_STACKLESS_EXTENSION: c_ulong = 0;
|
||||
|
||||
/// Objects support type attribute cache
|
||||
pub const Py_TPFLAGS_HAVE_VERSION_TAG: c_ulong = (1 << 18);
|
||||
pub const Py_TPFLAGS_VALID_VERSION_TAG: c_ulong = (1 << 19);
|
||||
pub const Py_TPFLAGS_HAVE_VERSION_TAG: c_ulong = 1 << 18;
|
||||
pub const Py_TPFLAGS_VALID_VERSION_TAG: c_ulong = 1 << 19;
|
||||
|
||||
/* Type is abstract and cannot be instantiated */
|
||||
pub const Py_TPFLAGS_IS_ABSTRACT: c_ulong = (1 << 20);
|
||||
pub const Py_TPFLAGS_IS_ABSTRACT: c_ulong = 1 << 20;
|
||||
|
||||
/* These flags are used to determine if a type is a subclass. */
|
||||
pub const Py_TPFLAGS_LONG_SUBCLASS: c_ulong = (1 << 24);
|
||||
pub const Py_TPFLAGS_LIST_SUBCLASS: c_ulong = (1 << 25);
|
||||
pub const Py_TPFLAGS_TUPLE_SUBCLASS: c_ulong = (1 << 26);
|
||||
pub const Py_TPFLAGS_BYTES_SUBCLASS: c_ulong = (1 << 27);
|
||||
pub const Py_TPFLAGS_UNICODE_SUBCLASS: c_ulong = (1 << 28);
|
||||
pub const Py_TPFLAGS_DICT_SUBCLASS: c_ulong = (1 << 29);
|
||||
pub const Py_TPFLAGS_BASE_EXC_SUBCLASS: c_ulong = (1 << 30);
|
||||
pub const Py_TPFLAGS_TYPE_SUBCLASS: c_ulong = (1 << 31);
|
||||
pub const Py_TPFLAGS_LONG_SUBCLASS: c_ulong = 1 << 24;
|
||||
pub const Py_TPFLAGS_LIST_SUBCLASS: c_ulong = 1 << 25;
|
||||
pub const Py_TPFLAGS_TUPLE_SUBCLASS: c_ulong = 1 << 26;
|
||||
pub const Py_TPFLAGS_BYTES_SUBCLASS: c_ulong = 1 << 27;
|
||||
pub const Py_TPFLAGS_UNICODE_SUBCLASS: c_ulong = 1 << 28;
|
||||
pub const Py_TPFLAGS_DICT_SUBCLASS: c_ulong = 1 << 29;
|
||||
pub const Py_TPFLAGS_BASE_EXC_SUBCLASS: c_ulong = 1 << 30;
|
||||
pub const Py_TPFLAGS_TYPE_SUBCLASS: c_ulong = 1 << 31;
|
||||
|
||||
pub const Py_TPFLAGS_DEFAULT: c_ulong =
|
||||
Py_TPFLAGS_HAVE_STACKLESS_EXTENSION | Py_TPFLAGS_HAVE_VERSION_TAG;
|
||||
|
|
|
@ -49,7 +49,7 @@ pub const T_NONE: c_int = 20; /* Value is always None */
|
|||
pub const READONLY: c_int = 1;
|
||||
pub const READ_RESTRICTED: c_int = 2;
|
||||
pub const PY_WRITE_RESTRICTED: c_int = 4;
|
||||
pub const RESTRICTED: c_int = (READ_RESTRICTED | PY_WRITE_RESTRICTED);
|
||||
pub const RESTRICTED: c_int = READ_RESTRICTED | PY_WRITE_RESTRICTED;
|
||||
|
||||
#[cfg_attr(windows, link(name = "pythonXY"))]
|
||||
extern "C" {
|
||||
|
|
|
@ -74,7 +74,7 @@ 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 _);
|
||||
obj as _
|
||||
} else {
|
||||
crate::pyclass::default_alloc::<Self>() as _
|
||||
|
@ -90,7 +90,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),
|
||||
}
|
||||
|
|
|
@ -13,17 +13,17 @@ 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 type_obj = T::type_object();
|
||||
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 {
|
||||
return base_new(tp_ptr, ptr::null_mut(), ptr::null_mut());
|
||||
if let Some(base_new) = base_tp.tp_new {
|
||||
return base_new(type_obj as *const _ as _, ptr::null_mut(), ptr::null_mut());
|
||||
}
|
||||
}
|
||||
let alloc = (*tp_ptr).tp_alloc.unwrap_or(ffi::PyType_GenericAlloc);
|
||||
alloc(tp_ptr, 0)
|
||||
let alloc = type_obj.tp_alloc.unwrap_or(ffi::PyType_GenericAlloc);
|
||||
alloc(type_obj as *const _ as _, 0)
|
||||
}
|
||||
|
||||
/// This trait enables custom alloc/dealloc implementations for `T: PyClass`.
|
||||
|
@ -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),
|
||||
}
|
||||
|
@ -253,19 +253,14 @@ where
|
|||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub(crate) fn create_type_object<T>(
|
||||
pub(crate) fn initialize_type_object<T>(
|
||||
py: Python,
|
||||
module_name: Option<&str>,
|
||||
) -> PyResult<Box<ffi::PyTypeObject>>
|
||||
type_object: &mut ffi::PyTypeObject,
|
||||
) -> PyResult<()>
|
||||
where
|
||||
T: PyClass,
|
||||
{
|
||||
// Box (or some other heap allocation) is needed because PyType_Ready expects the type object
|
||||
// to have a permanent memory address.
|
||||
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" {
|
||||
|
@ -274,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),
|
||||
|
@ -371,7 +366,7 @@ where
|
|||
// register type object
|
||||
unsafe {
|
||||
if ffi::PyType_Ready(type_object) == 0 {
|
||||
Ok(boxed)
|
||||
Ok(())
|
||||
} else {
|
||||
PyErr::fetch(py).into()
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
//! Python type object information
|
||||
|
||||
use crate::err::PyResult;
|
||||
use crate::instance::Py;
|
||||
use crate::pyclass::{create_type_object, PyClass};
|
||||
use crate::pyclass::{initialize_type_object, PyClass};
|
||||
use crate::pyclass_init::PyObjectInit;
|
||||
use crate::types::{PyAny, PyType};
|
||||
use crate::{ffi, AsPyPointer, Python};
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::ptr::NonNull;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
/// `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`
|
||||
|
@ -92,19 +92,19 @@ pub unsafe trait PyTypeInfo: Sized {
|
|||
/// Initializer for layout
|
||||
type Initializer: PyObjectInit<Self>;
|
||||
|
||||
/// PyTypeObject instance for this type, guaranteed to be global and initialized.
|
||||
fn type_object() -> NonNull<ffi::PyTypeObject>;
|
||||
/// PyTypeObject instance for this type.
|
||||
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 _ }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,49 +124,80 @@ where
|
|||
T: PyTypeInfo,
|
||||
{
|
||||
fn type_object() -> Py<PyType> {
|
||||
unsafe { Py::from_borrowed_ptr(<Self as PyTypeInfo>::type_object().as_ptr() as *mut _) }
|
||||
unsafe { Py::from_borrowed_ptr(<Self as PyTypeInfo>::type_object() as *const _ as _) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Type used to store static type objects
|
||||
/// Lazy type object for Exceptions
|
||||
#[doc(hidden)]
|
||||
pub struct LazyTypeObject {
|
||||
cell: OnceCell<NonNull<ffi::PyTypeObject>>,
|
||||
pub struct LazyHeapType {
|
||||
value: UnsafeCell<Option<NonNull<ffi::PyTypeObject>>>,
|
||||
initialized: AtomicBool,
|
||||
}
|
||||
|
||||
impl LazyTypeObject {
|
||||
impl LazyHeapType {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
cell: OnceCell::new(),
|
||||
LazyHeapType {
|
||||
value: UnsafeCell::new(None),
|
||||
initialized: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_or_init<F>(&self, constructor: F) -> PyResult<NonNull<ffi::PyTypeObject>>
|
||||
pub fn get_or_init<F>(&self, constructor: F) -> NonNull<ffi::PyTypeObject>
|
||||
where
|
||||
F: Fn() -> PyResult<NonNull<ffi::PyTypeObject>>,
|
||||
F: Fn(Python) -> NonNull<ffi::PyTypeObject>,
|
||||
{
|
||||
Ok(*self.cell.get_or_try_init(constructor)?)
|
||||
}
|
||||
|
||||
pub fn get_pyclass_type<T: PyClass>(&self) -> NonNull<ffi::PyTypeObject> {
|
||||
self.get_or_init(|| {
|
||||
// automatically initialize the class on-demand
|
||||
if !self
|
||||
.initialized
|
||||
.compare_and_swap(false, true, Ordering::Acquire)
|
||||
{
|
||||
// We have to get the GIL before setting the value to the global!!!
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let boxed = create_type_object::<T>(py, T::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 {}", T::NAME)
|
||||
})
|
||||
unsafe {
|
||||
*self.value.get() = Some(constructor(gil.python()));
|
||||
}
|
||||
}
|
||||
unsafe { (*self.value.get()).unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
// This is necessary for making static `LazyTypeObject`s
|
||||
// This is necessary for making static `LazyHeapType`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 {}
|
||||
unsafe impl Sync for LazyHeapType {}
|
||||
|
||||
/// Lazy type object for PyClass
|
||||
#[doc(hidden)]
|
||||
pub struct LazyStaticType {
|
||||
value: UnsafeCell<ffi::PyTypeObject>,
|
||||
initialized: AtomicBool,
|
||||
}
|
||||
|
||||
impl LazyStaticType {
|
||||
pub const fn new() -> Self {
|
||||
LazyStaticType {
|
||||
value: UnsafeCell::new(ffi::PyTypeObject_INIT),
|
||||
initialized: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_or_init<T: PyClass>(&self) -> &ffi::PyTypeObject {
|
||||
if !self
|
||||
.initialized
|
||||
.compare_and_swap(false, true, Ordering::Acquire)
|
||||
{
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
initialize_type_object::<T>(py, T::MODULE, unsafe { &mut *self.value.get() })
|
||||
.unwrap_or_else(|e| {
|
||||
e.print(py);
|
||||
panic!("An error occurred while initializing class {}", T::NAME)
|
||||
});
|
||||
}
|
||||
unsafe { &*self.value.get() }
|
||||
}
|
||||
}
|
||||
|
||||
// This is necessary for making static `LazyStaticType`s
|
||||
unsafe impl Sync for LazyStaticType {}
|
||||
|
|
|
@ -124,8 +124,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)]
|
||||
|
|
Loading…
Reference in a new issue