light_zero_copy_derive/lib.rs
1//! Procedural macros for borsh compatible zero copy serialization.
2//!
3//!
4//!
5//! ## Main Macros
6//!
7//! - `ZeroCopy`: Derives ZeroCopyAt
8//! - `ZeroCopyMut`: Derives ZeroCopyAtMut, ZeroCopyNew
9//! - `ZeroCopyEq`: Derives PartialEq for <StructName>::ZeroCopy == StructName
10//!
11//!
12//! ## Macro Rules
13//! 1. Create zero copy structs Z<StructName> for the struct
14//! 1.1. The first consecutive fixed-size fields are extracted into a meta struct Z<StructName>Meta
15//! 1.2. Meta extraction stops at first Vec, non-optimized Option (i.e., non-u16/u32/u64 Options), or non-Copy type
16//! 1.3. Primitive types are converted to little-endian equivalents (u16→U16, u32→U32, u64→U64, bool→u8)
17//! 1.4. Fields after meta are included directly in the Z-struct and deserialized sequentially
18//! 1.5. Vec<u8> uses optimized slice operations, other Vec<T> types use ZeroCopySlice
19//! 1.6. Option<u64/u32/u16> are optimized, other Option<T> delegate to T's ZeroCopyAt
20//! 1.7. Non-Copy types must implement ZeroCopyAt trait
21//!
22//! ## Supported Types
23//!
24//! ### Primitives
25//! - **Unsigned integers**: u8, u16, u32, u64
26//! - **Signed integers**: i8, i16, i32, i64
27//! - **Boolean**: bool
28//!
29//! ### Collections
30//! - Vec<T> where T is a supported type
31//! - Arrays [T; N] where T is a supported type
32//! - Option<T> where T is a supported type (optimized for u16/u32/u64)
33//!
34//! ### Custom Types
35//! - Any type that implements ZeroCopyAt trait
36//! - Nested structs with #[derive(ZeroCopy)]
37//! - Enums with unit variants or single unnamed field variants
38//!
39//! ## Limitations
40//!
41//! ### Type Support
42//! - **usize/isize**: Platform-dependent size types are not supported for cross-platform consistency
43//! - **f32/f64**: Floating point types are not supported
44//! - **char**: Character type is not supported
45//!
46//! ### Structural Limitations
47//! - **Tuple structs**: Not supported - only structs with named fields are allowed
48//! - **Empty structs**: Not supported - structs must have at least one field for zero-copy serialization
49//! - **Enum support**:
50//! - `ZeroCopy` supports enums with unit variants or single unnamed field variants
51//! - `ZeroCopyMut` does NOT support enums
52//! - `ZeroCopyEq` does NOT support enums
53//! - `ZeroCopyEq` does NOT support enums, vectors, arrays)
54//!
55//! ### Special Type Handling
56//! - **Arrays in Vec**: `Vec<[T; N]>` is supported. Arrays are Copy types that don't implement
57//! the `ZeroCopyStructInner` trait, so they are handled directly after type conversion
58//! (e.g., `[u32; N]` → `[U32; N]`) rather than through the trait's associated type.
59//! - **Primitive type conversion**: Integer types are automatically converted to their
60//! aligned equivalents for zero-copy safety (e.g., `u32` → `U32`, `i64` → `I64`)
61//!
62//! ### Requirements
63//! - All structs and enums must have `#[repr(C)]` attribute for memory layout safety
64//! - Fields must implement appropriate traits (Copy for meta fields, ZeroCopyAt for others)
65//! Examples:
66//! ```rust, ignore
67//! use light_zero_copy::slice::ZeroCopySliceBorsh;
68//! use light_zero_copy::slice_mut::ZeroCopySliceMutBorsh;
69//!
70//! pub struct Struct1 {
71//! a: Vec<u8>,
72//! }
73//!
74//! pub struct ZStruct1<'a> {
75//! a: &'a [u8]
76//! }
77//! pub struct ZStruct1Mut<'a> {
78//! a: &'a mut [u8]
79//! }
80//!
81//! pub struct Struct2 {
82//! a: Vec<u64>,
83//! }
84//!
85//! pub struct ZStruct2<'a> {
86//! a: ZeroCopySliceBorsh<'a, u64>,
87//! }
88//! pub struct ZStruct2Mut<'a> {
89//! a: ZeroCopySliceMutBorsh<'a, u64>,
90//! }
91//! ```
92//! 2. Implement ZeroCopyAt trait which returns Z<StructName>
93//! 3. ZeroCopyMut (separate derive) adds:
94//! 3.1. Mutable variants with 'Mut' suffix (Z<StructName>Mut, Z<StructName>MetaMut)
95//! 3.2. ZeroCopyAtMut trait implementation
96//! 3.3. ZeroCopyNew trait with configuration struct for dynamic field initialization
97
98use proc_macro::TokenStream;
99
100mod shared;
101mod zero_copy;
102mod zero_copy_eq;
103#[cfg(feature = "mut")]
104mod zero_copy_mut;
105
106#[cfg(test)]
107mod tests;
108
109/// ZeroCopy derivation macro for zero-copy deserialization
110///
111/// # Usage
112///
113/// Basic usage:
114/// ```rust, ignore
115/// use light_zero_copy_derive::ZeroCopy;
116/// #[derive(ZeroCopy)]
117/// #[repr(C)]
118/// pub struct MyStruct {
119/// pub a: u8,
120/// }
121/// ```
122///
123/// To derive PartialEq as well, use ZeroCopyEq in addition to ZeroCopy:
124/// ```rust, ignore
125/// use light_zero_copy_derive::{ZeroCopy, ZeroCopyEq};
126/// #[derive(ZeroCopy, ZeroCopyEq)]
127/// #[repr(C)]
128/// pub struct MyStruct {
129/// pub a: u8,
130/// }
131/// ```
132///
133#[proc_macro_derive(ZeroCopy, attributes(light_hasher, hash, skip))]
134pub fn derive_zero_copy(input: TokenStream) -> TokenStream {
135 let res = zero_copy::derive_zero_copy_impl(input);
136 TokenStream::from(match res {
137 Ok(res) => res,
138 Err(err) => err.to_compile_error(),
139 })
140}
141
142/// ZeroCopyEq implementation to add PartialEq for zero-copy structs.
143///
144/// Use this in addition to ZeroCopy when you want the generated struct to implement PartialEq:
145///
146/// ```rust, ignore
147/// use light_zero_copy_derive::{ZeroCopy, ZeroCopyEq};
148/// #[derive(ZeroCopy, ZeroCopyEq)]
149/// #[repr(C)]
150/// pub struct MyStruct {
151/// pub a: u8,
152/// }
153/// ```
154/// Note: Options are not supported in ZeroCopyEq
155#[proc_macro_derive(ZeroCopyEq)]
156pub fn derive_zero_copy_eq(input: TokenStream) -> TokenStream {
157 let res = zero_copy_eq::derive_zero_copy_eq_impl(input);
158 TokenStream::from(match res {
159 Ok(res) => res,
160 Err(err) => err.to_compile_error(),
161 })
162}
163
164/// ZeroCopyMut derivation macro for mutable zero-copy deserialization
165///
166/// This macro generates mutable zero-copy implementations including:
167/// - ZeroCopyAtMut trait implementation
168/// - Mutable Z-struct with `Mut` suffix (Z<StructName>Mut)
169/// - Mutable meta struct if there are fixed-size fields (Z<StructName>MetaMut)
170/// - ZeroCopyNew trait implementation with configuration support
171/// - Configuration struct for dynamic fields or unit type for fixed-size structs
172///
173/// # Usage
174///
175/// ```rust, ignore
176/// use light_zero_copy_derive::ZeroCopyMut;
177///
178/// #[derive(ZeroCopyMut)]
179/// #[repr(C)]
180/// pub struct MyStruct {
181/// pub a: u8,
182/// pub vec: Vec<u8>,
183/// }
184/// ```
185///
186/// This will generate:
187/// - `ZMyStructMut<'a>` type for mutable zero-copy access
188/// - `MyStructConfig` struct with `vec: u32` field for Vec length
189/// - `ZeroCopyAtMut` trait implementation for deserialization
190/// - `ZeroCopyNew` trait implementation for initialization with config
191///
192/// For fixed-size structs, generates unit config:
193/// ```rust, ignore
194/// use light_zero_copy_derive::ZeroCopyMut;
195/// #[derive(ZeroCopyMut)]
196/// #[repr(C)]
197/// pub struct FixedStruct {
198/// pub a: u8,
199/// pub b: u16,
200/// }
201/// // Generates: pub type FixedStructConfig = ();
202/// ```
203///
204/// For both immutable and mutable functionality, use both derives:
205/// ```rust, ignore
206/// use light_zero_copy_derive::{ZeroCopy, ZeroCopyMut};
207///
208/// #[derive(ZeroCopy, ZeroCopyMut)]
209/// #[repr(C)]
210/// pub struct MyStruct {
211/// pub a: u8,
212/// }
213/// ```
214#[cfg(feature = "mut")]
215#[proc_macro_derive(ZeroCopyMut)]
216pub fn derive_zero_copy_mut(input: TokenStream) -> TokenStream {
217 let res = zero_copy_mut::derive_zero_copy_mut_impl(input);
218 TokenStream::from(match res {
219 Ok(res) => res,
220 Err(err) => err.to_compile_error(),
221 })
222}