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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
//! # Parcode V4
//!
//! A high-performance, graph-based serialization library for Rust that enables lazy loading,
//! zero-copy operations, and parallel processing of complex data structures.
//!
//! ## Overview
//!
//! Parcode is fundamentally different from traditional serialization libraries. Instead of treating
//! data as a monolithic blob, Parcode analyzes the structural relationships within your data and
//! creates a dependency graph where each node represents a serializable chunk. This architectural
//! approach enables several powerful capabilities:
//!
//! ### Key Features
//!
//! * **Parallel Serialization:** Independent chunks are serialized and compressed concurrently
//! using Rayon's work-stealing scheduler, maximizing CPU utilization.
//! * **Parallel Deserialization:** Reading operations leverage memory mapping and parallel
//! reconstruction to minimize I/O latency and maximize throughput.
//! * **Zero-Copy Operations:** Data is read directly from memory-mapped files where possible,
//! eliminating unnecessary allocations and copies.
//! * **Lazy Loading:** Navigate deep object hierarchies without loading data from disk. Only
//! the metadata is read initially, and actual data is loaded on-demand.
//! * **Surgical Access:** Load only specific fields, vector elements, or map entries without
//! deserializing the entire structure.
//! * **O(1) Map Lookups:** Hash-based sharding enables constant-time lookups in large `HashMaps`
//! without loading the entire collection.
//! * **Streaming/Partial Reads:** Large collections can be iterated over without loading the
//! entire dataset into RAM.
//! * **Generic I/O:** Serialize to any destination implementing `std::io::Write` (Files, Memory Buffers, Network Streams).
//! * **Forensic Inspection:** Built-in tools to analyze the structure of Parcode files without deserializing them.
//!
//! ## Architecture
//!
//! ### The Graph Model
//!
//! When you serialize an object with Parcode, the library constructs a directed acyclic graph (DAG)
//! where:
//! - Each node represents a serializable chunk of data
//! - Edges represent dependencies (parent-child relationships)
//! - Leaf nodes contain primitive data or small collections
//! - Internal nodes contain metadata and references to their children
//!
//! This graph is then executed bottom-up: leaves are processed first, and parents are processed
//! only after all their children have completed. This enables maximum parallelism while maintaining
//! data integrity.
//!
//! ### File Format (V4)
//!
//! The physical layout on disk follows a "children-first" ordering:
//! ```text
//! [Leaf Chunk 1] [Leaf Chunk 2] ... [Parent Chunk] [Root Chunk] [Global Header]
//! ```
//!
//! Each chunk is self-contained with:
//! ```text
//! [Payload] [Children Table (Optional)] [MetaByte]
//! ```
//!
//! The Global Header at the end of the file points to the Root Chunk, which serves as the
//! entry point for reading operations.
//!
//! ## Core Concepts
//!
//! ### `TaskGraph`
//!
//! The [`graph::TaskGraph`] is the central structure representing the object graph to be serialized.
//! It acts as an arena allocator for nodes and manages the dependency relationships between them.
//! The graph lifetime is tied to the input data, enabling zero-copy serialization.
//!
//! ### Executor
//!
//! The [`executor`] module contains the engine that drives parallel execution of the graph.
//! It orchestrates the serialization → compression → I/O pipeline, using atomic operations
//! for lock-free dependency tracking and Rayon for work distribution.
//!
//! ### Inspector
//!
//! The [`inspector`] module provides tools for forensic analysis of Parcode files. It allows you to
//! visualize the internal chunk structure, compression ratios, and data distribution without
//! needing to deserialize the actual payloads.
//!
//! ### Reader
//!
//! The [`ParcodeFile`] is responsible for memory-mapping the file and reconstructing objects.
//! It provides both eager (full deserialization) and lazy (on-demand) reading strategies,
//! automatically selecting the optimal approach based on the data type.
//!
//! ### Visitor
//!
//! The [`visitor::ParcodeVisitor`] trait allows types to define how they should be decomposed
//! into graph nodes. The `#[derive(ParcodeObject)]` macro automatically implements this trait,
//! analyzing field attributes to determine which fields should be inlined vs. stored as
//! separate chunks.
//!
//! ## Usage Patterns
//!
//! ### Basic Serialization
//!
//! ```rust
//! use parcode::{Parcode, ParcodeObject};
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Serialize, Deserialize, ParcodeObject)]
//! struct PlayerData {
//! name: String,
//! stats: Vec<u32>,
//! }
//!
//! #[derive(Serialize, Deserialize, ParcodeObject)]
//! struct GameState {
//! level: u32,
//! score: u64,
//! #[parcode(chunkable)]
//! player_data: PlayerData,
//! }
//!
//! // Save
//! let state = GameState {
//! level: 1,
//! score: 1000,
//! player_data: PlayerData {
//! name: "Hero".to_string(),
//! stats: vec![10, 20, 30],
//! },
//! };
//! Parcode::save("game_lib.par", &state)?;
//!
//! // Load (eager)
//! let loaded: GameState = Parcode::load("game_lib.par")?;
//! # std::fs::remove_file("game_lib.par").ok();
//! # Ok::<(), parcode::ParcodeError>(())
//! ```
//!
//! ### Lazy Loading
//!
//! ```rust
//! use parcode::{Parcode, ParcodeFile, ParcodeObject};
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Serialize, Deserialize, ParcodeObject)]
//! struct PlayerData {
//! name: String,
//! stats: Vec<u32>,
//! }
//!
//! #[derive(Serialize, Deserialize, ParcodeObject)]
//! struct GameState {
//! level: u32,
//! score: u64,
//! #[parcode(chunkable)]
//! player_data: PlayerData,
//! }
//!
//! // Setup file
//! let state = GameState {
//! level: 1,
//! score: 1000,
//! player_data: PlayerData {
//! name: "Hero".to_string(),
//! stats: vec![10, 20, 30],
//! },
//! };
//! Parcode::save("game_lazy.par", &state)?;
//!
//! let file = Parcode::open("game_lazy.par")?;
//! let state_lazy = file.root::<GameState>()?;
//!
//! // Access local fields instantly (already in memory)
//! println!("Level: {}", state_lazy.level);
//!
//! // Load remote fields on-demand
//! let player_name = state_lazy.player_data.name;
//! # std::fs::remove_file("game_lazy.par").ok();
//! # Ok::<(), parcode::ParcodeError>(())
//! ```
//!
//! ### `HashMap` Sharding
//!
//! ```rust
//! use parcode::{Parcode, ParcodeFile, ParcodeObject};
//! use serde::{Serialize, Deserialize};
//! use std::collections::HashMap;
//!
//! #[derive(Serialize, Deserialize, ParcodeObject, Clone, Debug)]
//! struct User { name: String }
//!
//! #[derive(Serialize, Deserialize, ParcodeObject, Debug)]
//! struct Database {
//! #[parcode(map)] // Enable O(1) lookups
//! users: HashMap<u64, User>,
//! }
//!
//! // Setup
//! let mut users = HashMap::new();
//! users.insert(12345, User { name: "Alice".to_string() });
//! let db = Database { users };
//! Parcode::save("db_map.par", &db)?;
//!
//! let file = Parcode::open("db_map.par")?;
//! let db_lazy = file.root::<Database>()?;
//! let user = db_lazy.users.get(&12345u64).expect("User not found");
//! # std::fs::remove_file("db_map.par").ok();
//! # Ok::<(), parcode::ParcodeError>(())
//! ```
//!
//! ## Performance Considerations
//!
//! - **Write Performance:** Scales linearly with CPU cores for independent chunks
//! - **Read Performance:** Memory-mapped I/O provides near-instant startup times
//! - **Memory Usage:** Lazy loading keeps memory footprint minimal
//! - **Compression:** Optional LZ4 compression (feature: `lz4_flex`) trades CPU for I/O bandwidth
//!
//! ### Safety and Error Handling
//!
//! Parcode is designed with safety as a priority:
//!
//! * **Encapsulated Unsafe:** `unsafe` code is used sparingly and only in the `reader` module
//! to achieve zero-copy parallel stitching of vectors. These sections are strictly auditied.
//! * **No Panics:** No `unwrap()` or `panic!()` calls in the library (enforced by clippy lints).
//! * **Comprehensive Errors:** All failures correspond to a [`ParcodeError`] type.
//! * **Robust I/O:** Mutex poisoning and partial writes are handled gracefully.
// --- PUBLIC API MODULES ---
// --- INTERNAL IMPLEMENTATION MODULES (Hidden from Docs) ---
// Private modules
// --- MACRO SUPPORT MODULES ---
/// Runtime utilities used by the derived code.
/// Internal re-exports for the macro to ensure dependencies are available.
// --- RE-EXPORTS ---
pub use Lz4Compressor;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ParcodeObject;
pub use ;
/// Constants used throughout the library.