// Copyright (c) 2017-present PyO3 Project and Contributors use crate::conversion::{FromPyObject, IntoPyObject, ToPyObject}; use crate::err::{PyErr, PyResult}; use crate::ffi; use crate::instance; use crate::object::PyObject; use crate::objectprotocol::ObjectProtocol; use crate::python::{IntoPyPointer, Python, ToPyPointer}; use crate::pythonrun; use crate::typeob::PyTypeCreate; use crate::typeob::{PyTypeInfo, PyTypeObject}; use crate::types::PyObjectRef; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; use std::ptr::NonNull; use std::rc::Rc; /// Any instance that is managed Python can have access to `gil`. /// /// Originally, this was given to all classes with a `PyToken` field, but since `PyToken` was /// removed this is only given to native types. pub trait PyObjectWithGIL: Sized { fn py(&self) -> Python; } #[doc(hidden)] pub trait PyNativeType: PyObjectWithGIL {} /// A special reference of type `T`. `PyRef` refers a instance of T, which exists in the Python /// heap as a part of a Python object. /// /// We can't implement `ToPyPointer` or `ToPyObject` for `pyclass`es, because they're not Python /// objects until copied to the Python heap. So, instead of treating `&pyclass`es as Python objects, /// we need to use special reference types `PyRef` and `PyRefMut`. /// /// # Example /// /// ``` /// use pyo3::prelude::*; /// use pyo3::types::IntoPyDict; /// #[pyclass] /// struct Point { /// x: i32, /// y: i32, /// } /// #[pymethods] /// impl Point { /// fn length(&self) -> i32 { /// self.x * self.y /// } /// } /// let gil = Python::acquire_gil(); /// let py = gil.python(); /// let obj = PyRef::new(gil.python(), || Point { x: 3, y: 4 }).unwrap(); /// let d = vec![("p", obj)].into_py_dict(py); /// py.run("assert p.length() == 12", None, Some(d)).unwrap(); /// ``` #[derive(Debug)] pub struct PyRef<'a, T: PyTypeInfo>(&'a T, PhantomData>); impl<'a, T: PyTypeInfo> PyRef<'a, T> { pub(crate) fn from_ref(r: &'a T) -> Self { PyRef(r, PhantomData) } } impl<'a, T> PyRef<'a, T> where T: PyTypeInfo + PyTypeObject + PyTypeCreate, { pub fn new(py: Python, f: F) -> PyResult> where F: FnOnce() -> T, { let obj = T::create(py)?; obj.init(f)?; let ref_ = unsafe { py.from_owned_ptr(obj.into_ptr()) }; Ok(PyRef::from_ref(ref_)) } } impl<'a, T: PyTypeInfo> ToPyPointer for PyRef<'a, T> { fn as_ptr(&self) -> *mut ffi::PyObject { self.0.as_ptr_dispatch() } } impl<'a, T: PyTypeInfo> ToPyObject for PyRef<'a, T> { fn to_object(&self, py: Python) -> PyObject { unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) } } } impl<'a, T: PyTypeInfo> Deref for PyRef<'a, T> { type Target = T; fn deref(&self) -> &T { self.0 } } /// Mutable version of [`PyRef`](struct.PyRef.html). /// # Example /// ``` /// use pyo3::prelude::*; /// use pyo3::types::IntoPyDict; /// #[pyclass] /// struct Point { /// x: i32, /// y: i32, /// } /// #[pymethods] /// impl Point { /// fn length(&self) -> i32 { /// self.x * self.y /// } /// } /// let gil = Python::acquire_gil(); /// let py = gil.python(); /// let mut obj = PyRefMut::new(gil.python(), || Point { x: 3, y: 4 }).unwrap(); /// let d = vec![("p", obj.to_object(py))].into_py_dict(py); /// obj.x = 5; obj.y = 20; /// py.run("assert p.length() == 100", None, Some(d)).unwrap(); /// ``` #[derive(Debug)] pub struct PyRefMut<'a, T: PyTypeInfo>(&'a mut T, PhantomData>); impl<'a, T: PyTypeInfo> PyRefMut<'a, T> { pub(crate) fn from_mut(t: &'a mut T) -> Self { PyRefMut(t, PhantomData) } } impl<'a, T> PyRefMut<'a, T> where T: PyTypeInfo + PyTypeObject + PyTypeCreate, { pub fn new(py: Python, f: F) -> PyResult> where F: FnOnce() -> T, { let obj = T::create(py)?; obj.init(f)?; let ref_ = unsafe { py.mut_from_owned_ptr(obj.into_ptr()) }; Ok(PyRefMut::from_mut(ref_)) } } impl<'a, T: PyTypeInfo> ToPyPointer for PyRefMut<'a, T> { fn as_ptr(&self) -> *mut ffi::PyObject { (self.0 as &T).as_ptr_dispatch() } } impl<'a, T: PyTypeInfo> ToPyObject for PyRefMut<'a, T> { fn to_object(&self, py: Python) -> PyObject { unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) } } } impl<'a, T: PyTypeInfo> Deref for PyRefMut<'a, T> { type Target = T; fn deref(&self) -> &T { self.0 } } impl<'a, T: PyTypeInfo> DerefMut for PyRefMut<'a, T> { fn deref_mut(&mut self) -> &mut T { self.0 } } impl<'a, T> From> for &'a PyObjectRef where T: PyTypeInfo, { fn from(pref: PyRef<'a, T>) -> &'a PyObjectRef { unsafe { &*(pref.as_ptr() as *const PyObjectRef) } } } impl<'a, T> From> for &'a PyObjectRef where T: PyTypeInfo, { fn from(pref: PyRefMut<'a, T>) -> &'a PyObjectRef { unsafe { &*(pref.as_ptr() as *const PyObjectRef) } } } /// Specialization workaround trait PyRefDispatch { #[allow(clippy::cast_ptr_alignment)] fn as_ptr_dispatch(&self) -> *mut ffi::PyObject { unsafe { (self as *const _ as *mut u8).offset(-T::OFFSET) as *mut _ } } } impl PyRefDispatch for T {} impl PyRefDispatch for T { fn as_ptr_dispatch(&self) -> *mut ffi::PyObject { self as *const _ as *mut _ } } /// Trait implements object reference extraction from python managed pointer. pub trait AsPyRef: Sized { /// Return reference to object. fn as_ref(&self, py: Python) -> PyRef; /// Return mutable reference to object. fn as_mut(&mut self, py: Python) -> PyRefMut; /// Acquire python gil and call closure with object reference. fn with(&self, f: F) -> R where F: FnOnce(Python, PyRef) -> R, { let gil = Python::acquire_gil(); let py = gil.python(); f(py, self.as_ref(py)) } /// Acquire python gil and call closure with mutable object reference. fn with_mut(&mut self, f: F) -> R where F: FnOnce(Python, PyRefMut) -> R, { let gil = Python::acquire_gil(); let py = gil.python(); f(py, self.as_mut(py)) } fn into_py(self, f: F) -> R where Self: IntoPyPointer, F: FnOnce(Python, PyRef) -> R, { let gil = Python::acquire_gil(); let py = gil.python(); let result = f(py, self.as_ref(py)); py.xdecref(self); result } fn into_mut_py(mut self, f: F) -> R where Self: IntoPyPointer, F: FnOnce(Python, PyRefMut) -> R, { let gil = Python::acquire_gil(); let py = gil.python(); let result = f(py, self.as_mut(py)); py.xdecref(self); result } } /// Safe wrapper around unsafe `*mut ffi::PyObject` pointer with specified type information. #[derive(Debug)] #[repr(transparent)] pub struct Py(NonNull, std::marker::PhantomData); // `Py` is thread-safe, because any python related operations require a Python<'p> token. unsafe impl Send for Py {} unsafe impl Sync for Py {} impl Py { /// Creates a `Py` instance for the given FFI pointer. /// This moves ownership over the pointer into the `Py`. /// Undefined behavior if the pointer is NULL or invalid. #[inline] pub unsafe fn from_owned_ptr(ptr: *mut ffi::PyObject) -> Py { debug_assert!( !ptr.is_null() && ffi::Py_REFCNT(ptr) > 0, format!("REFCNT: {:?} - {:?}", ptr, ffi::Py_REFCNT(ptr)) ); Py(NonNull::new_unchecked(ptr), std::marker::PhantomData) } /// Creates a `Py` instance for the given FFI pointer. /// Panics if the pointer is `null`. /// Undefined behavior if the pointer is invalid. #[inline] pub unsafe fn from_owned_ptr_or_panic(ptr: *mut ffi::PyObject) -> Py { match NonNull::new(ptr) { Some(nonnull_ptr) => Py(nonnull_ptr, std::marker::PhantomData), None => { crate::err::panic_after_error(); } } } /// Construct `Py` from the result of a Python FFI call that /// returns a new reference (owned pointer). /// Returns `Err(PyErr)` if the pointer is `null`. /// Unsafe because the pointer might be invalid. pub unsafe fn from_owned_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult> { match NonNull::new(ptr) { Some(nonnull_ptr) => Ok(Py(nonnull_ptr, std::marker::PhantomData)), None => Err(PyErr::fetch(py)), } } /// Creates a `Py` instance for the given Python FFI pointer. /// Calls Py_INCREF() on the ptr. /// Undefined behavior if the pointer is NULL or invalid. #[inline] pub unsafe fn from_borrowed_ptr(ptr: *mut ffi::PyObject) -> Py { debug_assert!( !ptr.is_null() && ffi::Py_REFCNT(ptr) > 0, format!("REFCNT: {:?} - {:?}", ptr, ffi::Py_REFCNT(ptr)) ); ffi::Py_INCREF(ptr); Py(NonNull::new_unchecked(ptr), std::marker::PhantomData) } /// Gets the reference count of the ffi::PyObject pointer. #[inline] pub fn get_refcnt(&self) -> isize { unsafe { ffi::Py_REFCNT(self.0.as_ptr()) } } /// Clone self, Calls Py_INCREF() on the ptr. #[inline] pub fn clone_ref(&self, _py: Python) -> Py { unsafe { Py::from_borrowed_ptr(self.0.as_ptr()) } } /// Returns the inner pointer without decreasing the refcount /// /// This will eventually move into its own trait pub(crate) fn into_non_null(self) -> NonNull { let pointer = self.0; mem::forget(self); pointer } } impl Py where T: PyTypeCreate, { /// Create new instance of T and move it under python management /// Returns `Py`. pub fn new(py: Python, f: F) -> PyResult> where F: FnOnce() -> T, T: PyTypeObject + PyTypeInfo, { let ob = ::create(py)?; ob.init(f)?; let ob = unsafe { Py::from_owned_ptr(ob.into_ptr()) }; Ok(ob) } } /// Specialization workaround trait AsPyRefDispatch: ToPyPointer { fn as_ref_dispatch(&self, _py: Python) -> &T { unsafe { let ptr = (self.as_ptr() as *mut u8).offset(T::OFFSET) as *mut T; ptr.as_ref().unwrap() } } fn as_mut_dispatch(&mut self, _py: Python) -> &mut T { unsafe { let ptr = (self.as_ptr() as *mut u8).offset(T::OFFSET) as *mut T; ptr.as_mut().unwrap() } } } impl AsPyRefDispatch for Py {} impl AsPyRefDispatch for Py { fn as_ref_dispatch(&self, _py: Python) -> &T { unsafe { &*(self as *const instance::Py as *const T) } } fn as_mut_dispatch(&mut self, _py: Python) -> &mut T { unsafe { &mut *(self as *mut _ as *mut T) } } } impl AsPyRef for Py where T: PyTypeInfo, { #[inline] fn as_ref(&self, py: Python) -> PyRef { PyRef::from_ref(self.as_ref_dispatch(py)) } #[inline] fn as_mut(&mut self, py: Python) -> PyRefMut { PyRefMut::from_mut(self.as_mut_dispatch(py)) } } impl ToPyObject for Py { /// Converts `Py` instance -> PyObject. fn to_object(&self, py: Python) -> PyObject { unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) } } } impl IntoPyObject for Py { /// Converts `Py` instance -> PyObject. /// Consumes `self` without calling `Py_DECREF()` #[inline] fn into_object(self, py: Python) -> PyObject { unsafe { PyObject::from_owned_ptr(py, self.into_ptr()) } } } impl ToPyPointer for Py { /// Gets the underlying FFI pointer, returns a borrowed pointer. #[inline] fn as_ptr(&self) -> *mut ffi::PyObject { self.0.as_ptr() } } impl IntoPyPointer for Py { /// Gets the underlying FFI pointer, returns a owned pointer. #[inline] #[must_use] fn into_ptr(self) -> *mut ffi::PyObject { let ptr = self.0.as_ptr(); std::mem::forget(self); ptr } } impl PartialEq for Py { #[inline] fn eq(&self, o: &Py) -> bool { self.0 == o.0 } } /// Dropping a `Py` instance decrements the reference count on the object by 1. impl Drop for Py { fn drop(&mut self) { unsafe { pythonrun::register_pointer(self.0); } } } impl std::convert::From> for PyObject { #[inline] fn from(ob: Py) -> Self { unsafe { PyObject::from_not_null(ob.into_non_null()) } } } impl<'a, T> std::convert::From> for Py where T: PyTypeInfo, { fn from(ob: PyRef<'a, T>) -> Self { unsafe { Py::from_borrowed_ptr(ob.as_ptr()) } } } impl<'a, T> std::convert::From> for Py where T: PyTypeInfo, { fn from(ob: PyRefMut<'a, T>) -> Self { unsafe { Py::from_borrowed_ptr(ob.as_ptr()) } } } impl<'a, T> std::convert::From<&'a T> for PyObject where T: ToPyPointer, { fn from(ob: &'a T) -> Self { unsafe { Py::::from_borrowed_ptr(ob.as_ptr()) }.into() } } impl<'a, T> std::convert::From<&'a mut T> for PyObject where T: ToPyPointer, { fn from(ob: &'a mut T) -> Self { unsafe { Py::::from_borrowed_ptr(ob.as_ptr()) }.into() } } impl<'a, T> FromPyObject<'a> for Py where T: ToPyPointer, &'a T: 'a + FromPyObject<'a>, { /// Extracts `Self` from the source `PyObject`. fn extract(ob: &'a PyObjectRef) -> PyResult { unsafe { ob.extract::<&T>() .map(|val| Py::from_borrowed_ptr(val.as_ptr())) } } }