Hi !
let mut v: Vec<&str> = Vec::new();
loop {
let data = String::from("Hello, world!");
// Fill the vector with some data bound to the scope of the loop.
v.push(data.as_str());
// Do things with the data.
for s in &v { /* ... */ }
// Clear the vector, ensuring there is no references left in the vector.
v.clear();
}
This obviously does not compile because there is lots of ways for those references to leak outside of the loop. The main one being something panicking, or v.clear()
not being called.
However, it seems reasonable enough to want to reuse the allocation of v
in subsequent iterations of the loop.
This topic basically cover this exact case, but don't really like the solution proposed there.
I think its easier to solve this problem by using something like a VecAlloc
.
struct VecAlloc {
data: NonNull<()>,
capacity: usize,
layout: Layout,
}
impl VecAlloc {
pub fn from_vec<T>(v: Vec<T>) -> Self {
let mut v = ManuallyDrop::new(v);
v.clear();
Self {
data: NonNull::new(v.as_mut_ptr()).unwrap().cast(),
capacity: v.capacity(),
layout: Layout::new::<T>(),
}
}
pub fn into_vec<T>(self) -> Vec<T> {
assert_eq!(Layout::new::<T>(), self.layout);
let this = ManuallyDrop::new(self);
unsafe { Vec::from_raw_parts(this.data.as_ptr().cast(), 0, this.capacity) }
}
}
impl Drop for VecAlloc { /* ... deallocate */ }
// `Option` ensures that if something goes wrong in the loop, there won't be a double-free.
let mut valloc: Option<VecAlloc> = Some(VecAlloc::from_vec(Vec::new()));
loop {
let v = valloc.take().unwrap().into_vec::<&str>();
// Do things
v = Some(VecAlloc::from_vec(v));
}
Is there already a crate to do this? Because I'd rather use something well-tested. Otherwise, does this solution seem sound?