pub struct Parcode { /* private fields */ }Expand description
The main entry point for configuring and executing Parcode operations.
This struct provides a builder-style API for configuring serialization parameters and executing read/write operations. It is designed to be lightweight and can be constructed multiple times without significant overhead.
§Configuration Options
- Compression: Enable or disable compression (default: disabled). When enabled,
the library uses the default compression algorithm (LZ4 if the
lz4_flexfeature is enabled, otherwise no compression).
§Examples
§Basic Usage
use parcode::Parcode;
let data = vec![1, 2, 3];
Parcode::save("data_basic.par", &data).unwrap();
let loaded: Vec<i32> = Parcode::read("data_basic.par").unwrap();§With Compression
use parcode::Parcode;
let data = vec![1, 2, 3];
Parcode::builder()
.compression(true)
.write("data_comp.par", &data)?;§Performance Notes
- The builder itself has negligible overhead (it’s just a small struct with flags)
- Compression trades CPU time for reduced I/O and storage
- Parallel execution scales with the number of independent chunks in your data
Implementations§
Source§impl Parcode
impl Parcode
Sourcepub fn builder() -> Self
pub fn builder() -> Self
Creates a new Parcode builder with default settings.
This is the entry point for the builder pattern. The returned instance can be
configured using method chaining before calling write.
§Default Settings
- Compression: Disabled
§Examples
use parcode::Parcode;
let parcode = Parcode::builder()
.compression(true);§Performance
This method is extremely lightweight (just creates a small struct) and can be called repeatedly without concern for performance.
Sourcepub fn compression(self, enable: bool) -> Self
pub fn compression(self, enable: bool) -> Self
Enables or disables compression for all chunks.
When compression is enabled, the library will use the default compression algorithm to reduce the size of serialized chunks. The actual algorithm used depends on which features are enabled:
- If the
lz4_flexfeature is enabled: LZ4 compression (fast, moderate ratio) - Otherwise: No compression (pass-through)
§Parameters
enable: Whether to enable compression
§Returns
Returns self to allow method chaining.
§Trade-offs
- Enabled: Smaller files, lower I/O bandwidth, higher CPU usage
- Disabled: Larger files, higher I/O bandwidth, lower CPU usage
§Examples
use parcode::{Parcode, ParcodeObject};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, ParcodeObject)]
struct MyData { val: i32 }
let my_data = MyData { val: 42 };
// Enable compression
Parcode::builder()
.compression(true)
.write("data.par", &my_data)?;§Performance Notes
- LZ4 compression typically achieves 2-3x compression ratios on structured data with minimal CPU overhead. For data that doesn’t compress well (e.g., already compressed images), the overhead may outweigh the benefits.
Sourcepub fn read<T, P>(path: P) -> Result<T>
pub fn read<T, P>(path: P) -> Result<T>
Reads and fully deserializes an object from a Parcode file.
This method automatically selects the optimal reconstruction strategy based on the type being read:
- Collections (
Vec<T>): Uses parallel reconstruction across shards - Maps (
HashMap<K, V>): Reconstructs all shards and merges entries - Primitives and Structs: Uses sequential deserialization
§Type Parameters
T: The type to deserialize. Must implementParcodeNative.P: The path type (anything that implementsAsRef<Path>).
§Parameters
path: The file path to read from.
§Returns
Returns the fully deserialized object of type T.
§Errors
This method can fail if:
- The file does not exist or cannot be opened
- The file is not a valid Parcode file (wrong magic bytes or version)
- The file is corrupted or truncated
- Deserialization fails (e.g., type mismatch)
- Decompression fails
§Examples
use parcode::{Parcode, ParcodeObject};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, ParcodeObject)]
struct GameState { level: u32 }
// Setup
let data = vec![1, 2, 3];
Parcode::save("numbers_read.par", &data)?;
let state = GameState { level: 1 };
Parcode::save("game_read.par", &state)?;
// Read a vector
let data: Vec<i32> = Parcode::read("numbers_read.par")?;
// Read a custom struct
let state: GameState = Parcode::read("game_read.par")?;Sourcepub fn save<T, P>(path: P, root_object: &T) -> Result<()>
pub fn save<T, P>(path: P, root_object: &T) -> Result<()>
Saves an object to a file using default settings (no compression).
This is a convenience method that creates a default Parcode instance and calls
write.
§Type Parameters
T: The type to serialize. Must implementParcodeVisitorandSync(for parallel execution).P: The path type (anything that implementsAsRef<Path>).
§Parameters
path: The file path to write to. If the file exists, it will be truncated.root_object: A reference to the object to serialize.
§Returns
Returns Ok(()) on success.
§Errors
This method can fail if:
- The file cannot be created (e.g., permission denied, disk full)
- Serialization fails (e.g., bincode error)
- I/O errors occur during writing
§Examples
use parcode::{Parcode, ParcodeObject};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, ParcodeObject)]
struct MyData {
value: i32,
}
let data = MyData { value: 42 };
Parcode::save("data_save.par", &data)?;§Performance
- Zero-Copy: The serializer borrows data rather than cloning it
- Parallel Execution: Independent chunks are processed concurrently
- Buffered I/O: Uses a 16MB buffer to minimize syscalls
For custom configuration (e.g., enabling compression), use the builder pattern:
use parcode::Parcode;
let data = vec![1, 2, 3];
Parcode::builder()
.compression(true)
.write("data_builder.par", &data)?;Sourcepub fn write<T, P>(&self, path: P, root_object: &T) -> Result<()>
pub fn write<T, P>(&self, path: P, root_object: &T) -> Result<()>
Serializes an object graph to disk with the configured settings.
This method performs the complete serialization pipeline:
- Graph Construction: Analyzes the object structure and builds a dependency graph
- Parallel Execution: Processes independent chunks concurrently using Rayon
- Compression: Applies compression to each chunk (if enabled)
- I/O: Writes chunks to disk in a bottom-up order
- Header Writing: Appends the global header pointing to the root chunk
§Type Parameters
'a: The lifetime of the object being serialized. The graph borrows from the object, enabling zero-copy serialization.T: The type to serialize. Must implementParcodeVisitorandSync(for parallel execution).P: The path type (anything that implementsAsRef<Path>).
§Parameters
path: The file path to write to. If the file exists, it will be truncated.root_object: A reference to the object to serialize. This reference must remain valid for the entire duration of the serialization process.
§Returns
Returns Ok(()) on success.
§Errors
This method can fail if:
- The file cannot be created (e.g., permission denied, disk full)
- Serialization fails (e.g., bincode error)
- Compression fails
- I/O errors occur during writing
- The graph contains cycles (should not happen with valid
ParcodeVisitorimplementations)
§Examples
use parcode::Parcode;
let data = vec![1, 2, 3, 4, 5];
// Write with compression
Parcode::builder()
.compression(true)
.write("data_write.par", &data)?;§Performance Characteristics
- Parallelism: Scales with the number of independent chunks (typically O(cores))
- Memory: Uses zero-copy where possible; peak memory is proportional to the largest chunk plus buffer overhead
- I/O: Buffered writes (16MB buffer) minimize syscalls
- Compression: LZ4 compression adds ~10-20% CPU overhead but can reduce I/O by 2-3x
Serializes an object graph to disk with the configured settings.
This is a convenience wrapper around write_to_writer that handles file creation.
§Type Parameters
T: The type to serialize. Must implementParcodeVisitorandSync(for parallel execution).P: The path type (anything that implementsAsRef<Path>).
§Parameters
path: The file path to write to. If the file exists, it will be truncated.root_object: A reference to the object to serialize.
Sourcepub fn write_to_writer<'a, T, W>(
&self,
writer: W,
root_object: &'a T,
) -> Result<()>
pub fn write_to_writer<'a, T, W>( &self, writer: W, root_object: &'a T, ) -> Result<()>
Serializes the object graph to a generic writer (File, VecTcpStream, etc).
This method performs the complete serialization pipeline:
- Graph Construction: Analyzes the object structure and builds a dependency graph
- Parallel Execution: Processes independent chunks concurrently using Rayon
- Compression: Applies compression to each chunk (if enabled)
- I/O: Writes chunks to the writer in a bottom-up order
- Header Writing: Appends the global header pointing to the root chunk
§Type Parameters
'a: The lifetime of the object being serialized. The graph borrows from the object, enabling zero-copy serialization.
§Thread Safety
T: The type to serialize. Must implementParcodeVisitor+Sync.W: The writer type. Must implementWrite+Send.
§Parameters
writer: The destination to write to.root_object: A reference to the object to serialize.
§Returns
Returns Ok(()) on success.
§Errors
This method can fail if:
- Serialization fails (e.g., bincode error)
- Compression fails
- I/O errors occur during writing to the
writer
§Examples
use parcode::Parcode;
let data = vec![1, 2, 3];
let mut buffer = Vec::new();
Parcode::builder()
.write_to_writer(&mut buffer, &data)?;Sourcepub fn save_sync<T, P>(path: P, root_object: &T) -> Result<()>
pub fn save_sync<T, P>(path: P, root_object: &T) -> Result<()>
Serializes an object synchronously (single-threaded).
This method is useful for:
- Environments where spawning threads is expensive or restricted (WASM, embeddedish).
- Debugging serialization logic without concurrency noise.
- Benchmarking vs Parallel implementation.
It uses less memory than write because it reuses a single compression buffer.
Sourcepub fn write_sync<'a, T, P>(&self, path: P, root_object: &'a T) -> Result<()>
pub fn write_sync<'a, T, P>(&self, path: P, root_object: &'a T) -> Result<()>
Internal synchronous write implementation.
Currently only supports file paths because execute_graph_sync consumes the writer,
and we need to re-open the file to append the header (simplest approach for now).
A future refactor could support generic writers for sync mode if needed.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Parcode
impl RefUnwindSafe for Parcode
impl Send for Parcode
impl Sync for Parcode
impl Unpin for Parcode
impl UnwindSafe for Parcode
Blanket Implementations§
§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more