1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! # 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;
pub use Dstify;
pub use SmartPointer;