dyn_struct2
Modification of dyn_struct (GitHub, crates.io) which supports any unsized type, not just slices.
This crate allows you to initialize Dynamically Sized Types (DST) using only safe Rust. It also provides helpes to creates DSTs in unsafe Rust which handle the "gritty" details of alignment and fat pointers.
// Helpers for gritty details
use ;
// Automatic #[derive] proc macro
use ;
Why Dynamic Types?
In Rust, Dynamically Sized Types (DST) are everywhere. Slices ([T]) and trait
objects (dyn Trait) are the most common ones. However, it is also possible
to define your own! For example, this can be done by letting the last field in a
struct be a DST:
This tells the Rust compiler that contents of the DST are laid out in memory right after the other fields, and a pointer to MyDynamicType will be a fat pointer with the same metadata as the DST. This can be very preferable in some cases, since it removes one level of indirection and increases cache-locality.
However, there's a catch! Just as with slices, the compiler does not know how the size of dynamic. Thus, we need what is called a fat-pointer which stores both a pointer to the actual data, but also the size of the DST itself (and additional metadata, e.g. if it's a dyn the vtable). Rust's built-in support for DSTs is lacking, and there are no safe ways to construct these DSTs, as you can't actually pass unsized types to a constructor or function parameter. This crate uses some unsafe behind the scenes to work around the limitations of the language, all wrapped up in a safe interface.
The Derive Macro
The DynStruct macro can be applied to any #[repr(C)] struct that contains a
dynamically sized array as its last field.
Example
use DynStruct;
will produce a single impl-block with a new function. This function accepts all fields in
the same order they were declared. The last field, however, must be a DynArg:
# use DynArg;
#
#
#
Due to the nature of dynamically sized types, the resulting value has to be built on the heap. For safety reasons we currently only allow returning Box, though in a future version we may also allow Rc and Arc. In the meantime it is possible to use Arc::from(MyDynamicType::new(...)).
The DynStruct datatype
DynStruct is a generic type which can take on the shape of any DST which has #[repr(C)]. It consists of a head (which may be a single value or tuple of your statically-sized fields), and a tail (which may be the DST), and is literally just:
The key method in DynStruct is DynStruct::transmute, which allows you to marshal this into any dynamically-sized structure. This is an unsafe but easy way to create safe constructors for your own DSTs:
# use ;
#
#
#
DynArg
DynArg is a wrapper for dynamically-sized types so that you can consume them and pass them as arguments to a function. You create a DynArg with the macro dyn_arg!(arg).
Once you call dyn_arg!(arg), arg is effectively consumed. However it is not dropped unless you pass the dyn_arg to a DynStruct constructor, and then drop the constructed value. If you just ignore the dyn_arg then arg will leak, which is technically safe behavior but be aware.