[![Crates.io](https://img.shields.io/crates/v/dyn_struct2)](https://crates.io/crates/dyn_struct2) [![docs.rs](https://img.shields.io/docsrs/dyn_struct2)](https://docs.rs/dyn_struct2) # `dyn_struct2` Modification of `dyn_struct` ([GitHub](https://github.com/nolanderc/dyn_struct), [crates.io](https://crates.io/crates/dyn_struct)) 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. ```rust // Helpers for gritty details use dyn_struct2::{DynStruct, dyn_arg}; // Automatic #[derive] proc macro use dyn_struct_derive2::{DynStruct as DynStructDerive}; #[repr(C)] #[derive(DynStructDerive)] struct MyDynamicType { pub awesome: bool, pub number: u32, pub dynamic: [u32], } fn example() { let data = [4, 5, 6, 7]; // the `new` function is generated by the `DynStruct` macro. let foo: Box = MyDynamicType::new(true, 123, dyn_arg!(data)); assert_eq!(foo.awesome, true); assert_eq!(foo.number, 123); assert_eq!(&foo.dynamic, &[4, 5, 6, 7]); // You can also create values unsafely to generate your own constructors, or if you don't like proc macros let data2 = [7, 8, 9]; let foo2 = DynStruct::<(bool, u32), [u32]>::new((false, 456), dyn_arg!(data2)); let foo2 = unsafe { foo2.transmute::() }; assert_eq!(foo2.awesome, false); assert_eq!(foo2.number, 456); assert_eq!(&foo2.dynamic, &[7, 8, 9]); } ``` ## 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: ```rust struct MyDynamicType { awesome: bool, number: u32, dynamic: [u32], } ``` 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 ```rust #![cfg(feature = "derive")] use dyn_struct2::DynStruct; #[repr(C)] #[derive(DynStruct)] struct MyDynamicType { pub awesome: bool, pub number: u32, pub dynamic: [u32], } ``` 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`: ```rust # use dyn_struct2::DynArg; # # #[repr(C)] # struct MyDynamicType { # pub awesome: bool, # pub number: u32, # pub dynamic: [u32], # } impl MyDynamicType { pub fn new(awesome: bool, number: u32, dynamic: DynArg<[u32]>) -> Box { // ... implementation details ... todo!() } } ``` 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: ```rust #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct DynStruct { pub header: Header, pub tail: Tail } ``` 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: ```rust # use dyn_struct2::{DynStruct, DynArg}; # # #[repr(C)] # struct MyDynamicType { # pub awesome: bool, # pub number: u32, # pub dynamic: [u32], # } impl MyDynamicType { pub fn new(awesome: bool, number: u32, dynamic: DynArg<[u32]>) -> Box { // This is the actual generated body of MyDynamicType if you use #[derive(DynStruct)]! let dyn_struct = DynStruct::new((awesome, number), dynamic); unsafe { dyn_struct.transmute() } } } ``` ## `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.