Expand description
§Overview
This crate allows saving DST objects in the provided buffer.
In this way, it allows users to create global dynamic objects on a no_std
environment without a global allocator.
Imagine that you want to create a generic embedded logger which can be used for
any board regardless of its hardware details. But you cannot just declare
a static variable that implements some trait because the compiler doesn’t know how
much memory should be used to allocate it. In such cases, you have to use trait objects
to erase the origin type. You might use the alloc::boxed::Box
to do this thing, but it depends on the global allocator, which you also should provide,
and there are a lot of caveats not to use heap on the embedded devices.
Instead of using a global allocator, you can use this crate to store dynamic objects in the static memory.
§Examples
use static_box::Box;
struct Uart1Rx {
// Implementation details...
}
impl SerialWrite for Uart1Rx {
fn write(&mut self, _byte: u8) {
// Implementation details
}
}
let rx = Uart1Rx { /* ... */ };
let mut mem = [0_u8; 32];
let mut writer = Box::<dyn SerialWrite>::new(&mut mem, rx);
writer.write_str("Hello world!");
A more complex example demonstrating the usage of an external buffer.
use core::fmt::Display;
use static_box::Box;
let mut mem = [0_u8; 64];
let value = 42_u64;
// Calculate the amount of memory needed to store this object.
let total_len = {
let layout = Box::<dyn Display>::layout_of_dyn(&value);
let align_offset = mem.as_ptr().align_offset(layout.align());
layout.size() + align_offset
};
let (head, _tail) = mem.split_at_mut(total_len);
let val: Box<dyn Display> = Box::new(head, value);
assert_eq!(val.to_string(), "42");
§Limitations
At the moment this crate can only store dynamic objects, but it’s hard to imagine use cases where there is a need to store sized objects in this box.
§Minimum Supported rustc
Version
This crate uses the following unstable features:
In other words, the crate’s supported nightly rustc
version is 1.53.0
, but there
is no guarantee that this code will work fine on the newest versions.
§Implementation details
This crate uses unsafe code!
This crate inspired by the thin_box
example in the rustc
tests repository.
This implementation relies on that the type V
can be coerced into the unsized dyn T
,
see the Unsize
trait documentation.
From the coerced dyn T
it gets a pointer to metadata, which contains all the necessary
information to manipulate the concrete type stored inside a trait object. After that it copies
metadata and the origin value into the provided buffer.
Thus, to get the pointer to the dyn T
, you have to read the metadata given the memory alignment,
use them to calculate the memory layout of the object, and only after that collect this
all into the pointer. So, keep in mind that getting a reference to the stored dyn T
could be too
expensive in some cases.
Structs§
- Box
- A box that uses the provided memory to store dynamic objects.