Expand description
§Safe runtime stack allocations
Provides methods for Rust to access and use runtime stack allocated buffers in a safe way.
This is accomplished through a helper function that takes a closure of FnOnce
that takes the stack allocated buffer slice as a parameter.
The slice is considered to be valid only until this closure returns, at which point the stack is reverted back to the caller of the helper function. If you need a buffer that can be moved, use Vec
or statically sized arrays.
The memory is allocated on the closure’s caller’s stack frame, and is deallocated when the caller returns.
This slice will be properly formed with regards to the expectations safe Rust has on slices. However, it is still possible to cause a stack overflow by allocating too much memory, so use this sparingly and never allocate unchecked amounts of stack memory blindly.
§Examples
Allocating a byte buffer on the stack.
fn copy_with_buffer<R: Read, W: Write>(mut from: R, mut to: W, bufsize: usize) -> io::Result<usize>
{
alloca_zeroed(bufsize, move |buf| -> io::Result<usize> {
let mut read;
let mut completed = 0;
while { read = from.read(&mut buf[..])?; read != 0} {
to.write_all(&buf[..read])?;
completed += read;
}
Ok(completed)
})
}
§Arbitrary types
Allocating a slice of any type on the stack.
stackalloc(5, "str", |slice: &mut [&str]| {
assert_eq!(&slice[..], &["str"; 5]);
});
§Dropping
The wrapper handles dropping of types that require it.
stackalloc_with(5, || vec![String::from("string"); 10], |slice| {
assert_eq!(&slice[0][0][..], "string");
}); // The slice's elements will be dropped here
§MaybeUninit
You can get the aligned stack memory directly with no initialisation.
stackalloc_uninit(5, |slice| {
for s in slice.iter_mut()
{
*s = MaybeUninit::new(String::new());
}
// SAFETY: We have just initialised all elements of the slice.
let slice = unsafe { stackalloc::helpers::slice_assume_init_mut(slice) };
assert_eq!(&slice[..], &vec![String::new(); 5][..]);
// SAFETY: We have to manually drop the slice in place to ensure its elements are dropped, as `stackalloc_uninit` does not attempt to drop the potentially uninitialised elements.
unsafe {
std::ptr::drop_in_place(slice as *mut [String]);
}
});
§Performance
For small (1k or lower) element arrays stackalloc
can outperform Vec
by about 50% or more. This performance difference decreases are the amount of memory allocated grows.
- test tests::bench::stackalloc_of_uninit_bytes_known … bench: 3 ns/iter (+/- 0)
- test tests::bench::stackalloc_of_uninit_bytes_unknown … bench: 3 ns/iter (+/- 0)
- test tests::bench::stackalloc_of_zeroed_bytes_known … bench: 22 ns/iter (+/- 0)
- test tests::bench::stackalloc_of_zeroed_bytes_unknown … bench: 17 ns/iter (+/- 0)
- test tests::bench::vec_of_uninit_bytes_known … bench: 13 ns/iter (+/- 0)
- test tests::bench::vec_of_uninit_bytes_unknown … bench: 55 ns/iter (+/- 0)
- test tests::bench::vec_of_zeroed_bytes_known … bench: 36 ns/iter (+/- 2)
- test tests::bench::vec_of_zeroed_bytes_unknown … bench: 37 ns/iter (+/- 0)
§License
MIT licensed
Re-exports§
pub use avec::AVec;
Modules§
- avec
- A
Vec
-like wrapper type that only allocates if a provided buffer is first exhausted. - helpers
- A module of helper functions for slice memory manipulation
Functions§
- alloca
- Allocate a runtime length uninitialised byte buffer on the stack, call
callback
with this buffer, and then deallocate the buffer. - alloca_
zeroed - Allocate a runtime length zeroed byte buffer on the stack, call
callback
with this buffer, and then deallocate the buffer. - stackalloc
- Allocate a runtime length slice of
T
on the stack, fill it by cloninginit
, callcallback
with this buffer, and then drop and deallocate the buffer. - stackalloc_
from_ iter_ exact - Collect an exact size iterator into a stack allocated slice, call
callback
with this buffer, and then drop and deallocate the buffer. - stackalloc_
from_ ⚠iter_ trusted - Collect an iterator into a stack allocated buffer, call
callback
with this buffer, and then drop and deallocate the buffer. - stackalloc_
uninit - Allocate a runtime length slice of uninitialised
T
on the stack, callcallback
with this buffer, and then deallocate the buffer. - stackalloc_
with - Allocate a runtime length slice of
T
on the stack, fill it by callinginit_with
, callcallback
with this buffer, and then drop and deallocate the buffer. - stackalloc_
with_ default - Allocate a runtime length slice of
T
on the stack, fill it by callingT::default()
, callcallback
with this buffer, and then drop and deallocate the buffer. - stackalloc_
with_ iter - Collect an iterator into a stack allocated buffer up to
size
elements, callcallback
with this buffer, and then drop and deallocate the buffer.