use std::{mem, ptr};
use ffi;
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject, PythonObjectDowncastError};
use objects::PyType;
use err::PyResult;
#[repr(C)]
pub struct PyObject {
#[cfg(feature="nightly")]
ptr: ptr::Shared<ffi::PyObject>,
#[cfg(not(feature="nightly"))]
ptr: *mut 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(unpack_shared(self.ptr)); }
}
}
#[inline]
#[cfg(feature="nightly")]
unsafe fn make_shared(ptr: *mut ffi::PyObject) -> ptr::Shared<ffi::PyObject> {
ptr::Shared::new(ptr).expect("ptr should not be null")
}
#[inline]
#[cfg(not(feature="nightly"))]
unsafe fn make_shared(ptr: *mut ffi::PyObject) -> *mut ffi::PyObject {
ptr
}
#[inline]
#[cfg(feature="nightly")]
fn unpack_shared(ptr: ptr::Shared<ffi::PyObject>) -> *mut ffi::PyObject {
ptr.as_ptr()
}
#[inline]
#[cfg(not(feature="nightly"))]
fn unpack_shared(ptr: *mut ffi::PyObject) -> *mut ffi::PyObject {
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<'p>(_py: Python<'p>, obj: PyObject) -> Result<PyObject, PythonObjectDowncastError<'p>> {
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: make_shared(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: make_shared(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 {
unpack_shared(self.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<'a>(ptr : &'a *mut ffi::PyObject) -> &'a PyObject {
debug_assert!(!ptr.is_null());
mem::transmute(ptr)
}
#[inline]
pub unsafe fn borrow_from_owned_ptr_slice<'a>(ptr : &'a [*mut ffi::PyObject]) -> &'a [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<'p, T>(self, py: Python<'p>) -> Result<T, PythonObjectDowncastError<'p>>
where T: PythonObjectWithCheckedDowncast
{
PythonObjectWithCheckedDowncast::downcast_from(py, self)
}
#[inline]
pub unsafe fn unchecked_cast_as<'s, T>(&'s self) -> &'s 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: ::conversion::FromPyObject<'a>
{
::conversion::FromPyObject::extract(py, self)
}
}
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>());
}