Skip to content

Commit f6f8aa5

Browse files
committed
Don't panic in VecInner::extend and return a Result
Other methods for extending VecInner already return results instead of panicking. In case of VecInner::extend, avoiding a panic by checking that the actual amount of elements to extend with fits beforehand is not generally possible. So attempt to add the elements from the iterator and restore the original length in case of an error.
1 parent 45a1f11 commit f6f8aa5

File tree

3 files changed

+36
-12
lines changed

3 files changed

+36
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99
- Added `from_bytes_truncating_at_nul` to `CString`
1010
- Added `CString::{into_bytes, into_bytes_with_nul, into_string}`
1111
- Added `pop_front_if` and `pop_back_if` to `Deque`
12+
- Replace panicking in `VecInner::extend` with returning a `Result`.
1213

1314
## [v0.9.2] 2025-11-12
1415

src/linear_map.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,9 @@ where
586586
I: IntoIterator<Item = (K, V)>,
587587
{
588588
let mut out = Self::new();
589-
out.buffer.extend(iter);
589+
out.buffer
590+
.extend(iter)
591+
.expect("LinearMap::from_iter overflow");
590592
out
591593
}
592594
}

src/vec/mod.rs

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -621,17 +621,21 @@ impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> VecInner<T, LenT, S> {
621621
}
622622

623623
/// Extends the vec from an iterator.
624-
///
625-
/// # Panic
626-
///
627-
/// Panics if the vec cannot hold all elements of the iterator.
628-
pub fn extend<I>(&mut self, iter: I)
624+
pub fn extend<I>(&mut self, iter: I) -> Result<(), CapacityError>
629625
where
630626
I: IntoIterator<Item = T>,
631627
{
632-
for elem in iter {
633-
self.push(elem).ok().unwrap();
634-
}
628+
// Save current length to restore it later in case of an error.
629+
let len = self.len();
630+
631+
iter.into_iter()
632+
.try_for_each(|elem| self.push(elem))
633+
.map_err(|_| {
634+
// SAFETY: This is the length from before pushing elements for extending this
635+
// vector.
636+
unsafe { self.set_len(len) };
637+
CapacityError
638+
})
635639
}
636640

637641
/// Clones and appends all elements in a slice to the `Vec`.
@@ -1404,7 +1408,7 @@ impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> Extend<T> for VecInner<T, LenT
14041408
where
14051409
I: IntoIterator<Item = T>,
14061410
{
1407-
self.extend(iter);
1411+
self.extend(iter).expect("VecInner::extend overflow");
14081412
}
14091413
}
14101414

@@ -1416,7 +1420,8 @@ where
14161420
where
14171421
I: IntoIterator<Item = &'a T>,
14181422
{
1419-
self.extend(iter.into_iter().cloned());
1423+
self.extend(iter.into_iter().cloned())
1424+
.expect("Vec::extend overflow");
14201425
}
14211426
}
14221427

@@ -1808,7 +1813,7 @@ mod tests {
18081813

18091814
use static_assertions::assert_not_impl_any;
18101815

1811-
use super::{Vec, VecView};
1816+
use super::{CapacityError, Vec, VecView};
18121817

18131818
// Ensure a `Vec` containing `!Send` values stays `!Send` itself.
18141819
assert_not_impl_any!(Vec<*const (), 4>: Send);
@@ -2119,6 +2124,22 @@ mod tests {
21192124
assert_eq!(v.len(), 0);
21202125
}
21212126

2127+
#[test]
2128+
fn extend_size_limit() {
2129+
let mut v: Vec<u8, 4> = Vec::new();
2130+
assert!(v.extend(core::iter::empty()).is_ok());
2131+
assert!(v.is_empty());
2132+
2133+
assert!(v.extend(core::iter::repeat_n(42, 2)).is_ok());
2134+
assert_eq!(&v, &[42, 42]);
2135+
2136+
matches!(v.extend(core::iter::repeat_n(0, 3)), Err(CapacityError));
2137+
assert_eq!(&v, &[42, 42]);
2138+
2139+
assert!(v.extend(core::iter::repeat_n(0, 2)).is_ok());
2140+
assert_eq!(&v, &[42, 42, 0, 0]);
2141+
}
2142+
21222143
#[test]
21232144
fn resize_size_limit() {
21242145
let mut v: Vec<u8, 4> = Vec::new();

0 commit comments

Comments
 (0)