use std::{mem, ptr};
use crate::err::PyResult;
use crate::ffi;
use crate::objects::PyType;
use crate::python::{
Python, PythonObject, PythonObjectDowncastError, PythonObjectWithCheckedDowncast,
PythonObjectWithTypeObject,
};
#[repr(C)]
pub struct PyObject {
ptr: ptr::NonNull<ffi::PyObject>,
}
unsafe impl Send for PyObject {}
unsafe impl Sync for PyObject {}
impl Drop for PyObject {
fn drop(&mut self) {
let _gil_guard = Python::acquire_gil();
unsafe {
ffi::Py_DECREF(self.ptr.as_ptr());
}
}
}
impl PythonObject for PyObject {
#[inline]
fn as_object(&self) -> &PyObject {
self
}
#[inline]
fn into_object(self) -> PyObject {
self
}
#[inline]
unsafe fn unchecked_downcast_from(o: PyObject) -> PyObject {
o
}
#[inline]
unsafe fn unchecked_downcast_borrow_from(o: &PyObject) -> &PyObject {
o
}
}
impl PythonObjectWithCheckedDowncast for PyObject {
#[inline]
fn downcast_from(
_py: Python<'_>,
obj: PyObject,
) -> Result<PyObject, PythonObjectDowncastError<'_>> {
Ok(obj)
}
#[inline]
fn downcast_borrow_from<'a, 'p>(
_py: Python<'p>,
obj: &'a PyObject,
) -> Result<&'a PyObject, PythonObjectDowncastError<'p>> {
Ok(obj)
}
}
impl PythonObjectWithTypeObject for PyObject {
#[inline]
fn type_object(py: Python) -> PyType {
unsafe { PyType::from_type_ptr(py, &mut ffi::PyBaseObject_Type) }
}
}
impl PyObject {
#[inline]
pub unsafe fn from_owned_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyObject {
debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0);
PyObject {
ptr: ptr::NonNull::new_unchecked(ptr),
}
}
#[inline]
pub unsafe fn from_borrowed_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyObject {
debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0);
ffi::Py_INCREF(ptr);
PyObject {
ptr: ptr::NonNull::new_unchecked(ptr),
}
}
#[inline]
pub unsafe fn from_owned_ptr_opt(py: Python, ptr: *mut ffi::PyObject) -> Option<PyObject> {
if ptr.is_null() {
None
} else {
Some(PyObject::from_owned_ptr(py, ptr))
}
}
#[inline]
pub unsafe fn from_borrowed_ptr_opt(py: Python, ptr: *mut ffi::PyObject) -> Option<PyObject> {
if ptr.is_null() {
None
} else {
Some(PyObject::from_borrowed_ptr(py, ptr))
}
}
#[inline]
pub fn as_ptr(&self) -> *mut ffi::PyObject {
self.ptr.as_ptr()
}
#[inline]
#[must_use]
pub fn steal_ptr(self) -> *mut ffi::PyObject {
let ptr = self.as_ptr();
mem::forget(self);
ptr
}
#[inline]
pub unsafe fn borrow_from_ptr(ptr: &*mut ffi::PyObject) -> &PyObject {
debug_assert!(!ptr.is_null());
mem::transmute(ptr)
}
#[inline]
pub unsafe fn borrow_from_owned_ptr_slice(ptr: &[*mut ffi::PyObject]) -> &[PyObject] {
mem::transmute(ptr)
}
#[inline]
pub fn get_refcnt(&self, _py: Python) -> usize {
unsafe { ffi::Py_REFCNT(self.as_ptr()) as usize }
}
pub fn get_type(&self, py: Python) -> PyType {
unsafe { PyType::from_type_ptr(py, (*self.as_ptr()).ob_type) }
}
#[inline]
pub unsafe fn unchecked_cast_into<T>(self) -> T
where
T: PythonObject,
{
PythonObject::unchecked_downcast_from(self)
}
#[inline]
pub fn cast_into<T>(self, py: Python<'_>) -> Result<T, PythonObjectDowncastError<'_>>
where
T: PythonObjectWithCheckedDowncast,
{
PythonObjectWithCheckedDowncast::downcast_from(py, self)
}
#[inline]
pub unsafe fn unchecked_cast_as<T>(&self) -> &T
where
T: PythonObject,
{
PythonObject::unchecked_downcast_borrow_from(self)
}
#[inline]
pub fn cast_as<'s, 'p, T>(
&'s self,
py: Python<'p>,
) -> Result<&'s T, PythonObjectDowncastError<'p>>
where
T: PythonObjectWithCheckedDowncast,
{
PythonObjectWithCheckedDowncast::downcast_borrow_from(py, self)
}
#[inline]
pub fn extract<'a, T>(&'a self, py: Python) -> PyResult<T>
where
T: crate::conversion::FromPyObject<'a>,
{
crate::conversion::FromPyObject::extract(py, self)
}
#[inline]
pub fn is_none(&self, _py: Python) -> bool {
self.as_ptr() == unsafe { ffi::Py_None() }
}
}
impl PartialEq for PyObject {
#[inline]
fn eq(&self, o: &PyObject) -> bool {
self.as_ptr() == o.as_ptr()
}
}
impl Eq for PyObject {}
#[test]
fn test_sizeof() {
assert_eq!(
mem::size_of::<PyObject>(),
mem::size_of::<*mut ffi::PyObject>()
);
assert_eq!(
mem::size_of::<PyType>(),
mem::size_of::<*mut ffi::PyTypeObject>()
);
}