Skip to content
/ dstify Public

Rust crate for safe construction of custom dynamically-sized types (DSTs)

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

jsen-/dstify

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DSTify   crate docs

Rust crate for safe construction of custom dynamically-sized types (DSTs). Heavily inspired by slice-dst.

slice DSTs

use dstify::Dstify;
use std::{fs::File, io, path::Path};

#[derive(Dstify, Debug)]
#[repr(C)]
struct FileWithPath {
    file: File,
    path: Path, // `slice` DST
}

impl FileWithPath {
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Box<Self>> {
        let path = path.as_ref();
        let file = File::open(path)?;
        // call the method generated by `Dstify` proc macro
        Ok(FileWithPath::init_unsized(file, path))
    }
    pub fn path(&self) -> &Path {
        &self.path
    }
    pub fn file(&self) -> &File {
        &self.file
    }
}
fn main() {
    let named_file = FileWithPath::open("Cargo.toml").unwrap();
    // type of `named_file` is `Box<FileWithPath>`
    println!("{named_file:?}");
    // reference to `FileWithPath` is a wide (fat) pointer
    assert_eq!(size_of_val(&named_file), 16);
}

dyn Trait DSTs

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)
    }
}
fn main() {
    let dbg = DbgExtra::new(10, 27, io::Error::new(io::ErrorKind::Interrupted, ":/"));
    println!("{dbg:#?}");
}
DbgExtra {
    line: 10,
    column: 27,
    dbg: Custom {
        kind: Interrupted,
        error: ":/",
    },
}

Motivation

In some, arguably niche, use-cases it's more convenient to use a slice instead of a reference. Using a DST doubles the size of a reference from 8 to 16 bytes (on 64-bit platforms), but removes the need for a lifetime annotation and saves one pointer indirection.
Creating a reference (wide/fat pointer) to a built-in type like str or [u8] is easy, but it becomes extremely hard and error-prone once we'd like to store additional fields.

From dynamically sized types in rust nomicon:

Currently the only properly supported way to create a custom DST is by making your type generic and performing an unsizing coercion

Another possiblity is to manually allocate the memory with proper size and alignment and emplace the field values at correct offsets.
That's what is happening behind the curtains of dstify.

About

Rust crate for safe construction of custom dynamically-sized types (DSTs)

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages