diff --git a/pyo3-ffi/src/abstract_.rs b/pyo3-ffi/src/abstract_.rs index b5bf9cc3..1e002046 100644 --- a/pyo3-ffi/src/abstract_.rs +++ b/pyo3-ffi/src/abstract_.rs @@ -114,10 +114,7 @@ extern "C" { #[cfg(not(any(Py_3_8, PyPy)))] #[inline] pub unsafe fn PyIter_Check(o: *mut PyObject) -> c_int { - crate::PyObject_HasAttrString( - crate::Py_TYPE(o).cast(), - "__next__\0".as_ptr() as *const c_char, - ) + crate::PyObject_HasAttrString(crate::Py_TYPE(o).cast(), "__next__\0".as_ptr().cast()) } extern "C" { diff --git a/pyo3-ffi/src/cpython/abstract_.rs b/pyo3-ffi/src/cpython/abstract_.rs index ad28216c..34525cec 100644 --- a/pyo3-ffi/src/cpython/abstract_.rs +++ b/pyo3-ffi/src/cpython/abstract_.rs @@ -61,7 +61,7 @@ pub unsafe fn PyVectorcall_Function(callable: *mut PyObject) -> Option 0); let offset = (*tp).tp_vectorcall_offset; assert!(offset > 0); - let ptr = (callable as *const c_char).offset(offset) as *const Option; + let ptr = callable.cast::().offset(offset).cast(); *ptr } diff --git a/pyo3-ffi/src/datetime.rs b/pyo3-ffi/src/datetime.rs index a20b76aa..b985085f 100644 --- a/pyo3-ffi/src/datetime.rs +++ b/pyo3-ffi/src/datetime.rs @@ -13,7 +13,9 @@ use crate::{PyLong_AsLong, PyLong_Check, PyObject_GetAttrString, Py_DecRef}; use crate::{PyObject, PyObject_TypeCheck, PyTypeObject, Py_TYPE}; use std::cell::UnsafeCell; -use std::os::raw::{c_char, c_int}; +#[cfg(not(GraalPy))] +use std::os::raw::c_char; +use std::os::raw::c_int; use std::ptr; #[cfg(not(PyPy))] use {crate::PyCapsule_Import, std::ffi::CString}; @@ -356,7 +358,7 @@ pub unsafe fn PyDateTime_DELTA_GET_MICROSECONDS(o: *mut PyObject) -> c_int { #[inline] #[cfg(GraalPy)] pub unsafe fn _get_attr(obj: *mut PyObject, field: &str) -> c_int { - let result = PyObject_GetAttrString(obj, field.as_ptr() as *const c_char); + let result = PyObject_GetAttrString(obj, field.as_ptr().cast()); Py_DecRef(result); // the original macros are borrowing if PyLong_Check(result) == 1 { PyLong_AsLong(result) as c_int @@ -416,7 +418,7 @@ pub unsafe fn PyDateTime_DATE_GET_FOLD(o: *mut PyObject) -> c_int { #[inline] #[cfg(GraalPy)] pub unsafe fn PyDateTime_DATE_GET_TZINFO(o: *mut PyObject) -> *mut PyObject { - let res = PyObject_GetAttrString(o, "tzinfo\0".as_ptr() as *const c_char); + let res = PyObject_GetAttrString(o, "tzinfo\0".as_ptr().cast()); Py_DecRef(res); // the original macros are borrowing res } @@ -454,7 +456,7 @@ pub unsafe fn PyDateTime_TIME_GET_FOLD(o: *mut PyObject) -> c_int { #[inline] #[cfg(GraalPy)] pub unsafe fn PyDateTime_TIME_GET_TZINFO(o: *mut PyObject) -> *mut PyObject { - let res = PyObject_GetAttrString(o, "tzinfo\0".as_ptr() as *const c_char); + let res = PyObject_GetAttrString(o, "tzinfo\0".as_ptr().cast()); Py_DecRef(res); // the original macros are borrowing res } diff --git a/src/buffer.rs b/src/buffer.rs index 74ac7fe8..558fb5e9 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -263,7 +263,7 @@ impl PyBuffer { }, #[cfg(Py_3_11)] { - indices.as_ptr() as *const ffi::Py_ssize_t + indices.as_ptr().cast() }, #[cfg(not(Py_3_11))] { @@ -317,7 +317,7 @@ impl PyBuffer { /// However, dimensions of length 0 are possible and might need special attention. #[inline] pub fn shape(&self) -> &[usize] { - unsafe { slice::from_raw_parts(self.0.shape as *const usize, self.0.ndim as usize) } + unsafe { slice::from_raw_parts(self.0.shape.cast(), self.0.ndim as usize) } } /// Returns an array that holds, for each dimension, the number of bytes to skip to get to the next element in the dimension. @@ -361,23 +361,13 @@ impl PyBuffer { /// Gets whether the buffer is contiguous in C-style order (last index varies fastest when visiting items in order of memory address). #[inline] pub fn is_c_contiguous(&self) -> bool { - unsafe { - ffi::PyBuffer_IsContiguous( - &*self.0 as *const ffi::Py_buffer, - b'C' as std::os::raw::c_char, - ) != 0 - } + unsafe { ffi::PyBuffer_IsContiguous(&*self.0, b'C' as std::os::raw::c_char) != 0 } } /// Gets whether the buffer is contiguous in Fortran-style order (first index varies fastest when visiting items in order of memory address). #[inline] pub fn is_fortran_contiguous(&self) -> bool { - unsafe { - ffi::PyBuffer_IsContiguous( - &*self.0 as *const ffi::Py_buffer, - b'F' as std::os::raw::c_char, - ) != 0 - } + unsafe { ffi::PyBuffer_IsContiguous(&*self.0, b'F' as std::os::raw::c_char) != 0 } } /// Gets the buffer memory as a slice. @@ -609,7 +599,7 @@ impl PyBuffer { }, #[cfg(Py_3_11)] { - source.as_ptr() as *const raw::c_void + source.as_ptr().cast() }, #[cfg(not(Py_3_11))] { diff --git a/src/conversions/num_rational.rs b/src/conversions/num_rational.rs index 31eb7ca1..2129234d 100644 --- a/src/conversions/num_rational.rs +++ b/src/conversions/num_rational.rs @@ -48,7 +48,6 @@ use crate::sync::GILOnceCell; use crate::types::any::PyAnyMethods; use crate::types::PyType; use crate::{Bound, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject}; -use std::os::raw::c_char; #[cfg(feature = "num-bigint")] use num_bigint::BigInt; @@ -68,19 +67,13 @@ macro_rules! rational_conversion { let py_numerator_obj = unsafe { Bound::from_owned_ptr_or_err( py, - ffi::PyObject_GetAttrString( - obj.as_ptr(), - "numerator\0".as_ptr() as *const c_char, - ), + ffi::PyObject_GetAttrString(obj.as_ptr(), "numerator\0".as_ptr().cast()), ) }; let py_denominator_obj = unsafe { Bound::from_owned_ptr_or_err( py, - ffi::PyObject_GetAttrString( - obj.as_ptr(), - "denominator\0".as_ptr() as *const c_char, - ), + ffi::PyObject_GetAttrString(obj.as_ptr(), "denominator\0".as_ptr().cast()), ) }; let numerator_owned = unsafe { diff --git a/src/conversions/std/osstr.rs b/src/conversions/std/osstr.rs index 4565c3fb..8616a116 100644 --- a/src/conversions/std/osstr.rs +++ b/src/conversions/std/osstr.rs @@ -4,8 +4,6 @@ use crate::types::PyString; use crate::{ffi, FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject}; use std::borrow::Cow; use std::ffi::{OsStr, OsString}; -#[cfg(not(windows))] -use std::os::raw::c_char; impl ToPyObject for OsStr { fn to_object(&self, py: Python<'_>) -> PyObject { @@ -23,7 +21,7 @@ impl ToPyObject for OsStr { #[cfg(not(target_os = "wasi"))] let bytes = std::os::unix::ffi::OsStrExt::as_bytes(self); - let ptr = bytes.as_ptr() as *const c_char; + let ptr = bytes.as_ptr().cast(); let len = bytes.len() as ffi::Py_ssize_t; unsafe { // DecodeFSDefault automatically chooses an appropriate decoding mechanism to diff --git a/src/exceptions.rs b/src/exceptions.rs index d6a6e859..e2bb82f9 100644 --- a/src/exceptions.rs +++ b/src/exceptions.rs @@ -12,7 +12,6 @@ use crate::{ffi, Bound, PyResult, Python}; use std::ffi::CStr; use std::ops; -use std::os::raw::c_char; /// The boilerplate to convert between a Rust type and a Python exception. #[doc(hidden)] @@ -682,7 +681,7 @@ impl PyUnicodeDecodeError { unsafe { ffi::PyUnicodeDecodeError_Create( encoding.as_ptr(), - input.as_ptr() as *const c_char, + input.as_ptr().cast(), input.len() as ffi::Py_ssize_t, range.start as ffi::Py_ssize_t, range.end as ffi::Py_ssize_t, diff --git a/src/impl_/extract_argument.rs b/src/impl_/extract_argument.rs index 5f652d75..a354e578 100644 --- a/src/impl_/extract_argument.rs +++ b/src/impl_/extract_argument.rs @@ -318,9 +318,9 @@ impl FunctionDescription { let kwnames: Option> = Borrowed::from_ptr_or_opt(py, kwnames).map(|kwnames| kwnames.downcast_unchecked()); if let Some(kwnames) = kwnames { - // Safety: PyArg has the same memory layout as `*mut ffi::PyObject` let kwargs = ::std::slice::from_raw_parts( - (args as *const PyArg<'py>).offset(nargs), + // Safety: PyArg has the same memory layout as `*mut ffi::PyObject` + args.offset(nargs).cast::>(), kwnames.len(), ); diff --git a/src/impl_/pymodule.rs b/src/impl_/pymodule.rs index 5f04d888..0c3d8951 100644 --- a/src/impl_/pymodule.rs +++ b/src/impl_/pymodule.rs @@ -70,8 +70,8 @@ impl ModuleDef { }; let ffi_def = UnsafeCell::new(ffi::PyModuleDef { - m_name: name.as_ptr() as *const _, - m_doc: doc.as_ptr() as *const _, + m_name: name.as_ptr().cast(), + m_doc: doc.as_ptr().cast(), ..INIT }); diff --git a/src/instance.rs b/src/instance.rs index 82b05e78..2992b273 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1,5 +1,6 @@ use crate::err::{self, PyErr, PyResult}; use crate::impl_::pycell::PyClassObject; +use crate::internal_tricks::ptr_from_ref; use crate::pycell::{PyBorrowError, PyBorrowMutError}; use crate::pyclass::boolean_struct::{False, True}; #[cfg(feature = "gil-refs")] @@ -42,7 +43,7 @@ pub unsafe trait PyNativeType: Sized { // Safety: &'py Self is expected to be a Python pointer, // so has the same layout as Borrowed<'py, 'py, T> Borrowed( - unsafe { NonNull::new_unchecked(self as *const Self as *mut _) }, + unsafe { NonNull::new_unchecked(ptr_from_ref(self) as *mut _) }, PhantomData, self.py(), ) @@ -193,7 +194,7 @@ impl<'py> Bound<'py, PyAny> { _py: Python<'py>, ptr: &'a *mut ffi::PyObject, ) -> &'a Self { - &*(ptr as *const *mut ffi::PyObject).cast::>() + &*ptr_from_ref(ptr).cast::>() } /// Variant of the above which returns `None` for null pointers. @@ -205,7 +206,7 @@ impl<'py> Bound<'py, PyAny> { _py: Python<'py>, ptr: &'a *mut ffi::PyObject, ) -> &'a Option { - &*(ptr as *const *mut ffi::PyObject).cast::>>() + &*ptr_from_ref(ptr).cast::>>() } } @@ -454,7 +455,7 @@ impl<'py, T> Bound<'py, T> { pub fn as_any(&self) -> &Bound<'py, PyAny> { // Safety: all Bound have the same memory layout, and all Bound are valid // Bound, so pointer casting is valid. - unsafe { &*(self as *const Self).cast::>() } + unsafe { &*ptr_from_ref(self).cast::>() } } /// Helper to cast to `Bound<'py, PyAny>`, transferring ownership. @@ -694,7 +695,7 @@ impl<'py, T> Deref for Borrowed<'_, 'py, T> { #[inline] fn deref(&self) -> &Bound<'py, T> { // safety: Bound has the same layout as NonNull - unsafe { &*(&self.0 as *const _ as *const Bound<'py, T>) } + unsafe { &*ptr_from_ref(&self.0).cast() } } } @@ -1097,7 +1098,7 @@ impl Py { pub fn as_any(&self) -> &Py { // Safety: all Py have the same memory layout, and all Py are valid // Py, so pointer casting is valid. - unsafe { &*(self as *const Self).cast::>() } + unsafe { &*ptr_from_ref(self).cast::>() } } /// Helper to cast to `Py`, transferring ownership. @@ -1273,7 +1274,7 @@ impl Py { #[inline] pub fn bind<'py>(&self, _py: Python<'py>) -> &Bound<'py, T> { // Safety: `Bound` has the same layout as `Py` - unsafe { &*(self as *const Py).cast() } + unsafe { &*ptr_from_ref(self).cast() } } /// Same as `bind` but takes ownership of `self`. diff --git a/src/internal_tricks.rs b/src/internal_tricks.rs index 75f23edb..62ec0d02 100644 --- a/src/internal_tricks.rs +++ b/src/internal_tricks.rs @@ -217,3 +217,9 @@ pub(crate) fn extract_c_string( }; Ok(cow) } + +// TODO: use ptr::from_ref on MSRV 1.76 +#[inline] +pub(crate) const fn ptr_from_ref(t: &T) -> *const T { + t as *const T +} diff --git a/src/macros.rs b/src/macros.rs index 6dde89e5..9316b871 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -214,7 +214,7 @@ macro_rules! append_to_inittab { ); } $crate::ffi::PyImport_AppendInittab( - $module::__PYO3_NAME.as_ptr() as *const ::std::os::raw::c_char, + $module::__PYO3_NAME.as_ptr().cast(), ::std::option::Option::Some($module::__pyo3_init), ); } diff --git a/src/marker.rs b/src/marker.rs index a6b1e305..b2cbc317 100644 --- a/src/marker.rs +++ b/src/marker.rs @@ -652,7 +652,7 @@ impl<'py> Python<'py> { ) -> PyResult> { let code = CString::new(code)?; unsafe { - let mptr = ffi::PyImport_AddModule("__main__\0".as_ptr() as *const _); + let mptr = ffi::PyImport_AddModule("__main__\0".as_ptr().cast()); if mptr.is_null() { return Err(PyErr::fetch(self)); } diff --git a/src/pycell.rs b/src/pycell.rs index f15f5a54..1d601474 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -202,6 +202,7 @@ use crate::types::any::PyAnyMethods; use crate::{ conversion::ToPyObject, impl_::pyclass::PyClassImpl, + internal_tricks::ptr_from_ref, pyclass::boolean_struct::True, pyclass_init::PyClassInitializer, type_object::{PyLayout, PySizedLayout}, @@ -511,7 +512,7 @@ where #[allow(deprecated)] unsafe impl AsPyPointer for PyCell { fn as_ptr(&self) -> *mut ffi::PyObject { - (self as *const _) as *mut _ + ptr_from_ref(self) as *mut _ } } diff --git a/src/pyclass/create_type_object.rs b/src/pyclass/create_type_object.rs index 1b3a9fb1..262d1e8f 100644 --- a/src/pyclass/create_type_object.rs +++ b/src/pyclass/create_type_object.rs @@ -3,17 +3,17 @@ use pyo3_ffi::PyType_IS_GC; use crate::{ exceptions::PyTypeError, ffi, - impl_::pycell::PyClassObject, - impl_::pyclass::{ - assign_sequence_item_from_mapping, get_sequence_item_from_mapping, tp_dealloc, - tp_dealloc_with_gc, PyClassItemsIter, - }, impl_::{ + pycell::PyClassObject, + pyclass::{ + assign_sequence_item_from_mapping, get_sequence_item_from_mapping, tp_dealloc, + tp_dealloc_with_gc, PyClassItemsIter, + }, pymethods::{get_doc, get_name, Getter, Setter}, trampoline::trampoline, }, - types::typeobject::PyTypeMethods, - types::PyType, + internal_tricks::ptr_from_ref, + types::{typeobject::PyTypeMethods, PyType}, Py, PyClass, PyGetterDef, PyMethodDefType, PyResult, PySetterDef, PyTypeInfo, Python, }; use std::{ @@ -608,7 +608,7 @@ impl GetSetDefType { slf: *mut ffi::PyObject, closure: *mut c_void, ) -> *mut ffi::PyObject { - let getset: &GetterAndSetter = &*(closure as *const GetterAndSetter); + let getset: &GetterAndSetter = &*closure.cast(); trampoline(|py| (getset.getter)(py, slf)) } @@ -617,13 +617,13 @@ impl GetSetDefType { value: *mut ffi::PyObject, closure: *mut c_void, ) -> c_int { - let getset: &GetterAndSetter = &*(closure as *const GetterAndSetter); + let getset: &GetterAndSetter = &*closure.cast(); trampoline(|py| (getset.setter)(py, slf, value)) } ( Some(getset_getter), Some(getset_setter), - closure.as_ref() as *const GetterAndSetter as _, + ptr_from_ref::(closure) as *mut _, ) } }; diff --git a/src/types/any.rs b/src/types/any.rs index 85e540f9..06634d69 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -4,6 +4,7 @@ use crate::err::{DowncastError, DowncastIntoError, PyErr, PyResult}; use crate::exceptions::{PyAttributeError, PyTypeError}; use crate::ffi_ptr_ext::FfiPtrExt; use crate::instance::Bound; +use crate::internal_tricks::ptr_from_ref; use crate::py_result_ext::PyResultExt; use crate::type_object::{PyTypeCheck, PyTypeInfo}; #[cfg(not(any(PyPy, GraalPy)))] @@ -912,7 +913,7 @@ impl PyAny { /// when they are finished with the pointer. #[inline] pub fn as_ptr(&self) -> *mut ffi::PyObject { - self as *const PyAny as *mut ffi::PyObject + ptr_from_ref(self) as *mut ffi::PyObject } /// Returns an owned raw FFI pointer represented by self. @@ -2211,7 +2212,7 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> { #[inline] unsafe fn downcast_unchecked(&self) -> &Bound<'py, T> { - &*(self as *const Bound<'py, PyAny>).cast() + &*ptr_from_ref(self).cast() } #[inline] diff --git a/src/types/bytearray.rs b/src/types/bytearray.rs index ec3d7eaf..fbd77a38 100644 --- a/src/types/bytearray.rs +++ b/src/types/bytearray.rs @@ -6,7 +6,6 @@ use crate::types::any::PyAnyMethods; use crate::{ffi, PyAny, Python}; #[cfg(feature = "gil-refs")] use crate::{AsPyPointer, PyNativeType}; -use std::os::raw::c_char; use std::slice; /// Represents a Python `bytearray`. @@ -20,7 +19,7 @@ impl PyByteArray { /// /// The byte string is initialized by copying the data from the `&[u8]`. pub fn new_bound<'py>(py: Python<'py>, src: &[u8]) -> Bound<'py, PyByteArray> { - let ptr = src.as_ptr() as *const c_char; + let ptr = src.as_ptr().cast(); let len = src.len() as ffi::Py_ssize_t; unsafe { ffi::PyByteArray_FromStringAndSize(ptr, len) diff --git a/src/types/bytes.rs b/src/types/bytes.rs index 1d6a2f8e..661c3022 100644 --- a/src/types/bytes.rs +++ b/src/types/bytes.rs @@ -5,7 +5,6 @@ use crate::types::any::PyAnyMethods; use crate::PyNativeType; use crate::{ffi, Py, PyAny, PyResult, Python}; use std::ops::Index; -use std::os::raw::c_char; use std::slice::SliceIndex; use std::str; @@ -23,7 +22,7 @@ impl PyBytes { /// /// Panics if out of memory. pub fn new_bound<'p>(py: Python<'p>, s: &[u8]) -> Bound<'p, PyBytes> { - let ptr = s.as_ptr() as *const c_char; + let ptr = s.as_ptr().cast(); let len = s.len() as ffi::Py_ssize_t; unsafe { ffi::PyBytes_FromStringAndSize(ptr, len) @@ -85,7 +84,7 @@ impl PyBytes { /// `std::slice::from_raw_parts`, this is /// unsafe](https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety). pub unsafe fn bound_from_ptr(py: Python<'_>, ptr: *const u8, len: usize) -> Bound<'_, PyBytes> { - ffi::PyBytes_FromStringAndSize(ptr as *const _, len as isize) + ffi::PyBytes_FromStringAndSize(ptr.cast(), len as isize) .assume_owned(py) .downcast_into_unchecked() } diff --git a/src/types/string.rs b/src/types/string.rs index 4f0025ac..0582a900 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -10,7 +10,6 @@ use crate::types::PyBytes; use crate::PyNativeType; use crate::{ffi, Bound, IntoPy, Py, PyAny, PyResult, Python}; use std::borrow::Cow; -use std::os::raw::c_char; use std::str; /// Represents raw data backing a Python `str`. @@ -37,16 +36,10 @@ impl<'a> PyStringData<'a> { match self { Self::Ucs1(s) => s, Self::Ucs2(s) => unsafe { - std::slice::from_raw_parts( - s.as_ptr() as *const u8, - s.len() * self.value_width_bytes(), - ) + std::slice::from_raw_parts(s.as_ptr().cast(), s.len() * self.value_width_bytes()) }, Self::Ucs4(s) => unsafe { - std::slice::from_raw_parts( - s.as_ptr() as *const u8, - s.len() * self.value_width_bytes(), - ) + std::slice::from_raw_parts(s.as_ptr().cast(), s.len() * self.value_width_bytes()) }, } } @@ -141,7 +134,7 @@ impl PyString { /// /// Panics if out of memory. pub fn new_bound<'py>(py: Python<'py>, s: &str) -> Bound<'py, PyString> { - let ptr = s.as_ptr() as *const c_char; + let ptr = s.as_ptr().cast(); let len = s.len() as ffi::Py_ssize_t; unsafe { ffi::PyUnicode_FromStringAndSize(ptr, len) @@ -159,7 +152,7 @@ impl PyString { /// /// Panics if out of memory. pub fn intern_bound<'py>(py: Python<'py>, s: &str) -> Bound<'py, PyString> { - let ptr = s.as_ptr() as *const c_char; + let ptr = s.as_ptr().cast(); let len = s.len() as ffi::Py_ssize_t; unsafe { let mut ob = ffi::PyUnicode_FromStringAndSize(ptr, len); @@ -181,8 +174,8 @@ impl PyString { unsafe { ffi::PyUnicode_FromEncodedObject( src.as_ptr(), - encoding.as_ptr() as *const c_char, - errors.as_ptr() as *const c_char, + encoding.as_ptr().cast(), + errors.as_ptr().cast(), ) .assume_owned_or_err(src.py()) .downcast_into_unchecked() @@ -607,7 +600,7 @@ mod tests { let ptr = unsafe { crate::ffi::PyUnicode_FromKindAndData( crate::ffi::PyUnicode_1BYTE_KIND as _, - buffer.as_ptr() as *const _, + buffer.as_ptr().cast(), 2, ) }; @@ -651,7 +644,7 @@ mod tests { let ptr = unsafe { crate::ffi::PyUnicode_FromKindAndData( crate::ffi::PyUnicode_2BYTE_KIND as _, - buffer.as_ptr() as *const _, + buffer.as_ptr().cast(), 2, ) }; @@ -692,7 +685,7 @@ mod tests { let ptr = unsafe { crate::ffi::PyUnicode_FromKindAndData( crate::ffi::PyUnicode_4BYTE_KIND as _, - buffer.as_ptr() as *const _, + buffer.as_ptr().cast(), 2, ) }; diff --git a/src/types/tuple.rs b/src/types/tuple.rs index afe12987..fcf931c1 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -388,13 +388,10 @@ impl<'py> PyTupleMethods<'py> for Bound<'py, PyTuple> { #[cfg(not(any(Py_LIMITED_API, GraalPy)))] fn as_slice(&self) -> &[Bound<'py, PyAny>] { - // This is safe because Bound<'py, PyAny> has the same memory layout as *mut ffi::PyObject, - // and because tuples are immutable. - unsafe { - let ptr = self.as_ptr() as *mut ffi::PyTupleObject; - let slice = std::slice::from_raw_parts((*ptr).ob_item.as_ptr(), self.len()); - &*(slice as *const [*mut ffi::PyObject] as *const [Bound<'py, PyAny>]) - } + // SAFETY: self is known to be a tuple object, and tuples are immutable + let items = unsafe { &(*self.as_ptr().cast::()).ob_item }; + // SAFETY: Bound<'py, PyAny> has the same memory layout as *mut ffi::PyObject + unsafe { std::slice::from_raw_parts(items.as_ptr().cast(), self.len()) } } #[inline]