From c54b8d752c89d38d9d3d27d385bd4127e3b43470 Mon Sep 17 00:00:00 2001 From: nullstalgia Date: Mon, 8 Jun 2026 20:18:00 -0700 Subject: [PATCH 1/4] Modify Deque::truncate to closer match the new Deque::retain_back implementation --- CHANGELOG.md | 1 + src/deque.rs | 104 ++++++++++++++++++++++++++++----------------------- 2 files changed, 58 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index caa938303f..5d8c46af79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - Added `resize_with` to `Vec` +- Modify `Deque::truncate` to closer match the new `Deque::retain_back` implementation ## [v0.9.3] 2025-04-15 diff --git a/src/deque.rs b/src/deque.rs index 49c689f24f..ec964615ec 100644 --- a/src/deque.rs +++ b/src/deque.rs @@ -895,59 +895,69 @@ impl + ?Sized> DequeInner { /// assert_eq!(buf.make_contiguous(), [5]); /// ``` pub fn truncate(&mut self, len: usize) { - /// Runs the destructor for all items in the slice when it gets dropped (gracefully or - /// during unwinding). - struct Dropper<'a, T>(&'a mut [T]); - - impl<'a, T> Drop for Dropper<'a, T> { - fn drop(&mut self) { - unsafe { - ptr::drop_in_place(self.0); + // If new desired length is greater or equal, we don't need to act. + if len >= self.storage_len() { + return; + } + + let (front, back) = self.as_mut_slices(); + + // If `len` desires to keep elements past front's entire length, + // then only back's contents will need to be dropped + // as the two slices combined should be more than `len`. + if len > front.len() { + let begin = len - front.len(); + + // Safety: `begin` is always < `back.len()` by the above conditional. + let drop_back = core::ptr::from_mut(unsafe { back.get_unchecked_mut(begin..) }); + + // Self::to_physical_index returns the index `len` units _after_ the front cursor, + // meaning we can use it to find the decremented index for `back` for non-contiguous + // deques, as well as determine where the new "cap" for front needs + // to be placed for contiguous deques. + self.back = self.to_physical_index(len); + self.full = false; + + // Safety: Any slice passed to `drop_in_place` is valid: + // * Only valid elements previously contained within `back` are present. + // * The elements are valid for reading/writing, originating from a &mut [T]. + // * Deque back cursor is moved before calling `drop_in_place`, so no value is + // dropped twice if `drop_in_place` panics. + unsafe { ptr::drop_in_place(drop_back) } + } else { + /// Runs the destructor for all items in the slice when it gets dropped (gracefully or + /// during unwinding). + struct Dropper<'a, T>(&'a mut [T]); + impl<'a, T> Drop for Dropper<'a, T> { + fn drop(&mut self) { + unsafe { + // Safety: + // The slice given to the Dropper should only contain elements + // that have been truncated by the movement of the front cursor. + ptr::drop_in_place(self.0); + } } } - } - // Safety: - // * Any slice passed to `drop_in_place` is valid; the second case has `len <= front.len()` - // and returning on `len > self.storage_len()` ensures `begin <= back.len()` in the first - // case - // * Deque front/back cursors are moved before calling `drop_in_place`, so no value is - // dropped twice if `drop_in_place` panics - unsafe { - // If new desired length is greater or equal, we don't need to act. - if len >= self.storage_len() { - return; - } - - let (front, back) = self.as_mut_slices(); - - // If `len` desires to keep elements past front's entire length, - // then only back's contents will need to be dropped - // as the two slices combined should be more than `len`. - if len > front.len() { - let begin = len - front.len(); - let drop_back = core::ptr::from_mut(back.get_unchecked_mut(begin..)); + // As `len` is <= `front.len()`, we know all of `back` needs to be dropped, + // since the desired length never reaches into it. + let drop_back = core::ptr::from_mut(back); - // Self::to_physical_index returns the index `len` units _after_ the front cursor, - // meaning we can use it to find the decremented index for `back` for non-contiguous - // deques, as well as determine where the new "cap" for front needs - // to be placed for contiguous deques. - self.back = self.to_physical_index(len); - self.full = false; + // Safety: `len` is always less than or equal to `front.len()` by the above conditional. + let drop_front = core::ptr::from_mut(unsafe { front.get_unchecked_mut(len..) }); - ptr::drop_in_place(drop_back); - } else { - // Otherwise, we know back's entire contents need to be dropped, - // since the desired length never reaches into it. - let drop_back = core::ptr::from_mut(back); - let drop_front = core::ptr::from_mut(front.get_unchecked_mut(len..)); - - self.back = self.to_physical_index(len); - self.full = false; + // Determine new "cap" for `front`, + // shortening it to be equal to `len` elements. + self.back = self.to_physical_index(len); + self.full = false; - // If `drop_front` causes a panic, the Dropper will still be called to drop it's - // slice during unwinding. In either case, front will always be - // dropped before back. + // Safety: + // * If `drop_front` causes a panic, the Dropper will still be called to drop its + // slice during unwinding. In either case, front will always be + // dropped before back. + // * Deque back cursor is moved before calling `drop_in_place`, so no value is + // dropped twice if either `drop_in_place` panics. + unsafe { let _back_dropper = Dropper(&mut *drop_back); ptr::drop_in_place(drop_front); } From 0315f1272bed28215e73388511119d53e4ff7a14 Mon Sep 17 00:00:00 2001 From: nullstalgia Date: Mon, 8 Jun 2026 20:22:05 -0700 Subject: [PATCH 2/4] Fix cargo fmt being unhappy with changes to Deque::truncate --- src/deque.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/deque.rs b/src/deque.rs index ec964615ec..4d2273a66d 100644 --- a/src/deque.rs +++ b/src/deque.rs @@ -921,8 +921,8 @@ impl + ?Sized> DequeInner { // Safety: Any slice passed to `drop_in_place` is valid: // * Only valid elements previously contained within `back` are present. // * The elements are valid for reading/writing, originating from a &mut [T]. - // * Deque back cursor is moved before calling `drop_in_place`, so no value is - // dropped twice if `drop_in_place` panics. + // * Deque back cursor is moved before calling `drop_in_place`, so no value is dropped + // twice if `drop_in_place` panics. unsafe { ptr::drop_in_place(drop_back) } } else { /// Runs the destructor for all items in the slice when it gets dropped (gracefully or @@ -952,11 +952,10 @@ impl + ?Sized> DequeInner { self.full = false; // Safety: - // * If `drop_front` causes a panic, the Dropper will still be called to drop its - // slice during unwinding. In either case, front will always be - // dropped before back. - // * Deque back cursor is moved before calling `drop_in_place`, so no value is - // dropped twice if either `drop_in_place` panics. + // * If `drop_front` causes a panic, the Dropper will still be called to drop its slice + // during unwinding. In either case, front will always be dropped before back. + // * Deque back cursor is moved before calling `drop_in_place`, so no value is dropped + // twice if either `drop_in_place` panics. unsafe { let _back_dropper = Dropper(&mut *drop_back); ptr::drop_in_place(drop_front); From c931aabfd8b66260a9e09de87045a3a7d4111283 Mon Sep 17 00:00:00 2001 From: nullstalgia Date: Tue, 9 Jun 2026 09:16:08 -0700 Subject: [PATCH 3/4] Remove extraneous Changelog entry --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d8c46af79..caa938303f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - Added `resize_with` to `Vec` -- Modify `Deque::truncate` to closer match the new `Deque::retain_back` implementation ## [v0.9.3] 2025-04-15 From b93bc5bc7ef48bff7359427a79def630b7fbf0c4 Mon Sep 17 00:00:00 2001 From: nullstalgia Date: Tue, 9 Jun 2026 09:28:34 -0700 Subject: [PATCH 4/4] Remove println! from Deque::truncate unit test --- src/deque.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deque.rs b/src/deque.rs index 4d2273a66d..874fbb7907 100644 --- a/src/deque.rs +++ b/src/deque.rs @@ -2164,7 +2164,7 @@ mod tests { // Truncating past the elements present, no change. tester.truncate(10); assert_eq!(tester.as_slices(), (&[3, 2, 1][..], &[1, 2, 3][..])); - println!("{} {}", tester.front, tester.back); + // Truncating equal to elements present, no change. tester.truncate(6); assert_eq!(tester.as_slices(), (&[3, 2, 1][..], &[1, 2, 3][..]));