Crate static_box[][src]

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 writer = Box::<dyn SerialWrite, [u8; 32]>::new(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, &mut [u8]>::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_in_buf(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.