diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs index a43853604a2d2..da4b803c64d56 100644 --- a/library/alloc/src/collections/vec_deque/drain.rs +++ b/library/alloc/src/collections/vec_deque/drain.rs @@ -5,6 +5,7 @@ use core::ptr::NonNull; use core::{fmt, ptr}; use super::VecDeque; +use super::index::WrappedIndex; use crate::alloc::{Allocator, Global}; /// A draining iterator over the elements of a `VecDeque`. @@ -203,11 +204,11 @@ impl Drop for Drain<'_, T, A> { let (src, dst, len); if head_len < tail_len { src = source_deque.head; - dst = source_deque.to_physical_idx(drain_len); + dst = source_deque.to_wrapped_index(drain_len); len = head_len; } else { - src = source_deque.to_physical_idx(head_len + drain_len); - dst = source_deque.to_physical_idx(head_len); + src = source_deque.to_wrapped_index(head_len + drain_len); + dst = source_deque.to_wrapped_index(head_len); len = tail_len; }; @@ -220,10 +221,10 @@ impl Drop for Drain<'_, T, A> { if new_len == 0 { // Special case: If the entire deque was drained, reset the head back to 0, // like `.clear()` does. - source_deque.head = 0; + source_deque.head = WrappedIndex::zero(); } else if head_len < tail_len { // If we moved the head above, then we need to adjust the head index here. - source_deque.head = source_deque.to_physical_idx(drain_len); + source_deque.head = source_deque.to_wrapped_index(drain_len); } source_deque.len = new_len; } @@ -240,7 +241,7 @@ impl Iterator for Drain<'_, T, A> { if self.remaining == 0 { return None; } - let wrapped_idx = unsafe { self.deque.as_ref().to_physical_idx(self.idx) }; + let wrapped_idx = unsafe { self.deque.as_ref().to_wrapped_index(self.idx) }; self.idx += 1; self.remaining -= 1; Some(unsafe { self.deque.as_mut().buffer_read(wrapped_idx) }) @@ -261,7 +262,8 @@ impl DoubleEndedIterator for Drain<'_, T, A> { return None; } self.remaining -= 1; - let wrapped_idx = unsafe { self.deque.as_ref().to_physical_idx(self.idx + self.remaining) }; + let wrapped_idx = + unsafe { self.deque.as_ref().to_wrapped_index(self.idx + self.remaining) }; Some(unsafe { self.deque.as_mut().buffer_read(wrapped_idx) }) } } diff --git a/library/alloc/src/collections/vec_deque/extract_if.rs b/library/alloc/src/collections/vec_deque/extract_if.rs index 437f0d6dd5eb3..19439dfb4f05d 100644 --- a/library/alloc/src/collections/vec_deque/extract_if.rs +++ b/library/alloc/src/collections/vec_deque/extract_if.rs @@ -83,8 +83,8 @@ where // // Note: we can't use `vec.get_mut(i).unwrap()` here since the precondition for that // function is that i < vec.len, but we've set vec's length to zero. - let idx = self.vec.to_physical_idx(i); - let cur = unsafe { &mut *self.vec.ptr().add(idx) }; + let idx = self.vec.to_wrapped_index(i); + let cur = unsafe { &mut *self.vec.ptr().add(idx.as_index()) }; let drained = (self.pred)(cur); // Update the index *after* the predicate is called. If the index // is updated prior and the predicate panics, the element at this @@ -95,7 +95,7 @@ where // SAFETY: We never touch this element again after returning it. return Some(unsafe { ptr::read(cur) }); } else if self.del > 0 { - let hole_slot = self.vec.to_physical_idx(i - self.del); + let hole_slot = self.vec.to_wrapped_index(i - self.del); // SAFETY: `self.del` > 0, so the hole slot must not overlap with current element. // We use copy for move, and never touch this element again. unsafe { self.vec.wrap_copy(idx, hole_slot, 1) }; @@ -113,8 +113,8 @@ where impl Drop for ExtractIf<'_, T, F, A> { fn drop(&mut self) { if self.del > 0 { - let src = self.vec.to_physical_idx(self.idx); - let dst = self.vec.to_physical_idx(self.idx - self.del); + let src = self.vec.to_wrapped_index(self.idx); + let dst = self.vec.to_wrapped_index(self.idx - self.del); let len = self.old_len - self.idx; // SAFETY: Trailing unchecked items must be valid since we never touch them. unsafe { self.vec.wrap_copy(src, dst, len) }; @@ -131,7 +131,7 @@ where { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let peek = if self.idx < self.end { - let idx = self.vec.to_physical_idx(self.idx); + let idx = self.vec.to_wrapped_index(self.idx); // This has to use pointer arithmetic as `self.vec[self.idx]` or // `self.vec.get_unchecked(self.idx)` wouldn't work since we // temporarily set the length of `self.vec` to zero. @@ -141,7 +141,7 @@ where // smaller than `self.old_len`, `idx` is valid for indexing the // buffer. Also, per the invariant of `self.idx`, this element // has not been inspected/moved out yet. - Some(unsafe { &*self.vec.ptr().add(idx) }) + Some(unsafe { &*self.vec.ptr().add(idx.as_index()) }) } else { None }; diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs index 2b09a5e7ddc58..e18b85dd4b694 100644 --- a/library/alloc/src/collections/vec_deque/into_iter.rs +++ b/library/alloc/src/collections/vec_deque/into_iter.rs @@ -5,6 +5,7 @@ use core::ops::Try; use core::{array, fmt, ptr}; use super::VecDeque; +use super::index::WrappedIndex; use crate::alloc::{Allocator, Global}; /// An owning iterator over the elements of a `VecDeque`. @@ -86,7 +87,7 @@ impl Iterator for IntoIter { impl<'a, T, A: Allocator> Drop for Guard<'a, T, A> { fn drop(&mut self) { self.deque.len -= self.consumed; - self.deque.head = self.deque.to_physical_idx(self.consumed); + self.deque.head = self.deque.to_wrapped_index(self.consumed); } } @@ -140,7 +141,7 @@ impl Iterator for IntoIter { // SAFETY: By manually adjusting the head and length of the deque, we effectively // make it forget the first `N` elements, so taking ownership of them is safe. unsafe { ptr::copy_nonoverlapping(head.as_ptr(), raw_arr_ptr, N) }; - self.inner.head = self.inner.to_physical_idx(N); + self.inner.head = self.inner.to_wrapped_index(N); self.inner.len -= N; // SAFETY: We initialized the entire array with items from `head` return Ok(unsafe { raw_arr.transpose().assume_init() }); @@ -155,7 +156,7 @@ impl Iterator for IntoIter { unsafe { ptr::copy_nonoverlapping(tail.as_ptr(), raw_arr_ptr.add(head.len()), remaining) }; - self.inner.head = self.inner.to_physical_idx(N); + self.inner.head = self.inner.to_wrapped_index(N); self.inner.len -= N; // SAFETY: We initialized the entire array with items from `head` and `tail` Ok(unsafe { raw_arr.transpose().assume_init() }) @@ -166,7 +167,7 @@ impl Iterator for IntoIter { }; let init = head.len() + tail.len(); // We completely drained all the deques elements. - self.inner.head = 0; + self.inner.head = WrappedIndex::zero(); self.inner.len = 0; // SAFETY: We copied all elements from both slices to the beginning of the array, so // the given range is initialized. diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index eda29db442572..f91536df266d5 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -107,7 +107,7 @@ pub struct VecDeque< > { // `self[0]`, if it exists, is `buf[head]`. // `head < buf.capacity()`, unless `buf.capacity() == 0` when `head == 0`. - head: usize, + head: WrappedIndex, // the number of initialized elements, starting from the one at `head` and potentially wrapping around. // if `len == 0`, the exact value of `head` is unimportant. // if `T` is zero-Sized, then `self.len <= usize::MAX`, otherwise `self.len <= isize::MAX as usize`. @@ -183,7 +183,7 @@ impl VecDeque { unsafe fn push_unchecked(&mut self, element: T) { // SAFETY: Because of the precondition, it's guaranteed that there is space // in the logical array after the last element. - unsafe { self.buffer_write(self.to_physical_idx(self.len), element) }; + unsafe { self.buffer_write(self.to_wrapped_index(self.len), element) }; // This can't overflow because `deque.len() < deque.capacity() <= usize::MAX`. self.len += 1; } @@ -205,8 +205,8 @@ impl VecDeque { /// Moves an element out of the buffer #[inline] - unsafe fn buffer_read(&mut self, off: usize) -> T { - unsafe { ptr::read(self.ptr().add(off)) } + unsafe fn buffer_read(&mut self, off: WrappedIndex) -> T { + unsafe { ptr::read(self.ptr().add(off.as_index())) } } /// Writes an element into the buffer, moving it and returning a pointer to it. @@ -214,9 +214,9 @@ impl VecDeque { /// /// May only be called if `off < self.capacity()`. #[inline] - unsafe fn buffer_write(&mut self, off: usize, value: T) -> &mut T { + unsafe fn buffer_write(&mut self, off: WrappedIndex, value: T) -> &mut T { unsafe { - let ptr = self.ptr().add(off); + let ptr = self.ptr().add(off.as_index()); ptr::write(ptr, value); &mut *ptr } @@ -240,20 +240,23 @@ impl VecDeque { /// Returns the index in the underlying buffer for a given logical element /// index + addend. #[inline] - fn wrap_add(&self, idx: usize, addend: usize) -> usize { - wrap_index(idx.wrapping_add(addend), self.capacity()) + fn wrap_add(&self, idx: WrappedIndex, addend: usize) -> WrappedIndex { + wrap_index(idx.as_index().wrapping_add(addend), self.capacity()) } #[inline] - fn to_physical_idx(&self, idx: usize) -> usize { + fn to_wrapped_index(&self, idx: usize) -> WrappedIndex { self.wrap_add(self.head, idx) } /// Returns the index in the underlying buffer for a given logical element /// index - subtrahend. #[inline] - fn wrap_sub(&self, idx: usize, subtrahend: usize) -> usize { - wrap_index(idx.wrapping_sub(subtrahend).wrapping_add(self.capacity()), self.capacity()) + fn wrap_sub(&self, idx: WrappedIndex, subtrahend: usize) -> WrappedIndex { + wrap_index( + idx.as_index().wrapping_sub(subtrahend).wrapping_add(self.capacity()), + self.capacity(), + ) } /// Get source, destination and count (like the arguments to [`ptr::copy_nonoverlapping`]) @@ -273,7 +276,7 @@ impl VecDeque { src: usize, dst: usize, count: usize, - head: usize, + head: WrappedIndex, ) -> [(*const T, *mut T, usize); 2] { // "`src` and `dst` must be at least as far apart as `count`" debug_assert!( @@ -289,8 +292,8 @@ impl VecDeque { let wrapped_src = self.wrap_add(head, src); let wrapped_dst = self.wrap_add(head, dst); - let room_after_src = self.capacity() - wrapped_src; - let room_after_dst = self.capacity() - wrapped_dst; + let room_after_src = self.capacity() - wrapped_src.as_index(); + let room_after_dst = self.capacity() - wrapped_dst.as_index(); let src_wraps = room_after_src < count; let dst_wraps = room_after_dst < count; @@ -305,8 +308,8 @@ impl VecDeque { unsafe { let ptr = self.ptr(); - let src_ptr = ptr.add(wrapped_src); - let dst_ptr = ptr.add(wrapped_dst); + let src_ptr = ptr.add(wrapped_src.as_index()); + let dst_ptr = ptr.add(wrapped_dst.as_index()); if src_wraps { [ @@ -330,7 +333,7 @@ impl VecDeque { /// Copies a contiguous block of memory len long from src to dst #[inline] - unsafe fn copy(&mut self, src: usize, dst: usize, len: usize) { + unsafe fn copy(&mut self, src: WrappedIndex, dst: WrappedIndex, len: usize) { debug_assert!( dst + len <= self.capacity(), "cpy dst={} src={} len={} cap={}", @@ -348,13 +351,13 @@ impl VecDeque { self.capacity() ); unsafe { - ptr::copy(self.ptr().add(src), self.ptr().add(dst), len); + ptr::copy(self.ptr().add(src.as_index()), self.ptr().add(dst.as_index()), len); } } /// Copies a contiguous block of memory len long from src to dst #[inline] - unsafe fn copy_nonoverlapping(&mut self, src: usize, dst: usize, len: usize) { + unsafe fn copy_nonoverlapping(&mut self, src: WrappedIndex, dst: WrappedIndex, len: usize) { debug_assert!( dst + len <= self.capacity(), "cno dst={} src={} len={} cap={}", @@ -372,14 +375,18 @@ impl VecDeque { self.capacity() ); unsafe { - ptr::copy_nonoverlapping(self.ptr().add(src), self.ptr().add(dst), len); + ptr::copy_nonoverlapping( + self.ptr().add(src.as_index()), + self.ptr().add(dst.as_index()), + len, + ); } } /// Copies a potentially wrapping block of memory len long from src to dest. /// (abs(dst - src) + len) must be no larger than capacity() (There must be at /// most one continuous overlapping region between src and dest). - unsafe fn wrap_copy(&mut self, src: usize, dst: usize, len: usize) { + unsafe fn wrap_copy(&mut self, src: WrappedIndex, dst: WrappedIndex, len: usize) { debug_assert!( cmp::min(src.abs_diff(dst), self.capacity() - src.abs_diff(dst)) + len <= self.capacity(), @@ -395,10 +402,10 @@ impl VecDeque { return; } - let dst_after_src = self.wrap_sub(dst, src) < len; + let dst_after_src = self.wrap_sub(dst, src.as_index()) < len; - let src_pre_wrap_len = self.capacity() - src; - let dst_pre_wrap_len = self.capacity() - dst; + let src_pre_wrap_len = self.capacity() - src.as_index(); + let dst_pre_wrap_len = self.capacity() - dst.as_index(); let src_wraps = src_pre_wrap_len < len; let dst_wraps = dst_pre_wrap_len < len; @@ -426,7 +433,11 @@ impl VecDeque { // unsafe { self.copy(src, dst, dst_pre_wrap_len); - self.copy(src + dst_pre_wrap_len, 0, len - dst_pre_wrap_len); + self.copy( + src.add(dst_pre_wrap_len), + WrappedIndex::zero(), + len - dst_pre_wrap_len, + ); } } (true, false, true) => { @@ -439,7 +450,11 @@ impl VecDeque { // . . D . // unsafe { - self.copy(src + dst_pre_wrap_len, 0, len - dst_pre_wrap_len); + self.copy( + src.add(dst_pre_wrap_len), + WrappedIndex::zero(), + len - dst_pre_wrap_len, + ); self.copy(src, dst, dst_pre_wrap_len); } } @@ -454,7 +469,11 @@ impl VecDeque { // unsafe { self.copy(src, dst, src_pre_wrap_len); - self.copy(0, dst + src_pre_wrap_len, len - src_pre_wrap_len); + self.copy( + WrappedIndex::zero(), + dst.add(src_pre_wrap_len), + len - src_pre_wrap_len, + ); } } (true, true, false) => { @@ -467,7 +486,11 @@ impl VecDeque { // D . . . // unsafe { - self.copy(0, dst + src_pre_wrap_len, len - src_pre_wrap_len); + self.copy( + WrappedIndex::zero(), + dst.add(src_pre_wrap_len), + len - src_pre_wrap_len, + ); self.copy(src, dst, src_pre_wrap_len); } } @@ -485,8 +508,12 @@ impl VecDeque { let delta = dst_pre_wrap_len - src_pre_wrap_len; unsafe { self.copy(src, dst, src_pre_wrap_len); - self.copy(0, dst + src_pre_wrap_len, delta); - self.copy(delta, 0, len - dst_pre_wrap_len); + self.copy(WrappedIndex::zero(), dst.add(src_pre_wrap_len), delta); + self.copy( + WrappedIndex::new(delta), + WrappedIndex::zero(), + len - dst_pre_wrap_len, + ); } } (true, true, true) => { @@ -502,8 +529,16 @@ impl VecDeque { debug_assert!(src_pre_wrap_len > dst_pre_wrap_len); let delta = src_pre_wrap_len - dst_pre_wrap_len; unsafe { - self.copy(0, delta, len - src_pre_wrap_len); - self.copy(self.capacity() - delta, 0, delta); + self.copy( + WrappedIndex::zero(), + WrappedIndex::new(delta), + len - src_pre_wrap_len, + ); + self.copy( + WrappedIndex::new(self.capacity() - delta), + WrappedIndex::zero(), + delta, + ); self.copy(src, dst, dst_pre_wrap_len); } } @@ -513,17 +548,17 @@ impl VecDeque { /// Copies all values from `src` to `dst`, wrapping around if needed. /// Assumes capacity is sufficient. #[inline] - unsafe fn copy_slice(&mut self, dst: usize, src: &[T]) { + unsafe fn copy_slice(&mut self, dst: WrappedIndex, src: &[T]) { debug_assert!(src.len() <= self.capacity()); - let head_room = self.capacity() - dst; + let head_room = self.capacity() - dst.as_index(); if src.len() <= head_room { unsafe { - ptr::copy_nonoverlapping(src.as_ptr(), self.ptr().add(dst), src.len()); + ptr::copy_nonoverlapping(src.as_ptr(), self.ptr().add(dst.as_index()), src.len()); } } else { let (left, right) = src.split_at(head_room); unsafe { - ptr::copy_nonoverlapping(left.as_ptr(), self.ptr().add(dst), left.len()); + ptr::copy_nonoverlapping(left.as_ptr(), self.ptr().add(dst.as_index()), left.len()); ptr::copy_nonoverlapping(right.as_ptr(), self.ptr(), right.len()); } } @@ -533,7 +568,7 @@ impl VecDeque { /// Assumes capacity is sufficient. /// Equivalent to calling [`VecDeque::copy_slice`] with a [reversed](https://doc.rust-lang.org/std/primitive.slice.html#method.reverse) slice. #[inline] - unsafe fn copy_slice_reversed(&mut self, dst: usize, src: &[T]) { + unsafe fn copy_slice_reversed(&mut self, dst: WrappedIndex, src: &[T]) { /// # Safety /// /// See [`ptr::copy_nonoverlapping`]. @@ -544,15 +579,23 @@ impl VecDeque { } debug_assert!(src.len() <= self.capacity()); - let head_room = self.capacity() - dst; + let head_room = self.capacity() - dst.as_index(); if src.len() <= head_room { unsafe { - copy_nonoverlapping_reversed(src.as_ptr(), self.ptr().add(dst), src.len()); + copy_nonoverlapping_reversed( + src.as_ptr(), + self.ptr().add(dst.as_index()), + src.len(), + ); } } else { let (left, right) = src.split_at(src.len() - head_room); unsafe { - copy_nonoverlapping_reversed(right.as_ptr(), self.ptr().add(dst), right.len()); + copy_nonoverlapping_reversed( + right.as_ptr(), + self.ptr().add(dst.as_index()), + right.len(), + ); copy_nonoverlapping_reversed(left.as_ptr(), self.ptr(), left.len()); } } @@ -567,12 +610,12 @@ impl VecDeque { #[inline] unsafe fn write_iter( &mut self, - dst: usize, + dst: WrappedIndex, iter: impl Iterator, written: &mut usize, ) { iter.enumerate().for_each(|(i, element)| unsafe { - self.buffer_write(dst + i, element); + self.buffer_write(dst.add(i), element); *written += 1; }); } @@ -587,7 +630,7 @@ impl VecDeque { /// Assumes capacity is sufficient. unsafe fn write_iter_wrapping( &mut self, - dst: usize, + dst: WrappedIndex, mut iter: impl Iterator, len: usize, ) -> usize { @@ -602,7 +645,7 @@ impl VecDeque { } } - let head_room = self.capacity() - dst; + let head_room = self.capacity() - dst.as_index(); let mut guard = Guard { deque: self, written: 0 }; @@ -615,7 +658,7 @@ impl VecDeque { ByRefSized(&mut iter).take(head_room), &mut guard.written, ); - guard.deque.write_iter(0, iter, &mut guard.written) + guard.deque.write_iter(WrappedIndex::zero(), iter, &mut guard.written) }; } @@ -652,16 +695,20 @@ impl VecDeque { // A // Nop } else { - let head_len = old_capacity - self.head; + let head_len = old_capacity - self.head.as_index(); let tail_len = self.len - head_len; if head_len > tail_len && new_capacity - old_capacity >= tail_len { // B unsafe { - self.copy_nonoverlapping(0, old_capacity, tail_len); + self.copy_nonoverlapping( + WrappedIndex::zero(), + WrappedIndex::new(old_capacity), + tail_len, + ); } } else { // C - let new_head = new_capacity - head_len; + let new_head = unsafe { WrappedIndex::new(new_capacity - head_len) }; unsafe { // can't use copy_nonoverlapping here, because if e.g. head_len = 2 // and new_capacity = old_capacity + 1, then the heads overlap. @@ -780,7 +827,7 @@ impl VecDeque { #[must_use] pub const fn new() -> VecDeque { // FIXME(const-hack): This should just be `VecDeque::new_in(Global)` once that hits stable. - VecDeque { head: 0, len: 0, buf: RawVec::new() } + VecDeque { head: WrappedIndex::zero(), len: 0, buf: RawVec::new() } } /// Creates an empty deque with space for at least `capacity` elements. @@ -820,7 +867,11 @@ impl VecDeque { #[inline] #[unstable(feature = "try_with_capacity", issue = "91913")] pub fn try_with_capacity(capacity: usize) -> Result, TryReserveError> { - Ok(VecDeque { head: 0, len: 0, buf: RawVec::try_with_capacity_in(capacity, Global)? }) + Ok(VecDeque { + head: WrappedIndex::zero(), + len: 0, + buf: RawVec::try_with_capacity_in(capacity, Global)?, + }) } } @@ -837,7 +888,7 @@ impl VecDeque { #[inline] #[unstable(feature = "allocator_api", issue = "32838")] pub const fn new_in(alloc: A) -> VecDeque { - VecDeque { head: 0, len: 0, buf: RawVec::new_in(alloc) } + VecDeque { head: WrappedIndex::zero(), len: 0, buf: RawVec::new_in(alloc) } } /// Creates an empty deque with space for at least `capacity` elements. @@ -851,7 +902,11 @@ impl VecDeque { /// ``` #[unstable(feature = "allocator_api", issue = "32838")] pub fn with_capacity_in(capacity: usize, alloc: A) -> VecDeque { - VecDeque { head: 0, len: 0, buf: RawVec::with_capacity_in(capacity, alloc) } + VecDeque { + head: WrappedIndex::zero(), + len: 0, + buf: RawVec::with_capacity_in(capacity, alloc), + } } /// Creates a `VecDeque` from a raw allocation, when the initialized @@ -880,7 +935,7 @@ impl VecDeque { // and that the allocation is valid for use in `RawVec`. unsafe { VecDeque { - head: initialized.start, + head: WrappedIndex::new(initialized.start), len: initialized.end.unchecked_sub(initialized.start), buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), } @@ -906,8 +961,8 @@ impl VecDeque { #[stable(feature = "rust1", since = "1.0.0")] pub fn get(&self, index: usize) -> Option<&T> { if index < self.len { - let idx = self.to_physical_idx(index); - unsafe { Some(&*self.ptr().add(idx)) } + let idx = self.to_wrapped_index(index); + unsafe { Some(&*self.ptr().add(idx.as_index())) } } else { None } @@ -936,8 +991,8 @@ impl VecDeque { #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { if index < self.len { - let idx = self.to_physical_idx(index); - unsafe { Some(&mut *self.ptr().add(idx)) } + let idx = self.to_wrapped_index(index); + unsafe { Some(&mut *self.ptr().add(idx.as_index())) } } else { None } @@ -970,9 +1025,9 @@ impl VecDeque { pub fn swap(&mut self, i: usize, j: usize) { assert!(i < self.len()); assert!(j < self.len()); - let ri = self.to_physical_idx(i); - let rj = self.to_physical_idx(j); - unsafe { ptr::swap(self.ptr().add(ri), self.ptr().add(rj)) } + let ri = self.to_wrapped_index(i); + let rj = self.to_wrapped_index(j); + unsafe { ptr::swap(self.ptr().add(ri.as_index()), self.ptr().add(rj.as_index())) } } /// Returns the number of elements the deque can hold without @@ -1223,8 +1278,8 @@ impl VecDeque { let old_head = self.head; if self.len == 0 { - self.head = 0; - } else if self.head >= target_cap && tail_outside { + self.head = WrappedIndex::zero(); + } else if self.head.as_index() >= target_cap && tail_outside { // Head and tail are both out of bounds, so copy all of them to the front. // // H := head @@ -1235,9 +1290,9 @@ impl VecDeque { // [o o o o o o o . ] unsafe { // nonoverlapping because `self.head >= target_cap >= self.len`. - self.copy_nonoverlapping(self.head, 0, self.len); + self.copy_nonoverlapping(self.head, WrappedIndex::zero(), self.len); } - self.head = 0; + self.head = WrappedIndex::zero(); } else if self.head < target_cap && tail_outside { // Head is in bounds, tail is out of bounds. // Copy the overflowing part to the beginning of the @@ -1250,8 +1305,9 @@ impl VecDeque { // L H // [o o . o o o o o ] let len = self.head + self.len - target_cap; + // Safety: head is < target_cap, so the index is wrapped unsafe { - self.copy_nonoverlapping(target_cap, 0, len); + self.copy_nonoverlapping(WrappedIndex::new(target_cap), WrappedIndex::zero(), len); } } else if !self.is_contiguous() { // The head slice is at least partially out of bounds, tail is in bounds. @@ -1264,8 +1320,10 @@ impl VecDeque { // [o o o o o . . . . . . . . . o o ] // L H // [o o o o o . o o ] - let head_len = self.capacity() - self.head; - let new_head = target_cap - head_len; + let head_len = self.capacity() - self.head.as_index(); + + // Safety: head_len is at least one, so new_head will be < target_cap + let new_head = unsafe { WrappedIndex::new(target_cap - head_len) }; unsafe { // can't use `copy_nonoverlapping()` here because the new and old // regions for the head might overlap. @@ -1276,7 +1334,7 @@ impl VecDeque { struct Guard<'a, T, A: Allocator> { deque: &'a mut VecDeque, - old_head: usize, + old_head: WrappedIndex, target_cap: usize, } @@ -1308,7 +1366,7 @@ impl VecDeque { /// /// `old_head` refers to the head index before `shrink_to` was called. `target_cap` /// is the capacity that it was trying to shrink to. - unsafe fn abort_shrink(&mut self, old_head: usize, target_cap: usize) { + unsafe fn abort_shrink(&mut self, old_head: WrappedIndex, target_cap: usize) { // Moral equivalent of self.head + self.len <= target_cap. Won't overflow // because `self.len <= target_cap`. if self.head <= target_cap - self.len { @@ -1317,7 +1375,7 @@ impl VecDeque { } // `shrink_to` already copied the head to fit into the new capacity, so this won't overflow. - let head_len = target_cap - self.head; + let head_len = target_cap - self.head.as_index(); // `self.head > target_cap - self.len` => `self.len > target_cap - self.head =: head_len` so this must be positive. let tail_len = self.len - head_len; @@ -1328,7 +1386,11 @@ impl VecDeque { unsafe { // The old tail and the new tail can't overlap because the head slice lies between them. The // head slice ends at `target_cap`, so that's where we copy to. - self.copy_nonoverlapping(0, target_cap, tail_len); + self.copy_nonoverlapping( + WrappedIndex::zero(), + WrappedIndex::new(target_cap), + tail_len, + ); } } else { // Either there's not enough spare capacity to make the deque contiguous, or the head is shorter than the tail @@ -1453,7 +1515,7 @@ impl VecDeque { // and end < front.len() let end = front.len() - (len - back.len()); let drop_front = front.get_unchecked_mut(..end) as *mut _; - self.head += end; + self.head = self.head.add(end); self.len = len; ptr::drop_in_place(drop_front); } else { @@ -1461,7 +1523,7 @@ impl VecDeque { // 'end' is non-negative by the condition above let end = back.len() - len; let drop_back = back.get_unchecked_mut(..end) as *mut _; - self.head = self.to_physical_idx(self.len - len); + self.head = self.to_wrapped_index(self.len - len); self.len = len; // Make sure the second half is dropped even when a destructor @@ -1676,20 +1738,20 @@ impl VecDeque { // `slice::range` guarantees that `start <= end <= len`. // because `len != 0`, we know that `start < end`, so `start < len` // and the indexing is valid. - let wrapped_start = self.to_physical_idx(start); + let wrapped_start = self.to_wrapped_index(start); // this subtraction can never overflow because `wrapped_start` is // at most `self.capacity()` (and if `self.capacity != 0`, then `wrapped_start` is strictly less // than `self.capacity`). - let head_len = self.capacity() - wrapped_start; + let head_len = self.capacity() - wrapped_start.as_index(); if head_len >= len { // we know that `len + wrapped_start <= self.capacity <= usize::MAX`, so this addition can't overflow - (wrapped_start..wrapped_start + len, 0..0) + (wrapped_start.as_index()..wrapped_start + len, 0..0) } else { // can't overflow because of the if condition let tail_len = len - head_len; - (wrapped_start..self.capacity(), 0..tail_len) + (wrapped_start.as_index()..self.capacity(), 0..tail_len) } } } @@ -1920,7 +1982,7 @@ impl VecDeque { pub fn clear(&mut self) { self.truncate(0); // Not strictly necessary, but leaves things in a more consistent/predictable state. - self.head = 0; + self.head = WrappedIndex::zero(); } /// Returns `true` if the deque contains an element equal to the @@ -2066,7 +2128,7 @@ impl VecDeque { None } else { let old_head = self.head; - self.head = self.to_physical_idx(1); + self.head = self.to_wrapped_index(1); self.len -= 1; unsafe { core::hint::assert_unchecked(self.len < self.capacity()); @@ -2097,7 +2159,7 @@ impl VecDeque { self.len -= 1; unsafe { core::hint::assert_unchecked(self.len < self.capacity()); - Some(self.buffer_read(self.to_physical_idx(self.len))) + Some(self.buffer_read(self.to_wrapped_index(self.len))) } } } @@ -2227,7 +2289,7 @@ impl VecDeque { let len = self.len; self.len += 1; - unsafe { self.buffer_write(self.to_physical_idx(len), value) } + unsafe { self.buffer_write(self.to_wrapped_index(len), value) } } /// Prepends all contents of the iterator to the front of the deque. @@ -2441,9 +2503,9 @@ impl VecDeque { // and panicked. unsafe { // see `remove()` for explanation why this wrap_copy() call is safe. - self.wrap_copy(self.to_physical_idx(index), self.to_physical_idx(index + 1), k); + self.wrap_copy(self.to_wrapped_index(index), self.to_wrapped_index(index + 1), k); self.len += 1; - self.buffer_write(self.to_physical_idx(index), value) + self.buffer_write(self.to_wrapped_index(index), value) } } else { let old_head = self.head; @@ -2451,7 +2513,7 @@ impl VecDeque { unsafe { self.wrap_copy(old_head, self.head, index); self.len += 1; - self.buffer_write(self.to_physical_idx(index), value) + self.buffer_write(self.to_wrapped_index(index), value) } } } @@ -2484,7 +2546,7 @@ impl VecDeque { return None; } - let wrapped_idx = self.to_physical_idx(index); + let wrapped_idx = self.to_wrapped_index(index); let elem = unsafe { Some(self.buffer_read(wrapped_idx)) }; @@ -2497,7 +2559,7 @@ impl VecDeque { self.len -= 1; } else { let old_head = self.head; - self.head = self.to_physical_idx(1); + self.head = self.to_wrapped_index(1); unsafe { self.wrap_copy(old_head, self.head, index) }; self.len -= 1; } @@ -2601,23 +2663,23 @@ impl VecDeque { if T::IS_ZST { self.len = self.len.checked_add(other.len).expect("capacity overflow"); other.len = 0; - other.head = 0; + other.head = WrappedIndex::zero(); return; } self.reserve(other.len); unsafe { let (left, right) = other.as_slices(); - self.copy_slice(self.to_physical_idx(self.len), left); + self.copy_slice(self.to_wrapped_index(self.len), left); // no overflow, because self.capacity() >= old_cap + left.len() >= self.len + left.len() - self.copy_slice(self.to_physical_idx(self.len + left.len()), right); + self.copy_slice(self.to_wrapped_index(self.len + left.len()), right); } // SAFETY: Update pointers after copying to avoid leaving doppelganger // in case of panics. self.len += other.len; // Now that we own its values, forget everything in `other`. other.len = 0; - other.head = 0; + other.head = WrappedIndex::zero(); } /// Retains only the elements specified by the predicate. @@ -2825,11 +2887,13 @@ impl VecDeque { #[stable(feature = "deque_make_contiguous", since = "1.48.0")] pub fn make_contiguous(&mut self) -> &mut [T] { if T::IS_ZST { - self.head = 0; + self.head = WrappedIndex::zero(); } if self.is_contiguous() { - unsafe { return slice::from_raw_parts_mut(self.ptr().add(self.head), self.len) } + unsafe { + return slice::from_raw_parts_mut(self.ptr().add(self.head.as_index()), self.len); + } } let &mut Self { head, len, .. } = self; @@ -2837,9 +2901,11 @@ impl VecDeque { let cap = self.capacity(); let free = cap - len; - let head_len = cap - head; - let tail = len - head_len; - let tail_len = tail; + let head_len = cap - head.as_index(); + + // Safety: tail <= head_len <= len <= capacity + let tail = unsafe { WrappedIndex::new(len - head_len) }; + let tail_len = tail.as_index(); if free >= head_len { // there is enough free space to copy the head in one go, @@ -2849,13 +2915,13 @@ impl VecDeque { // from: DEFGH....ABC // to: ABCDEFGH.... unsafe { - self.copy(0, head_len, tail_len); + self.copy(WrappedIndex::zero(), WrappedIndex::new(head_len), tail_len); // ...DEFGH.ABC - self.copy_nonoverlapping(head, 0, head_len); + self.copy_nonoverlapping(head, WrappedIndex::zero(), head_len); // ABCDEFGH.... } - self.head = 0; + self.head = WrappedIndex::zero(); } else if free >= tail_len { // there is enough free space to copy the tail in one go, // this means that we first shift the head forwards, and then @@ -2866,7 +2932,7 @@ impl VecDeque { unsafe { self.copy(head, tail, head_len); // FGHABCDE.... - self.copy_nonoverlapping(0, tail + head_len, tail_len); + self.copy_nonoverlapping(WrappedIndex::zero(), tail.add(head_len), tail_len); // ...ABCDEFGH. } @@ -2902,7 +2968,7 @@ impl VecDeque { // because we only move the tail forward as much as there's free space // behind it, we don't overwrite any elements of the head slice, and // the slices end up right next to each other. - self.copy(0, free, tail_len); + self.copy(WrappedIndex::zero(), WrappedIndex::new(free), tail_len); } // We just copied the tail right next to the head slice, @@ -2915,7 +2981,7 @@ impl VecDeque { // the used part of the buffer now is `free..self.capacity()`, so set // `head` to the beginning of that range. - self.head = free; + self.head = WrappedIndex::new(free); } } else { // head is shorter so: @@ -2928,7 +2994,7 @@ impl VecDeque { // right next to each other and we don't need to move any memory. if free != 0 { // copy the head slice to lie right behind the tail slice. - self.copy(self.head, tail_len, head_len); + self.copy(self.head, WrappedIndex::new(tail_len), head_len); } // because we copied the head slice so that both slices lie right @@ -2941,12 +3007,12 @@ impl VecDeque { // the used part of the buffer now is `0..self.len`, so set // `head` to the beginning of that range. - self.head = 0; + self.head = WrappedIndex::zero(); } } } - unsafe { slice::from_raw_parts_mut(ptr.add(self.head), self.len) } + unsafe { slice::from_raw_parts_mut(ptr.add(self.head.as_index()), self.len) } } /// Rotates the double-ended queue `n` places to the left. @@ -3046,16 +3112,16 @@ impl VecDeque { unsafe fn rotate_left_inner(&mut self, mid: usize) { debug_assert!(mid * 2 <= self.len()); unsafe { - self.wrap_copy(self.head, self.to_physical_idx(self.len), mid); + self.wrap_copy(self.head, self.to_wrapped_index(self.len), mid); } - self.head = self.to_physical_idx(mid); + self.head = self.to_wrapped_index(mid); } unsafe fn rotate_right_inner(&mut self, k: usize) { debug_assert!(k * 2 <= self.len()); self.head = self.wrap_sub(self.head, k); unsafe { - self.wrap_copy(self.to_physical_idx(self.len), self.head, k); + self.wrap_copy(self.to_wrapped_index(self.len), self.head, k); } } @@ -3456,7 +3522,7 @@ impl SpecExtendFromWithin for VecDeque { let (src, dst, count) = ranges[1]; for offset in (0..count).rev() { dst.add(offset).write((*src.add(offset)).clone()); - self.head -= 1; + self.head = self.head.sub(1); self.len += 1; } @@ -3466,16 +3532,18 @@ impl SpecExtendFromWithin for VecDeque { if let Some(offset) = iter.next() { dst.add(offset).write((*src.add(offset)).clone()); // After the first clone of the second range, wrap `head` around - if self.head == 0 { - self.head = cap; + if self.head.is_zero() { + // SAFETY: the wrapped index may be temporarily equal to the capacity even if it + // is not zero, because we subtract it one line below. + self.head = WrappedIndex::new(cap); } - self.head -= 1; + self.head = self.head.sub(1); self.len += 1; // Continue like normal for offset in iter { dst.add(offset).write((*src.add(offset)).clone()); - self.head -= 1; + self.head = self.head.sub(1); self.len += 1; } } @@ -3529,15 +3597,108 @@ impl SpecExtendFromWithin for VecDeque { } } -/// Returns the index in the underlying buffer for a given logical element index. -#[inline] -fn wrap_index(logical_index: usize, capacity: usize) -> usize { - debug_assert!( - (logical_index == 0 && capacity == 0) - || logical_index < capacity - || (logical_index - capacity) < capacity - ); - if logical_index >= capacity { logical_index - capacity } else { logical_index } +use index::{WrappedIndex, wrap_index}; + +// The code is separated into a module to make it harder to construct a BufferIndex without +// going through wrapping. +mod index { + use core::cmp::Ordering; + + /// Returns the index in the underlying buffer for a given logical element index. + #[inline] + pub(super) fn wrap_index(logical_index: usize, capacity: usize) -> WrappedIndex { + debug_assert!( + (logical_index == 0 && capacity == 0) + || logical_index < capacity + || (logical_index - capacity) < capacity + ); + if logical_index >= capacity { + WrappedIndex(logical_index - capacity) + } else { + WrappedIndex(logical_index) + } + } + + /// Represents an index that can be safely used to index the VecDeque buffer. + /// It exists as a separate type to avoid passing logical (unwrapped) indices to various + /// VecDeque functions by accident. + /// + /// The invariant of this index is that it is always < VecDeque capacity, unless the VecDeque + /// is empty (in that case the index can be 0 when the capacity is 0). + #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] + #[repr(transparent)] + pub(super) struct WrappedIndex(usize); + + impl WrappedIndex { + /// Safety invariant: the newly constructed index must be in-bounds for the VecDeque + #[inline(always)] + pub(super) unsafe fn new(index: usize) -> Self { + Self(index) + } + + /// Safety invariant: the newly constructed index must still be in-bounds for the VecDeque + #[inline(always)] + pub(super) unsafe fn add(self, offset: usize) -> Self { + Self(self.0 + offset) + } + + /// Safety invariant: the newly constructed index must still be in-bounds for the VecDeque + #[inline(always)] + pub(super) unsafe fn sub(self, offset: usize) -> Self { + debug_assert!(self.0 >= offset); + Self(self.0 - offset) + } + + #[inline(always)] + pub(super) const fn zero() -> Self { + Self(0) + } + + #[inline(always)] + pub(super) fn abs_diff(self, other: Self) -> usize { + self.0.abs_diff(other.0) + } + + #[inline(always)] + pub(super) fn as_index(self) -> usize { + self.0 + } + + #[inline(always)] + pub(super) fn is_zero(self) -> bool { + self.0 == 0 + } + } + + impl core::ops::Add for WrappedIndex { + // The output might not be wrapped anymore + type Output = usize; + + #[inline(always)] + fn add(self, rhs: usize) -> Self::Output { + self.0 + rhs + } + } + + impl core::fmt::Display for WrappedIndex { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.0.fmt(f) + } + } + + impl core::cmp::PartialEq for WrappedIndex { + #[inline(always)] + fn eq(&self, other: &usize) -> bool { + self.0.eq(other) + } + } + + impl core::cmp::PartialOrd for WrappedIndex { + #[inline(always)] + fn partial_cmp(&self, other: &usize) -> Option { + self.0.partial_cmp(other) + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -3745,7 +3906,11 @@ impl From> for VecDeque { #[inline] fn from(other: Vec) -> Self { let (ptr, len, cap, alloc) = other.into_raw_parts_with_alloc(); - Self { head: 0, len, buf: unsafe { RawVec::from_raw_parts_in(ptr, cap, alloc) } } + Self { + head: WrappedIndex::zero(), + len, + buf: unsafe { RawVec::from_raw_parts_in(ptr, cap, alloc) }, + } } } @@ -3790,8 +3955,8 @@ impl From> for Vec { let cap = other.capacity(); let alloc = ptr::read(other.allocator()); - if other.head != 0 { - ptr::copy(buf.add(other.head), buf, len); + if !other.head.is_zero() { + ptr::copy(buf.add(other.head.as_index()), buf, len); } Vec::from_raw_parts_in(buf, len, cap, alloc) } @@ -3818,7 +3983,7 @@ impl From<[T; N]> for VecDeque { ptr::copy_nonoverlapping(arr.as_ptr(), deq.ptr(), N); } } - deq.head = 0; + deq.head = WrappedIndex::zero(); deq.len = N; deq } diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs index 184e8b769347d..5f7c78d812366 100644 --- a/library/alloc/src/collections/vec_deque/spec_extend.rs +++ b/library/alloc/src/collections/vec_deque/spec_extend.rs @@ -58,7 +58,7 @@ where self.reserve(additional); let written = unsafe { - self.write_iter_wrapping(self.to_physical_idx(self.len), iter, additional) + self.write_iter_wrapping(self.to_wrapped_index(self.len), iter, additional) }; debug_assert_eq!( @@ -83,7 +83,7 @@ impl SpecExtend> for Ve self.reserve(slice.len()); unsafe { - self.copy_slice(self.to_physical_idx(self.len), slice); + self.copy_slice(self.to_wrapped_index(self.len), slice); self.len += slice.len(); } iterator.forget_remaining_elements(); @@ -109,7 +109,7 @@ where self.reserve(slice.len()); unsafe { - self.copy_slice(self.to_physical_idx(self.len), slice); + self.copy_slice(self.to_wrapped_index(self.len), slice); self.len += slice.len(); } } diff --git a/library/alloc/src/collections/vec_deque/splice.rs b/library/alloc/src/collections/vec_deque/splice.rs index d7b9a96291c39..8a9e834d5bf8b 100644 --- a/library/alloc/src/collections/vec_deque/splice.rs +++ b/library/alloc/src/collections/vec_deque/splice.rs @@ -120,7 +120,7 @@ impl Drain<'_, T, A> { for idx in range_start..range_end { if let Some(new_item) = replace_with.next() { - let index = deque.to_physical_idx(idx); + let index = deque.to_wrapped_index(idx); unsafe { deque.buffer_write(index, new_item) }; deque.len += 1; self.drain_len -= 1; @@ -144,8 +144,8 @@ impl Drain<'_, T, A> { let new_tail_start = tail_start + additional; unsafe { deque.wrap_copy( - deque.to_physical_idx(tail_start), - deque.to_physical_idx(new_tail_start), + deque.to_wrapped_index(tail_start), + deque.to_wrapped_index(new_tail_start), self.tail_len, ); } diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs index dc50cc34d9dac..6566598bc3648 100644 --- a/library/alloc/src/collections/vec_deque/tests.rs +++ b/library/alloc/src/collections/vec_deque/tests.rs @@ -12,7 +12,7 @@ fn bench_push_back_100(b: &mut test::Bencher) { for i in 0..100 { deq.push_back(i); } - deq.head = 0; + deq.head = WrappedIndex::zero(); deq.len = 0; }) } @@ -24,7 +24,7 @@ fn bench_push_front_100(b: &mut test::Bencher) { for i in 0..100 { deq.push_front(i); } - deq.head = 0; + deq.head = WrappedIndex::zero(); deq.len = 0; }) } @@ -38,7 +38,7 @@ fn bench_pop_back_100(b: &mut test::Bencher) { unsafe { deq.ptr().write_bytes(0u8, size + 1) }; b.iter(|| { - deq.head = 0; + deq.head = WrappedIndex::zero(); deq.len = 100; while !deq.is_empty() { test::black_box(deq.pop_back()); @@ -88,7 +88,7 @@ fn bench_pop_front_100(b: &mut test::Bencher) { unsafe { deq.ptr().write_bytes(0u8, size + 1) }; b.iter(|| { - deq.head = 0; + deq.head = WrappedIndex::zero(); deq.len = 100; while !deq.is_empty() { test::black_box(deq.pop_front()); @@ -109,7 +109,9 @@ fn test_swap_front_back_remove() { let expected: VecDeque<_> = if back { (0..len).collect() } else { (0..len).rev().collect() }; for head_pos in 0..usable_cap { - tester.head = head_pos; + unsafe { + tester.head = WrappedIndex::new(head_pos); + } tester.len = 0; if back { for i in 0..len * 2 { @@ -127,7 +129,7 @@ fn test_swap_front_back_remove() { assert_eq!(tester.swap_remove_front(idx), Some(len * 2 - 1 - i)); } } - assert!(tester.head <= tester.capacity()); + assert!(tester.head.as_index() <= tester.capacity()); assert!(tester.len <= tester.capacity()); assert_eq!(tester, expected); } @@ -155,7 +157,9 @@ fn test_insert() { let expected = (0..).take(len).collect::>(); for head_pos in 0..cap { for to_insert in 0..len { - tester.head = head_pos; + unsafe { + tester.head = WrappedIndex::new(head_pos); + } tester.len = 0; for i in 0..len { if i != to_insert { @@ -636,7 +640,9 @@ fn test_remove() { let expected = (0..).take(len).collect::>(); for head_pos in 0..cap { for to_remove in 0..=len { - tester.head = head_pos; + unsafe { + tester.head = WrappedIndex::new(head_pos); + } tester.len = 0; for i in 0..len { if i == to_remove { @@ -666,7 +672,9 @@ fn test_range() { for head in 0..=cap { for start in 0..=len { for end in start..=len { - tester.head = head; + unsafe { + tester.head = WrappedIndex::new(head); + } tester.len = 0; for i in 0..len { tester.push_back(i); @@ -691,7 +699,9 @@ fn test_range_mut() { for head in 0..=cap { for start in 0..=len { for end in start..=len { - tester.head = head; + unsafe { + tester.head = WrappedIndex::new(head); + } tester.len = 0; for i in 0..len { tester.push_back(i); @@ -725,7 +735,9 @@ fn test_drain() { for head in 0..cap { for drain_start in 0..=len { for drain_end in drain_start..=len { - tester.head = head; + unsafe { + tester.head = WrappedIndex::new(head); + } tester.len = 0; for i in 0..len { tester.push_back(i); @@ -782,7 +794,9 @@ fn test_shrink_to() { assert_eq!(deque.capacity(), cap); // we can let the head point anywhere in the buffer since the deque is empty. - deque.head = head; + unsafe { + deque.head = WrappedIndex::new(head); + } deque.extend(1..=len); deque.shrink_to(target_cap); @@ -811,7 +825,9 @@ fn test_shrink_to_fit() { let expected = (0..).take(len).collect::>(); for head_pos in 0..=max_cap { tester.reserve(head_pos); - tester.head = head_pos; + unsafe { + tester.head = WrappedIndex::new(head_pos); + } tester.len = 0; tester.reserve(63); for i in 0..len { @@ -848,7 +864,9 @@ fn test_split_off() { let expected_other = (at..).take(len - at).collect::>(); for head_pos in 0..cap { - tester.head = head_pos; + unsafe { + tester.head = WrappedIndex::new(head_pos); + } tester.len = 0; for i in 0..len { tester.push_back(i); diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index b0b6682f5279e..8957f1d4da61a 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -163,7 +163,13 @@ def display_hint(): class StdVecDequeProvider(printer_base): def __init__(self, valobj): self._valobj = valobj - self._head = int(valobj["head"]) + + head = valobj["head"] + + # BACKCOMPAT: rust 1.95 + if head.type.code != gdb.TYPE_CODE_INT: + head = head[ZERO_FIELD] + self._head = int(head) self._size = int(valobj["len"]) # BACKCOMPAT: rust 1.75 cap = valobj["buf"]["inner"]["cap"] diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 582471622baa6..74b5fd6b132d8 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -987,7 +987,7 @@ def StdSliceSummaryProvider(valobj, dict): class StdVecDequeSyntheticProvider: """Pretty-printer for alloc::collections::vec_deque::VecDeque - struct VecDeque { head: usize, len: usize, buf: RawVec } + struct VecDeque { head: BufferIndex, len: usize, buf: RawVec } """ def __init__(self, valobj: SBValue, _dict: LLDBOpaque): @@ -1016,7 +1016,11 @@ def get_child_at_index(self, index: int) -> SBValue: return element def update(self): - self.head = self.valobj.GetChildMemberWithName("head").GetValueAsUnsigned() + head = self.valobj.GetChildMemberWithName("head") + # BACKCOMPAT: rust 1.95 + if head.GetType().num_fields == 1: + head = head.GetChildAtIndex(0) + self.head = head.GetValueAsUnsigned() self.size = self.valobj.GetChildMemberWithName("len").GetValueAsUnsigned() self.buf = self.valobj.GetChildMemberWithName("buf").GetChildMemberWithName( "inner" diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis index 1528a8b1226ca..dade85dafe738 100644 --- a/src/etc/natvis/liballoc.natvis +++ b/src/etc/natvis/liballoc.natvis @@ -23,7 +23,7 @@ - (($T1*)buf.inner.ptr.pointer.pointer)[(i + head) % buf.inner.cap.__0] + (($T1*)buf.inner.ptr.pointer.pointer)[(i + head.__0) % buf.inner.cap.__0] i = i + 1