use crate::pyclass::{initialize_type_object, PyClass};
use crate::pyclass_init::PyObjectInit;
use crate::types::{PyAny, PyType};
use crate::{ffi, AsPyPointer, Py, Python};
use std::cell::UnsafeCell;
use std::ptr::NonNull;
use std::sync::atomic::{AtomicBool, Ordering};
pub unsafe trait PyLayout<T: PyTypeInfo> {
const IS_NATIVE_TYPE: bool = true;
fn get_super(&mut self) -> Option<&mut T::BaseLayout> {
None
}
unsafe fn py_init(&mut self, _value: T) {}
unsafe fn py_drop(&mut self, _py: Python) {}
}
pub trait PySizedLayout<T: PyTypeInfo>: PyLayout<T> + Sized {}
pub unsafe trait PyBorrowFlagLayout<T: PyTypeInfo>: PyLayout<T> + Sized {}
#[doc(hidden)]
pub mod type_flags {
pub const GC: usize = 1;
pub const WEAKREF: usize = 1 << 1;
pub const BASETYPE: usize = 1 << 2;
pub const DICT: usize = 1 << 3;
pub const EXTENDED: usize = 1 << 4;
}
pub unsafe trait PyTypeInfo: Sized {
type Type;
const NAME: &'static str;
const MODULE: Option<&'static str>;
const DESCRIPTION: &'static str = "\0";
const FLAGS: usize = 0;
type BaseType: PyTypeInfo + PyTypeObject;
type Layout: PyLayout<Self>;
type BaseLayout: PySizedLayout<Self::BaseType>;
type Initializer: PyObjectInit<Self>;
type AsRefTarget: crate::PyNativeType;
fn type_object() -> &'static ffi::PyTypeObject;
fn is_instance(object: &PyAny) -> bool {
unsafe {
ffi::PyObject_TypeCheck(object.as_ptr(), Self::type_object() as *const _ as _) != 0
}
}
fn is_exact_instance(object: &PyAny) -> bool {
unsafe { (*object.as_ptr()).ob_type == Self::type_object() as *const _ as _ }
}
}
pub unsafe trait PyTypeObject {
fn type_object() -> Py<PyType>;
}
unsafe impl<T> PyTypeObject for T
where
T: PyTypeInfo,
{
fn type_object() -> Py<PyType> {
unsafe { Py::from_borrowed_ptr(<Self as PyTypeInfo>::type_object() as *const _ as _) }
}
}
#[doc(hidden)]
pub struct LazyHeapType {
value: UnsafeCell<Option<NonNull<ffi::PyTypeObject>>>,
initialized: AtomicBool,
}
impl LazyHeapType {
pub const fn new() -> Self {
LazyHeapType {
value: UnsafeCell::new(None),
initialized: AtomicBool::new(false),
}
}
pub fn get_or_init<F>(&self, constructor: F) -> NonNull<ffi::PyTypeObject>
where
F: Fn(Python) -> NonNull<ffi::PyTypeObject>,
{
if !self
.initialized
.compare_and_swap(false, true, Ordering::Acquire)
{
let gil = Python::acquire_gil();
unsafe {
*self.value.get() = Some(constructor(gil.python()));
}
}
unsafe { (*self.value.get()).unwrap() }
}
}
unsafe impl Sync for LazyHeapType {}
#[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() }
}
}
unsafe impl Sync for LazyStaticType {}