diff --git a/pyo3-derive-backend/src/module.rs b/pyo3-derive-backend/src/module.rs index 218ef3caf10..264f834510b 100644 --- a/pyo3-derive-backend/src/module.rs +++ b/pyo3-derive-backend/src/module.rs @@ -190,7 +190,7 @@ pub fn add_fn_to_module( }; let function = unsafe { - pyo3::PyObject::from_owned_ptr_or_panic( + pyo3::PyObject::from_owned_ptr( py, pyo3::ffi::PyCFunction_New( Box::into_raw(Box::new(_def.as_method_def())), diff --git a/src/instance.rs b/src/instance.rs index 22252ef4f34..4a90051f41d 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -115,64 +115,6 @@ where } impl Py { - /// For internal conversions - pub(crate) unsafe fn from_not_null(ptr: NonNull) -> Self { - Self(ptr, PhantomData) - } - - /// 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(_py: Python, 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), 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(_py: Python, ptr: *mut ffi::PyObject) -> Py { - match NonNull::new(ptr) { - Some(nonnull_ptr) => Py(nonnull_ptr, PhantomData), - None => { - crate::err::panic_after_error(_py); - } - } - } - - /// 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, 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(_py: Python, 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), PhantomData) - } - /// Gets the reference count of the `ffi::PyObject` pointer. #[inline] pub fn get_refcnt(&self, _py: Python) -> isize { @@ -185,47 +127,6 @@ impl Py { unsafe { Py::from_borrowed_ptr(py, 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 - } - - /// Constructs a `PyObject` from the result of a Python FFI call that - /// returns a new reference (owned pointer). - /// Returns `None` if the pointer is NULL. - pub unsafe fn from_owned_ptr_or_opt(_py: Python, ptr: *mut ffi::PyObject) -> Option { - match NonNull::new(ptr) { - Some(nonnull_ptr) => Some(Py(nonnull_ptr, PhantomData)), - None => None, - } - } - - /// Creates a `PyObject` instance for the given Python FFI pointer. - /// Calls `Py_INCREF()` on the ptr. - /// Returns `Err(PyErr)` if the pointer is NULL. - pub unsafe fn from_borrowed_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult { - if ptr.is_null() { - Err(PyErr::fetch(py)) - } else { - Ok(Self::from_borrowed_ptr(py, ptr)) - } - } - - /// Creates a `PyObject` instance for the given Python FFI pointer. - /// Calls `Py_INCREF()` on the ptr. - /// Returns `None` if the pointer is NULL. - pub unsafe fn from_borrowed_ptr_or_opt(py: Python, ptr: *mut ffi::PyObject) -> Option { - if ptr.is_null() { - None - } else { - Some(Self::from_borrowed_ptr(py, ptr)) - } - } - /// Returns whether the object is considered to be None. /// /// This is equivalent to the Python expression `self is None`. @@ -245,16 +146,6 @@ impl Py { } } - /// Casts the PyObject to a concrete Python object type. - /// - /// This can cast only to native Python types, not types implemented in Rust. - pub fn cast_as<'p, D>(&'p self, py: Python<'p>) -> Result<&'p D, PyDowncastError> - where - D: PyTryFrom<'p>, - { - D::try_from(unsafe { py.from_borrowed_ptr::(self.as_ptr()) }) - } - /// Extracts some type from the Python object. /// /// This is a wrapper function around `FromPyObject::extract()`. @@ -355,6 +246,113 @@ impl Py { pub fn call_method0(&self, py: Python, name: &str) -> PyResult { self.call_method(py, name, (), None) } + + /// Create a `Py` instance by taking ownership of the given FFI pointer. + /// + /// # Safety + /// `ptr` must be a pointer to a Python object of type T. + /// + /// # Panics + /// Panics if `ptr` is null. + #[inline] + pub unsafe fn from_owned_ptr(py: Python, ptr: *mut ffi::PyObject) -> Py { + match NonNull::new(ptr) { + Some(nonnull_ptr) => Py(nonnull_ptr, PhantomData), + None => crate::err::panic_after_error(py), + } + } + + /// Deprecated alias for [`from_owned_ptr`](#method.from_owned_ptr). + #[inline] + #[deprecated = "this is a deprecated alias for Py::from_owned_ptr"] + pub unsafe fn from_owned_ptr_or_panic(py: Python, ptr: *mut ffi::PyObject) -> Py { + Py::from_owned_ptr(py, ptr) + } + + /// Create a `Py` instance by taking ownership of the given FFI pointer. + /// + /// If `ptr` is null then the current Python exception is fetched as a `PyErr`. + /// + /// # Safety + /// If non-null, `ptr` must be a pointer to a Python object of type T. + #[inline] + 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, PhantomData)), + None => Err(PyErr::fetch(py)), + } + } + + /// Create a `Py` instance by taking ownership of the given FFI pointer. + /// + /// If `ptr` is null then `None` is returned. + /// + /// # Safety + /// If non-null, `ptr` must be a pointer to a Python object of type T. + #[inline] + pub unsafe fn from_owned_ptr_or_opt(_py: Python, ptr: *mut ffi::PyObject) -> Option { + match NonNull::new(ptr) { + Some(nonnull_ptr) => Some(Py(nonnull_ptr, PhantomData)), + None => None, + } + } + + /// Create a `Py` instance by creating a new reference from the given FFI pointer. + /// + /// # Safety + /// `ptr` must be a pointer to a Python object of type T. + /// + /// # Panics + /// Panics if `ptr` is null. + #[inline] + pub unsafe fn from_borrowed_ptr(py: Python, ptr: *mut ffi::PyObject) -> Py { + match Self::from_borrowed_ptr_or_opt(py, ptr) { + Some(slf) => slf, + None => crate::err::panic_after_error(py), + } + } + + /// Create a `Py` instance by creating a new reference from the given FFI pointer. + /// + /// If `ptr` is null then the current Python exception is fetched as a `PyErr`. + /// + /// # Safety + /// `ptr` must be a pointer to a Python object of type T. + #[inline] + pub unsafe fn from_borrowed_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult { + Self::from_borrowed_ptr_or_opt(py, ptr).ok_or_else(|| PyErr::fetch(py)) + } + + /// Create a `Py` instance by creating a new reference from the given FFI pointer. + /// + /// If `ptr` is null then `None` is returned. + /// + /// # Safety + /// `ptr` must be a pointer to a Python object of type T. + #[inline] + pub unsafe fn from_borrowed_ptr_or_opt(_py: Python, ptr: *mut ffi::PyObject) -> Option { + NonNull::new(ptr).map(|nonnull_ptr| { + ffi::Py_INCREF(ptr); + Py(nonnull_ptr, PhantomData) + }) + } + + /// For internal conversions. + /// + /// # Safety + /// `ptr` must point to a Python object of type T. + #[inline] + unsafe fn from_non_null(ptr: NonNull) -> Self { + Self(ptr, PhantomData) + } + + /// Returns the inner pointer without decreasing the refcount. + #[inline] + fn into_non_null(self) -> NonNull { + let pointer = self.0; + mem::forget(self); + pointer + } } /// Retrieves `&'py` types from `Py` or `PyObject`. @@ -421,7 +419,7 @@ impl IntoPy for Py { /// Consumes `self` without calling `Py_DECREF()`. #[inline] fn into_py(self, _py: Python) -> PyObject { - unsafe { PyObject::from_not_null(self.into_non_null()) } + unsafe { PyObject::from_non_null(self.into_non_null()) } } } @@ -566,6 +564,19 @@ impl std::fmt::Debug for Py { /// See the documentation for [`Py`](struct.Py.html). pub type PyObject = Py; +impl PyObject { + /// Casts the PyObject to a concrete Python object type. + /// + /// This can cast only to native Python types, not types implemented in Rust. For a more + /// flexible alternative, see [`Py::extract`](struct.Py.html#method.extract). + pub fn cast_as<'p, D>(&'p self, py: Python<'p>) -> Result<&'p D, PyDowncastError> + where + D: PyTryFrom<'p>, + { + D::try_from(unsafe { py.from_borrowed_ptr::(self.as_ptr()) }) + } +} + #[cfg(test)] mod test { use super::{Py, PyObject}; diff --git a/src/types/complex.rs b/src/types/complex.rs index 3cf8e756fc4..c3a38bb467c 100644 --- a/src/types/complex.rs +++ b/src/types/complex.rs @@ -149,7 +149,7 @@ mod complex_conversion { unsafe { let raw_obj = ffi::PyComplex_FromDoubles(self.re as c_double, self.im as c_double); - PyObject::from_owned_ptr_or_panic(py, raw_obj) + PyObject::from_owned_ptr(py, raw_obj) } } } diff --git a/src/types/list.rs b/src/types/list.rs index 4191a466dd2..28bc7258252 100644 --- a/src/types/list.rs +++ b/src/types/list.rs @@ -173,7 +173,7 @@ where let obj = e.to_object(py).into_ptr(); ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj); } - PyObject::from_owned_ptr_or_panic(py, ptr) + PyObject::from_owned_ptr(py, ptr) } } } @@ -218,7 +218,7 @@ where let obj = e.into_py(py).into_ptr(); ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj); } - PyObject::from_owned_ptr_or_panic(py, ptr) + PyObject::from_owned_ptr(py, ptr) } } } diff --git a/src/types/num.rs b/src/types/num.rs index 376c104ccbb..09b419b68c8 100644 --- a/src/types/num.rs +++ b/src/types/num.rs @@ -62,17 +62,13 @@ macro_rules! int_fits_c_long { impl ToPyObject for $rust_type { #![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))] fn to_object(&self, py: Python) -> PyObject { - unsafe { - PyObject::from_owned_ptr_or_panic(py, ffi::PyLong_FromLong(*self as c_long)) - } + unsafe { PyObject::from_owned_ptr(py, ffi::PyLong_FromLong(*self as c_long)) } } } impl IntoPy for $rust_type { #![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))] fn into_py(self, py: Python) -> PyObject { - unsafe { - PyObject::from_owned_ptr_or_panic(py, ffi::PyLong_FromLong(self as c_long)) - } + unsafe { PyObject::from_owned_ptr(py, ffi::PyLong_FromLong(self as c_long)) } } } @@ -101,13 +97,13 @@ macro_rules! int_convert_u64_or_i64 { impl ToPyObject for $rust_type { #[inline] fn to_object(&self, py: Python) -> PyObject { - unsafe { PyObject::from_owned_ptr_or_panic(py, $pylong_from_ll_or_ull(*self)) } + unsafe { PyObject::from_owned_ptr(py, $pylong_from_ll_or_ull(*self)) } } } impl IntoPy for $rust_type { #[inline] fn into_py(self, py: Python) -> PyObject { - unsafe { PyObject::from_owned_ptr_or_panic(py, $pylong_from_ll_or_ull(self)) } + unsafe { PyObject::from_owned_ptr(py, $pylong_from_ll_or_ull(self)) } } } impl<'source> FromPyObject<'source> for $rust_type { @@ -194,7 +190,7 @@ mod int128_conversion { IS_LITTLE_ENDIAN, $is_signed, ); - PyObject::from_owned_ptr_or_panic(py, obj) + PyObject::from_owned_ptr(py, obj) } } } @@ -278,7 +274,7 @@ mod int128_conversion { super::IS_LITTLE_ENDIAN, 0, ); - let obj = PyObject::from_owned_ptr_or_panic(py, obj); + let obj = PyObject::from_owned_ptr(py, obj); let err = obj.extract::(py).unwrap_err(); assert!(err.is_instance::(py)); } @@ -319,7 +315,7 @@ mod bigint_conversion { 1, $is_signed, ); - PyObject::from_owned_ptr_or_panic(py, obj) + PyObject::from_owned_ptr(py, obj) } } } diff --git a/src/types/tuple.rs b/src/types/tuple.rs index 36fed55be57..60216045c94 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -144,7 +144,7 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+ unsafe { let ptr = ffi::PyTuple_New($length); $(ffi::PyTuple_SetItem(ptr, $n, self.$n.to_object(py).into_ptr());)+ - PyObject::from_owned_ptr_or_panic(py, ptr) + PyObject::from_owned_ptr(py, ptr) } } } @@ -153,7 +153,7 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+ unsafe { let ptr = ffi::PyTuple_New($length); $(ffi::PyTuple_SetItem(ptr, $n, self.$n.into_py(py).into_ptr());)+ - PyObject::from_owned_ptr_or_panic(py, ptr) + PyObject::from_owned_ptr(py, ptr) } } } @@ -163,7 +163,7 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+ unsafe { let ptr = ffi::PyTuple_New($length); $(ffi::PyTuple_SetItem(ptr, $n, self.$n.into_py(py).into_ptr());)+ - Py::from_owned_ptr_or_panic(py, ptr) + Py::from_owned_ptr(py, ptr) } } }