1- //! Procedural macros for zero-copy deserialization.
1+ //! Procedural macros for borsh compatible zero copy serialization.
2+ //!
23//!
3- //! This crate provides derive macros that generate efficient zero-copy data structures
4- //! and deserialization code, eliminating the need for data copying during parsing.
54//!
65//! ## Main Macros
76//!
8- //! - `ZeroCopy`: Generates zero-copy structs and deserialization traits
9- //! - `ZeroCopyMut`: Adds mutable zero-copy support
10- //! - `ZeroCopyEq`: Adds PartialEq implementation for comparing with original structs
11- //! - `ZeroCopyNew`: Generates configuration structs for initialization
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, Option, 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+ //! Examples:
22+ //! ```rust
23+ //! use light_zero_copy::slice::ZeroCopySliceBorsh;
24+ //! use light_zero_copy::slice_mut::ZeroCopySliceMutBorsh;
25+ //!
26+ //! pub struct Struct1 {
27+ //! a: Vec<u8>,
28+ //! }
29+ //!
30+ //! pub struct ZStruct1<'a> {
31+ //! a: &'a [u8]
32+ //! }
33+ //! pub struct ZStruct1Mut<'a> {
34+ //! a: &'a mut [u8]
35+ //! }
36+ //!
37+ //! pub struct Struct2 {
38+ //! a: Vec<u64>,
39+ //! }
40+ //!
41+ //! pub struct ZStruct2<'a> {
42+ //! a: ZeroCopySliceBorsh<'a, u64>,
43+ //! }
44+ //! pub struct ZStruct2Mut<'a> {
45+ //! a: ZeroCopySliceMutBorsh<'a, u64>,
46+ //! }
47+ //! ```
48+ //! 2. Implement ZeroCopyAt trait which returns Z<StructName>
49+ //! 3. ZeroCopyMut (separate derive) adds:
50+ //! 3.1. Mutable variants with 'Mut' suffix (Z<StructName>Mut, Z<StructName>MetaMut)
51+ //! 3.2. ZeroCopyAtMut trait implementation
52+ //! 3.3. ZeroCopyNew trait with configuration struct for dynamic field initialization
1253
1354use proc_macro:: TokenStream ;
1455
@@ -43,33 +84,6 @@ mod tests;
4384/// }
4485/// ```
4586///
46- /// To derive LightHasher for the generated ZStruct, use the #[light_hasher] attribute:
47- /// ```ignore
48- /// use light_zero_copy_derive::ZeroCopy;
49- /// #[derive(ZeroCopy)]
50- /// #[light_hasher] // Currently disabled due to Vec<u8>/&[u8] hash inconsistency
51- /// pub struct MyStruct {
52- /// pub a: u8,
53- /// }
54- /// ```
55- ///
56- /// Note: #[light_hasher] is currently disabled due to hash inconsistency between
57- /// Vec<u8> fields in the original struct and &[u8] slice fields in the generated ZStruct.
58- ///
59- /// # Macro Rules
60- /// 1. Create zero copy structs Z<StructName> and Z<StructName>Mut for the struct
61- /// 1.1. The first fields are extracted into a meta struct until we reach a Vec, Option or type that does not implement Copy
62- /// 1.2. Represent vectors to ZeroCopySlice & don't include these into the meta struct
63- /// 1.3. Replace u16 with U16, u32 with U32, etc
64- /// 1.4. Every field after the first vector is directly included in the ZStruct and deserialized 1 by 1
65- /// 1.5. If a vector contains a nested vector (does not implement Copy) it must implement Deserialize
66- /// 1.6. Elements in an Option must implement Deserialize
67- /// 1.7. A type that does not implement Copy must implement Deserialize, and is deserialized 1 by 1
68- /// 1.8. is u8 deserialized as u8::zero_copy_at instead of Ref<&'a [u8], u8> for non mut, for mut it is Ref<&'a mut [u8], u8>
69- /// 2. Implement Deserialize and ZeroCopyAtMut which return Z<StructName> and Z<StructName>Mut
70- /// 3. Implement From<Z<StructName>> for StructName and From<Z<StructName>Mut> for StructName
71- ///
72- /// Note: Options are not supported in ZeroCopyEq
7387#[ proc_macro_derive( ZeroCopy , attributes( light_hasher, hash, skip) ) ]
7488pub fn derive_zero_copy ( input : TokenStream ) -> TokenStream {
7589 let res = zero_copy:: derive_zero_copy_impl ( input) ;
@@ -90,6 +104,7 @@ pub fn derive_zero_copy(input: TokenStream) -> TokenStream {
90104/// pub a: u8,
91105/// }
92106/// ```
107+ /// Note: Options are not supported in ZeroCopyEq
93108#[ proc_macro_derive( ZeroCopyEq ) ]
94109pub fn derive_zero_copy_eq ( input : TokenStream ) -> TokenStream {
95110 let res = zero_copy_eq:: derive_zero_copy_eq_impl ( input) ;
@@ -103,9 +118,10 @@ pub fn derive_zero_copy_eq(input: TokenStream) -> TokenStream {
103118///
104119/// This macro generates mutable zero-copy implementations including:
105120/// - ZeroCopyAtMut trait implementation
106- /// - Mutable Z-struct with `Mut` suffix
107- /// - byte_len() method implementation
108- /// - Mutable ZeroCopyStructInner implementation
121+ /// - Mutable Z-struct with `Mut` suffix (Z<StructName>Mut)
122+ /// - Mutable meta struct if there are fixed-size fields (Z<StructName>MetaMut)
123+ /// - ZeroCopyNew trait implementation with configuration support
124+ /// - Configuration struct for dynamic fields or unit type for fixed-size structs
109125///
110126/// # Usage
111127///
@@ -120,9 +136,21 @@ pub fn derive_zero_copy_eq(input: TokenStream) -> TokenStream {
120136/// ```
121137///
122138/// This will generate:
123- /// - `MyStruct::zero_copy_at_mut()` method
124139/// - `ZMyStructMut<'a>` type for mutable zero-copy access
125- /// - `MyStruct::byte_len()` method
140+ /// - `MyStructConfig` struct with `vec: u32` field for Vec length
141+ /// - `ZeroCopyAtMut` trait implementation for deserialization
142+ /// - `ZeroCopyNew` trait implementation for initialization with config
143+ ///
144+ /// For fixed-size structs, generates unit config:
145+ /// ```rust
146+ /// use light_zero_copy_derive::ZeroCopyMut;
147+ /// #[derive(ZeroCopyMut)]
148+ /// pub struct FixedStruct {
149+ /// pub a: u8,
150+ /// pub b: u16,
151+ /// }
152+ /// // Generates: pub type FixedStructConfig = ();
153+ /// ```
126154///
127155/// For both immutable and mutable functionality, use both derives:
128156/// ```rust
@@ -142,41 +170,3 @@ pub fn derive_zero_copy_mut(input: TokenStream) -> TokenStream {
142170 Err ( err) => err. to_compile_error ( ) ,
143171 } )
144172}
145-
146- // /// ZeroCopyNew derivation macro for configuration-based zero-copy initialization
147- // ///
148- // /// This macro generates configuration structs and initialization methods for structs
149- // /// with Vec and Option fields that need to be initialized with specific configurations.
150- // ///
151- // /// # Usage
152- // ///
153- // /// ```ignore
154- // /// use light_zero_copy_derive::ZeroCopyNew;
155- // ///
156- // /// #[derive(ZeroCopyNew)]
157- // /// pub struct MyStruct {
158- // /// pub a: u8,
159- // /// pub vec: Vec<u8>,
160- // /// pub option: Option<u64>,
161- // /// }
162- // /// ```
163- // ///
164- // /// This will generate:
165- // /// - `MyStructConfig` struct with configuration fields
166- // /// - `ZeroCopyNew` implementation for `MyStruct`
167- // /// - `new_zero_copy(bytes, config)` method for initialization
168- // ///
169- // /// The configuration struct will have fields based on the complexity of the original fields:
170- // /// - `Vec<Primitive>` → `field_name: u32` (length)
171- // /// - `Option<Primitive>` → `field_name: bool` (is_some)
172- // /// - `Vec<Complex>` → `field_name: Vec<ComplexConfig>` (config per element)
173- // /// - `Option<Complex>` → `field_name: Option<ComplexConfig>` (config if some)
174- // #[cfg(feature = "mut")]
175- // #[proc_macro_derive(ZeroCopyNew)]
176- // pub fn derive_zero_copy_config(input: TokenStream) -> TokenStream {
177- // let res = zero_copy_new::derive_zero_copy_config_impl(input);
178- // TokenStream::from(match res {
179- // Ok(res) => res,
180- // Err(err) => err.to_compile_error(),
181- // })
182- // }
0 commit comments