Crate slimbox

Source
Expand description

SlimBox is a thin pointer type for heap allocation; by storing metadata (either a full pointer, or just the metadata when the nightly feature is enabled) together with the value in the same allocation, it allows you to box a DST (i.e. a slice or a trait object) while only using one machine word’s worth of space. Additionally, the SlimRef and SlimMut types provide the equivalent of shared and exclusive references to the contents of a SlimBox, while also being the size of a thin pointer.

A convenient slimbox_unsize! macro is provided, to construct a SlimBox<T> from a value of type S that can be unsized to T. By enabling the nightly feature (requiring a nightly compiler) or the unsafe_stable feature, the SlimBox::from_box conversion function is also made available, to convert from a preexisting Box<T> into a SlimBox<T>.

The use of the unsafe_stable feature does rely on something that could potentially become false in the future, leading to UB; namely, the fact that a fat pointer contains a thin pointer at offset 0. This does seem to be the case now, and it’s probably going to stay like this in the future, but for additional peace of mind it is recommended to just construct the SlimBox out of the original Sized value in the first place.

The three types are FFI-compatible and null-optimized, so you can declare extern "C" functions that deal in SlimBox, SlimRef and SlimMut or Options of those while only declaring opaque pointers to the foreign side.

trait Frob {
    fn foo(&self) -> i32;
}

// void *frob_new(int32_t p);
#[no_mangle]
extern "C" fn frob_new(p: i32) -> Option<SlimBox<dyn Frob>> {
    if p == 0 {
        None
    } else if p % 2 == 0 {
        Some(slimbox_unsize!(A(p / 2)))
    } else {
        Some(slimbox_unsize!(B(p)))
    }
}

// int32_t frob_foo(const void *f);
#[no_mangle]
extern "C" fn frob_foo(f: SlimRef<'_, dyn Frob>) -> i32 {
    f.foo()
}

// void frob_free(void *f);
#[no_mangle]
extern "C" fn frob_free(f: Option<SlimBox<dyn Frob>>) {}

Macros§

slimbox_unsize
slimbox_unsize!(T, expression) will unsize expression into a SlimBox<T>. The T parameter can be omitted if it can be inferred.

Structs§

SlimBox
A thin owned pointer; like Box<T> but guaranteed to be as big as a regular pointer, even for !Sized types.
SlimMut
A thin exclusive reference; like &mut T but guaranteed to be as big as a regular pointer, even for !Sized types. It will typically refer to a value owned by a SlimBox, but it can also refer to a stack-allocated Slimmable via from_slimmable.
SlimRef
A thin shared reference; like &T but guaranteed to be as big as a regular pointer, even for !Sized types. It will typically refer to a value owned by a SlimBox, but it can also refer to a stack-allocated Slimmable via from_slimmable.
Slimmable
A container for a value that can also hold enough information to be able to reconstruct a (potentially-wide) pointer to itself from a thin pointer to itself. The internal container type used by SlimBox.