Expand description
§DSTify
This crate enables safe construction of custom dynamically-sized types (DSTs).
Consists of a derive procedural macro that can be applied on any #[repr(C)] struct with dynamically-sized last field.
Structs with both named and unnamed fields (tuple structs) are supported. The last field may be either a slice DST or dyn Trait DST.
§slice DST example
use dstify::Dstify;
#[derive(Dstify, Debug)]
#[repr(C)]
struct FileWithPath {
file: File,
path: Path, // `slice` DST
}
impl FileWithPath {
pub fn open<P: AsRef<Path>>(path: P) -> std::io::Result<Box<Self>> {
let path = path.as_ref();
let file = File::open(path)?;
Ok(FileWithPath::init_unsized(file, path))
}
pub fn path(&self) -> &Path {
&self.path
}
pub fn file(&self) -> &File {
&self.file
}
}
let named_file = FileWithPath::open("Cargo.toml")?;
println!("{named_file:?}");
assert_eq!(size_of_val(&named_file), 16);§dyn Trait DST example
use dstify::Dstify;
use std::{fmt::Debug, io, sync::Arc};
#[derive(Dstify, Debug)]
#[repr(C)]
struct DbgExtra {
line: u64,
column: u64,
dbg: dyn Debug, // `dyn Trait` DST
}
impl DbgExtra {
pub fn new<D: Debug>(line: u64, col: u64, dbg: D) -> Arc<Self> {
// call the method generated by `Dstify` proc macro
Self::init_unsized(line, col, dbg)
}
}
let dbg = DbgExtra::new(10, 27, io::Error::new(io::ErrorKind::Interrupted, ":/"));
println!("{dbg:#?}");The Dstify proc macro in above example generates an impl block for the FileWithPath struct with two “static” methods, init_unsized and init_unsized_checked.
Both of them accept all the struct fields as arguments in definition order. The type of the last one, being a DST, becomes:
- for
sliceDST: a reference - for
dyn TraitDST: an owned value
The return type R, determines the smart pointer type that should be constructed. The bounding trait - SmartPointer, is implemented for Box, Rc and Arc.
The checked method returns LayoutError if the size of the resulting instance would exceed isize::MAX bytes.
The “unchecked” method panics in that case.
impl FileWithPath {
fn init_unsized<R>(file: File, path: &Path) -> R
where
R: dstify::SmartPointer<Self>
{
// ...
}
fn init_unsized_checked<R>(file: File, path: &Path) -> Result<R, LayoutError>
where
R: dstify::SmartPointer<Self>
{
// ...
}
}§Requirements
The type must be a struct. enums and unions are not supported as it’s forbidden to define a dynamically-sized enum or union in current rust.
It must be annotated with #[repr(C)] and the last field must be a DST.
#[derive(Dstify)]
#[repr(C)]
struct Fail2Compile<'a> {
not_dst: &'a [u64], // fails to compile due to last field not being a DST
}// fails to compile due to missing `#[repr(C)]`
#[derive(Dstify)]
struct Fail2Compile {
dst: [u128],
}§Features
- “std” - enabled by default
removing this feature (usingdefault-features = false) enables!#[no_std]support.
Traits§
- Smart
Pointer - Internal trait implemented for smart pointer types that
init_unsizedandinit_unsized_checkedcan return.