Add elem_offset and related methods · model-checking/verify-rust-std@0374ea2
@@ -4540,6 +4540,121 @@ impl<T> [T] {
45404540// are disjunct and in bounds.
45414541unsafe { Ok(self.get_many_unchecked_mut(indices)) }
45424542}
4543+4544+/// Returns the index that an element reference points to.
4545+ ///
4546+ /// Returns `None` if `element` does not point within the slice or if it points between elements.
4547+ ///
4548+ /// This method is useful for extending slice iterators like [`slice::split`].
4549+ ///
4550+ /// Note that this uses pointer arithmetic and **does not compare elements**.
4551+ /// To find the index of an element via comparison, use
4552+ /// [`.iter().position()`](crate::iter::Iterator::position) instead.
4553+ ///
4554+ /// # Panics
4555+ /// Panics if `T` is zero-sized.
4556+ ///
4557+ /// # Examples
4558+ /// Basic usage:
4559+ /// ```
4560+ /// #![feature(substr_range)]
4561+ ///
4562+ /// let nums: &[u32] = &[1, 7, 1, 1];
4563+ /// let num = &nums[2];
4564+ ///
4565+ /// assert_eq!(num, &1);
4566+ /// assert_eq!(nums.elem_offset(num), Some(2));
4567+ /// ```
4568+ /// Returning `None` with an in-between element:
4569+ /// ```
4570+ /// #![feature(substr_range)]
4571+ ///
4572+ /// let arr: &[[u32; 2]] = &[[0, 1], [2, 3]];
4573+ /// let flat_arr: &[u32] = arr.as_flattened();
4574+ ///
4575+ /// let ok_elm: &[u32; 2] = flat_arr[0..2].try_into().unwrap();
4576+ /// let weird_elm: &[u32; 2] = flat_arr[1..3].try_into().unwrap();
4577+ ///
4578+ /// assert_eq!(ok_elm, &[0, 1]);
4579+ /// assert_eq!(weird_elm, &[1, 2]);
4580+ ///
4581+ /// assert_eq!(arr.elem_offset(ok_elm), Some(0)); // Points to element 0
4582+ /// assert_eq!(arr.elem_offset(weird_elm), None); // Points between element 0 and 1
4583+ /// ```
4584+ #[must_use]
4585+#[unstable(feature = "substr_range", issue = "126769")]
4586+pub fn elem_offset(&self, element: &T) -> Option<usize> {
4587+if T::IS_ZST {
4588+panic!("elements are zero-sized");
4589+}
4590+4591+let self_start = self.as_ptr() as usize;
4592+let elem_start = element as *const T as usize;
4593+4594+let byte_offset = elem_start.wrapping_sub(self_start);
4595+4596+if byte_offset % mem::size_of::<T>() != 0 {
4597+return None;
4598+}
4599+4600+let offset = byte_offset / mem::size_of::<T>();
4601+4602+if offset < self.len() { Some(offset) } else { None }
4603+}
4604+4605+/// Returns the range of indices that a subslice points to.
4606+ ///
4607+ /// Returns `None` if `subslice` does not point within the slice or if it points between elements.
4608+ ///
4609+ /// This method **does not compare elements**. Instead, this method finds the location in the slice that
4610+ /// `subslice` was obtained from. To find the index of a subslice via comparison, instead use
4611+ /// [`.windows()`](slice::windows)[`.position()`](crate::iter::Iterator::position).
4612+ ///
4613+ /// This method is useful for extending slice iterators like [`slice::split`].
4614+ ///
4615+ /// Note that this may return a false positive (either `Some(0..0)` or `Some(self.len()..self.len())`)
4616+ /// if `subslice` has a length of zero and points to the beginning or end of another, separate, slice.
4617+ ///
4618+ /// # Panics
4619+ /// Panics if `T` is zero-sized.
4620+ ///
4621+ /// # Examples
4622+ /// Basic usage:
4623+ /// ```
4624+ /// #![feature(substr_range)]
4625+ ///
4626+ /// let nums = &[0, 5, 10, 0, 0, 5];
4627+ ///
4628+ /// let mut iter = nums
4629+ /// .split(|t| *t == 0)
4630+ /// .map(|n| nums.subslice_range(n).unwrap());
4631+ ///
4632+ /// assert_eq!(iter.next(), Some(0..0));
4633+ /// assert_eq!(iter.next(), Some(1..3));
4634+ /// assert_eq!(iter.next(), Some(4..4));
4635+ /// assert_eq!(iter.next(), Some(5..6));
4636+ /// ```
4637+ #[must_use]
4638+#[unstable(feature = "substr_range", issue = "126769")]
4639+pub fn subslice_range(&self, subslice: &[T]) -> Option<Range<usize>> {
4640+if T::IS_ZST {
4641+panic!("elements are zero-sized");
4642+}
4643+4644+let self_start = self.as_ptr() as usize;
4645+let subslice_start = subslice.as_ptr() as usize;
4646+4647+let byte_start = subslice_start.wrapping_sub(self_start);
4648+4649+if byte_start % core::mem::size_of::<T>() != 0 {
4650+return None;
4651+}
4652+4653+let start = byte_start / core::mem::size_of::<T>();
4654+let end = start.wrapping_add(subslice.len());
4655+4656+if start <= self.len() && end <= self.len() { Some(start..end) } else { None }
4657+}
45434658}
4544465945454660impl<T, const N: usize> [[T; N]] {