Expand description
§VecStorage
Struct to re-use the storage of a vector for borrowing values with different lifetimes.
§Examples
The following code does not compile:
let mut v = Vec::with_capacity(2);
{
let x = 1; let y = 2;
v.push(&x);
v.push(&y);
v.clear(); // We stop borrowing here, but the compiler doesn't know that.
}
{
let a = 1; let b = 2;
v.push(&a);
v.push(&b);
v.clear(); // We stop borrowing here, but the compiler doesn't know that.
}
You can use VecStorage
to solve this problem:
use vecstorage::VecStorage;
let mut v = VecStorage::<&'static u32>::with_capacity(2);
{
let x = 1; let y = 2;
let mut guard = v.vec_guard();
// `guard` behaves like a `Vec<&'_ u32>` that can be used to store `&x`.
guard.push(&x); // No memory allocation here, we use the memory allocated in `v`.
guard.push(&y);
// If we were going to push more items on the guard, we would allocate memory.
// When guard goes out of scope, it is cleared.
}
{
let a = 1; let b = 2;
let mut guard = v.vec_guard();
// Now guard behaves like a vector.
// The memory from the previous run has been cleared ...
assert_eq!(guard.len(), 0);
// ... but the memeroy has been reused.
assert_eq!(guard.capacity(), 2);
guard.push(&a);
guard.push(&b);
}
The VecStorage
re-uses the same memory each time:
use vecstorage::VecStorage;
let mut v = VecStorage::<&'static u32>::with_capacity(2);
let capacity;
{
let x = 1; let y = 2; let z = 3;
let mut guard = v.vec_guard();
guard.push(&x); // No memory allocation here, we use the memory allocated in `v`.
guard.push(&y);
// Let's push some more items on the guard and allocate memory:
guard.push(&z);
capacity = guard.capacity();
assert!(capacity > 2);
}
{
let mut guard = v.vec_guard::<&u32>();
// The memory from the previous run has been cleared ...
assert_eq!(guard.len(), 0);
// ... but the capacity is kept:
assert_eq!(capacity, guard.capacity());
}
The following example illustrates the typical usage of VecStorage
.
use vecstorage::VecStorage;
struct WithLifetime<'a> {
reference: &'a ()
}
struct MyStruct {
storage: VecStorage<WithLifetime<'static>>
}
impl MyStruct {
fn with_capacity(capacity: usize) -> Self {
Self {
storage: VecStorage::with_capacity(capacity)
}
}
fn apply_from_iterator<'a, I, F>(&mut self, iterator: I, f: F)
where I: Iterator<Item = WithLifetime<'a>>, F: Fn(&[WithLifetime<'a>]) {
let mut guard = self.storage.vec_guard();
for item in iterator {
guard.push(item)
}
f(guard.as_slice());
}
}
VecStorage<T>
allocates memory just like Vec<T>
.
Typically, T
is chosen to have a 'static
lifetime, but you actually want a
a Vec<TGuard>
, where TGuard
is another data type that does not have a 'static
lifetime.
If the types T
and TGuard
have the same size and alignment, you can use
the VecStorage<T>
to create a VecGuard<TGuard>
with the [vec_guard<'_, TGuard>()
] method.
The VecGuard
uses the memory from the VecStorage
and can temporarily
be used just like a Vec<TGuard>
(i.e.: it implements Deref<Target=Vec<TGuard>>
and DerefMut<Target=Vec<TGuard>>
).
When the VecGuard
is dropped, the vector is cleared, but
the memory “goes back to the VecStorage
” and
can be re-used later on to store references with a different lifetime.
Structs§
- VecGuard
- This can be used as a vector of
T
(Vec<T>
). - VecStorage
- Re-usable memory for creating a vector of references.