dstify 0.2.1

safe construction of custom dynamically-sized types (DSTs)
Documentation
#![cfg_attr(not(feature = "std"), no_std)]

//! # 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
//! ```no_run
//! # #[cfg(feature = "std")]
//! # {
//! # use std::fs::File;
//! # use std::path::Path;
//! 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
//!     }
//! }
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//!
//! let named_file = FileWithPath::open("Cargo.toml")?;
//! println!("{named_file:?}");
//! assert_eq!(size_of_val(&named_file), 16);
//! # Ok(())
//! # }
//! # }
//! ```
//! ### `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 + 'static>(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:#?}");
//! # }
//! ```
//!
//! 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`](`alloc::boxed::Box`), [`Rc`](`alloc::rc::Rc`) and [`Arc`](`alloc::sync::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.
//!
//! ```
//! # use std::{fs::File, path::Path, alloc::LayoutError};
//! # struct FileWithPath { file: File, path: Path }
//! impl FileWithPath {
//!     fn init_unsized<R>(file: File, path: &Path) -> R
//!     where
//!         R: dstify::SmartPointer<Self>
//!     {
//!         // ...
//!         # todo!()
//!     }
//!     fn init_unsized_checked<R>(file: File, path: &Path) -> Result<R, LayoutError>
//!     where
//!         R: dstify::SmartPointer<Self>
//!     {
//!         // ...
//!         # todo!()
//!     }
//! }
//! ```
//! ## 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.
//! ```compile_fail
//! # use dstify::Dstify;
//! #[derive(Dstify)]
//! #[repr(C)]
//! struct Fail2Compile<'a> {
//!     not_dst: &'a [u64], // fails to compile due to last field not being a DST
//! }
//! ```
//! ```compile_fail
//! # use dstify::Dstify;
//! // fails to compile due to missing `#[repr(C)]`
//! #[derive(Dstify)]
//! struct Fail2Compile {
//!     dst: [u128],
//! }
//! ```
//!
//! ## Features
//!
//! - **"std"** - enabled by default  
//!   removing this feature (using `default-features = false`) enables `!#[no_std]` support.

extern crate alloc;

#[doc(hidden)]
pub mod private;

mod smart_pointer;

pub use dstify_derive::Dstify;
pub use smart_pointer::SmartPointer;