Expand description

Using a Bump as a dedicated static pool.

§Usage – Static allocator

Some tasks will be created once during program startup but are not constant expression. The bump allocator allows you to provision static storage for them and then initialize them dynamically. In this way, the caller can also retain precise control over memory locality.

Consider a program that runs a global system, this might be an event loop for tasks, but it has two flavors of implementing this system. One of them might perform energy hungry but fast polling while a more efficient system uses interrupts. You want to let the program’s runtime environment decide which of these systems should be used so they implement a common trait and your program passes around a static dyn-reference.

struct TaskSystemA {
    // …
}

struct TaskSystemB {
    // …
}

trait CommonTrait {
    // …
}

Using a Bump allocator as a pool solves this problem very conveniently without the need for a global allocator. Compared to using the stack, your reference retain the 'static lifetime while compared to a once-cell you retain the uniqueness of the original reference.

use static_alloc::Bump;

union StorageForAOrB {
    variant_a: ManuallyDrop<TaskSystemA>,
    variant_b: ManuallyDrop<TaskSystemB>,
}

static POOL: Bump<StorageForAOrB> = Bump::uninit();

fn main() {
    // Split the pool based on an environment variable.
    let use_b = std::env::var_os("USE_VARIANT_B")
        .map_or(false, |_| true);

    // If we had stack-allocate them we wouldn't have `'static`.
    let used: &'static mut dyn CommonTrait = if use_b {
        POOL.leak(TaskSystemA::default()).unwrap()
    } else {
        POOL.leak(TaskSystemB::default()).unwrap()
    };
}