From 09097128c39ec7834ce3dac83753e3f6231b76bc Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 25 Sep 2025 17:48:08 +0200 Subject: [PATCH] alloc: fix `Debug` implementation of `ExtractIf` --- library/alloc/src/vec/extract_if.rs | 15 ++++++++++++++- library/alloctests/tests/vec.rs | 11 +++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/vec/extract_if.rs b/library/alloc/src/vec/extract_if.rs index a456d3d9e602d..c0c0060175362 100644 --- a/library/alloc/src/vec/extract_if.rs +++ b/library/alloc/src/vec/extract_if.rs @@ -115,7 +115,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() } } diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index 33a34daccbfd2..ad5e3c5ecd44f 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -1635,6 +1635,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