Rollup merge of #147035 - joboet:extract_if_debug, r=tgross35

alloc: fix `Debug` implementation of `ExtractIf`

I noticed this while reviewing rust-lang/rust#141032. Calling `get` on the inner `Vec` never returns `Some` as the `Vec`'s length is temporarily set to zero while the `ExtractIf` exists.
This commit is contained in:
Matthias Krüger 2025-11-20 11:15:50 +01:00 committed by GitHub
commit cd4ce66e50
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 25 additions and 1 deletions

View file

@ -130,7 +130,20 @@ where
A: Allocator,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let peek = if self.idx < self.end { self.vec.get(self.idx) } else { None };
let peek = if self.idx < self.end {
// 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.
//
// SAFETY:
// Since `self.idx` is smaller than `self.end` and `self.end` is
// 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.as_ptr().add(self.idx) })
} else {
None
};
f.debug_struct("ExtractIf").field("peek", &peek).finish_non_exhaustive()
}
}

View file

@ -1650,6 +1650,17 @@ fn extract_if_unconsumed() {
assert_eq!(vec, [1, 2, 3, 4]);
}
#[test]
fn extract_if_debug() {
let mut vec = vec![1, 2];
let mut drain = vec.extract_if(.., |&mut x| x % 2 != 0);
assert!(format!("{drain:?}").contains("Some(1)"));
drain.next();
assert!(format!("{drain:?}").contains("Some(2)"));
drain.next();
assert!(format!("{drain:?}").contains("None"));
}
#[test]
fn test_reserve_exact() {
// This is all the same as test_reserve