diff --git a/src/impl_/extract_argument.rs b/src/impl_/extract_argument.rs index 8a34d7475ca..b2cb91160c6 100644 --- a/src/impl_/extract_argument.rs +++ b/src/impl_/extract_argument.rs @@ -48,7 +48,7 @@ where obj: &'a Bound<'py, PyAny>, holder: &'a mut Option<&'a Bound<'py, T>>, ) -> PyResult { - Ok(&*holder.insert(obj.downcast()?)) + Ok(holder.insert(obj.downcast()?)) } } @@ -261,7 +261,9 @@ impl FunctionDescription { ); // Handle positional arguments - // Safety: Option has the same memory layout as `*mut ffi::PyObject` + // Safety: + // - Option has the same memory layout as `*mut ffi::PyObject` + // - we both have the GIL and can borrow these input references for the `'py` lifetime. let args: *const Option> = args.cast(); let positional_args_provided = nargs as usize; let remaining_positional_args = if args.is_null() { @@ -284,9 +286,12 @@ impl FunctionDescription { let mut varkeywords = K::Varkeywords::default(); // Safety: kwnames is known to be a pointer to a tuple, or null - let kwnames: &'py Option> = std::mem::transmute(&kwnames); - if let Some(kwnames) = kwnames.as_ref() { - // Safety: &PyAny has the same memory layout as `*mut ffi::PyObject` + // - we both have the GIL and can borrow this input reference for the `'py` lifetime. + let kwnames = Borrowed::from_ptr_or_opt(py, kwnames); + if let Some(kwnames) = kwnames { + // Safety: kwnames is known to be a PyTuple from the Python interpreter + let kwnames = kwnames.downcast_unchecked::(); + // 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), kwnames.len(), @@ -322,7 +327,7 @@ impl FunctionDescription { /// - `kwargs` must be a pointer to a PyDict, or NULL. pub unsafe fn extract_arguments_tuple_dict<'py, V, K>( &self, - _py: Python<'py>, + py: Python<'py>, args: *mut ffi::PyObject, kwargs: *mut ffi::PyObject, output: &mut [Option>], @@ -331,11 +336,14 @@ impl FunctionDescription { V: VarargsHandler<'py>, K: VarkeywordsHandler<'py>, { - // Safety: Bound has the same layout as a raw pointer, and reference is known to be - // borrowed for 'py. - let args: &'py Bound<'py, PyTuple> = std::mem::transmute(&args); - let kwargs: &'py Option> = std::mem::transmute(&kwargs); - let kwargs = kwargs.as_ref(); + // Safety: + // - `args` is known to be a tuple + // - `kwargs` is known to be a dict or null + // - we both have the GIL and can borrow these input references for the `'py` lifetime. + let args: Borrowed<'py, 'py, PyTuple> = + Borrowed::from_ptr(py, args).downcast_unchecked::(); + let kwargs: Option> = + Borrowed::from_ptr_or_opt(py, kwargs).map(|kwargs| kwargs.downcast_unchecked()); let num_positional_parameters = self.positional_parameter_names.len(); @@ -356,7 +364,7 @@ impl FunctionDescription { } // If any arguments remain, push them to varargs (if possible) or error - let varargs = V::handle_varargs_tuple(args, self)?; + let varargs = V::handle_varargs_tuple(&args, self)?; // Handle keyword arguments let mut varkeywords = K::Varkeywords::default(); diff --git a/src/types/dict.rs b/src/types/dict.rs index 2e81662e907..5020e0fb689 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -517,12 +517,12 @@ impl<'py> PyDictMethods<'py> for Bound<'py, PyDict> { } } -impl<'py> Bound<'py, PyDict> { +impl<'a, 'py> Borrowed<'a, 'py, PyDict> { /// Iterates over the contents of this dictionary without incrementing reference counts. /// /// # Safety /// It must be known that this dictionary will not be modified during iteration. - pub(crate) unsafe fn iter_borrowed<'a>(&'a self) -> BorrowedDictIter<'a, 'py> { + pub(crate) unsafe fn iter_borrowed(self) -> BorrowedDictIter<'a, 'py> { BorrowedDictIter::new(self) } } @@ -672,7 +672,7 @@ mod borrowed_iter { /// without incrementing reference counts. This is only safe if it's known /// that the dictionary will not be modified during iteration. pub struct BorrowedDictIter<'a, 'py> { - dict: &'a Bound<'py, PyDict>, + dict: Borrowed<'a, 'py, PyDict>, ppos: ffi::Py_ssize_t, len: ffi::Py_ssize_t, } @@ -710,8 +710,8 @@ mod borrowed_iter { } impl<'a, 'py> BorrowedDictIter<'a, 'py> { - pub(super) fn new(dict: &'a Bound<'py, PyDict>) -> Self { - let len = dict_len(dict); + pub(super) fn new(dict: Borrowed<'a, 'py, PyDict>) -> Self { + let len = dict_len(&dict); BorrowedDictIter { dict, ppos: 0, len } } } diff --git a/src/types/tuple.rs b/src/types/tuple.rs index e41fcbf0020..e5b0777622e 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -412,7 +412,7 @@ impl<'py> PyTupleMethods<'py> for Bound<'py, PyTuple> { } fn iter_borrowed<'a>(&'a self) -> BorrowedTupleIterator<'a, 'py> { - BorrowedTupleIterator::new(self.as_borrowed()) + self.as_borrowed().iter_borrowed() } fn to_list(&self) -> Bound<'py, PyList> { @@ -434,6 +434,10 @@ impl<'a, 'py> Borrowed<'a, 'py, PyTuple> { unsafe fn get_borrowed_item_unchecked(self, index: usize) -> Borrowed<'a, 'py, PyAny> { ffi::PyTuple_GET_ITEM(self.as_ptr(), index as Py_ssize_t).assume_borrowed(self.py()) } + + pub(crate) fn iter_borrowed(self) -> BorrowedTupleIterator<'a, 'py> { + BorrowedTupleIterator::new(self) + } } /// Used by `PyTuple::iter()`.