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}