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
slice
DST: a reference - for
dyn Trait
DST: 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_unsized
andinit_unsized_checked
can return.