Rollup merge of #91426 - eggyal:idfunctor-panic-safety, r=lcnr
Make IdFunctor::try_map_id panic-safe Addresses FIXME comment created in #78313 r? ```@lcnr```
This commit is contained in:
commit
7e18b79c77
2 changed files with 30 additions and 24 deletions
|
@ -34,38 +34,43 @@ impl<T> IdFunctor for Vec<T> {
|
||||||
type Inner = T;
|
type Inner = T;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_map_id<F, E>(mut self, mut f: F) -> Result<Self, E>
|
fn try_map_id<F, E>(self, mut f: F) -> Result<Self, E>
|
||||||
where
|
where
|
||||||
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
|
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
|
||||||
{
|
{
|
||||||
// FIXME: We don't really care about panics here and leak
|
struct HoleVec<T> {
|
||||||
// far more than we should, but that should be fine for now.
|
vec: Vec<mem::ManuallyDrop<T>>,
|
||||||
let len = self.len();
|
hole: Option<usize>,
|
||||||
unsafe {
|
}
|
||||||
self.set_len(0);
|
|
||||||
let start = self.as_mut_ptr();
|
|
||||||
for i in 0..len {
|
|
||||||
let p = start.add(i);
|
|
||||||
match f(p.read()) {
|
|
||||||
Ok(val) => p.write(val),
|
|
||||||
Err(err) => {
|
|
||||||
// drop all other elements in self
|
|
||||||
// (current element was "moved" into the call to f)
|
|
||||||
for j in (0..i).chain(i + 1..len) {
|
|
||||||
start.add(j).drop_in_place();
|
|
||||||
}
|
|
||||||
|
|
||||||
// returning will drop self, releasing the allocation
|
impl<T> Drop for HoleVec<T> {
|
||||||
// (len is 0 so elements will not be re-dropped)
|
fn drop(&mut self) {
|
||||||
return Err(err);
|
unsafe {
|
||||||
|
for (index, slot) in self.vec.iter_mut().enumerate() {
|
||||||
|
if self.hole != Some(index) {
|
||||||
|
mem::ManuallyDrop::drop(slot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Even if we encountered an error, set the len back
|
|
||||||
// so we don't leak memory.
|
|
||||||
self.set_len(len);
|
|
||||||
}
|
}
|
||||||
Ok(self)
|
|
||||||
|
unsafe {
|
||||||
|
let (ptr, length, capacity) = self.into_raw_parts();
|
||||||
|
let vec = Vec::from_raw_parts(ptr.cast(), length, capacity);
|
||||||
|
let mut hole_vec = HoleVec { vec, hole: None };
|
||||||
|
|
||||||
|
for (index, slot) in hole_vec.vec.iter_mut().enumerate() {
|
||||||
|
hole_vec.hole = Some(index);
|
||||||
|
let original = mem::ManuallyDrop::take(slot);
|
||||||
|
let mapped = f(original)?;
|
||||||
|
*slot = mem::ManuallyDrop::new(mapped);
|
||||||
|
hole_vec.hole = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem::forget(hole_vec);
|
||||||
|
Ok(Vec::from_raw_parts(ptr, length, capacity))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#![feature(once_cell)]
|
#![feature(once_cell)]
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
#![feature(thread_id_value)]
|
#![feature(thread_id_value)]
|
||||||
|
#![feature(vec_into_raw_parts)]
|
||||||
#![allow(rustc::default_hash_types)]
|
#![allow(rustc::default_hash_types)]
|
||||||
#![deny(unaligned_references)]
|
#![deny(unaligned_references)]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue