Patchable
A Rust library with for automatically deriving patch types and implementing efficient state updates for target types.
-
A
Patchabletrait is provided: -
A derive macro that automatically generates a companion "patch" type for your target struct and implements
Patchableon the target type.This enables efficient partial updates of struct instances by applying patches, which is particularly useful for:
-
State management in event-driven systems
-
Incremental updates in streaming applications
-
Serialization/deserialization of state changes
Features
- Automatic Patch Type Generation: Derives a companion
Statestruct for any struct annotated with#[derive(Patchable)] - Recursive Patching: Use
#[patchable]attribute to mark fields that require recursive patching - Smart Exclusion: Respects
#[serde(skip)]and#[serde(skip_serializing)], andPhantomDatato keep patches lean. - Serde Integration: Generated patch types automatically implement
serde::DeserializeandClone - Generic Support: Full support for generic types with automatic trait bound inference
- Zero Runtime Overhead: All code generation happens at compile time
Installation
Add this to your Cargo.toml:
[]
= "0.1.0"
Usage
Basic Example
use Patchable;
use ;
Skipping Fields
Fields can be excluded from patching using serde attributes:
use Patchable;
use ;
Fields marked with #[serde(skip)] or #[serde(skip_serializing)] are automatically excluded from the generated patch type.
Nested Patchable Structs
The macro fully supports generic types:
use Patchable;
use ;
The macro automatically:
- Preserves only the generic parameters used in non-skipped fields
- Adds appropriate trait bounds (
Clone,Patchable) based on field usage - Generates correctly parameterized patch types
Fallible Patching
The TryPatch trait allows for fallible updates, which is useful when patch application requires validation:
use TryPatch;
use fmt;
;
How It Works
When you derive Patchable on a struct:
-
Patch Type Generation: A companion struct named
{StructName}Stateis generated- Fields marked with
#[patchable]use their own patch types (T::Patch) - Other fields are copied directly with their original types
- Fields with
#[serde(skip)],#[serde(skip_serializing)]orPhantomDataare excluded
- Fields marked with
-
Trait Implementation: The
Patchabletrait is implemented: -
Patch Method: The
patchmethod updates the struct:- Regular fields are directly assigned from the patch
#[patchable]fields are recursively patched via their ownpatchmethod
API Reference
#[derive(Patchable)]
Derives the Patchable trait for a struct.
Requirements:
- Must be applied to a struct (not enums or unions)
- Does not support lifetime parameters (borrowed fields)
- Works with named, unnamed (tuple), and unit structs
#[patchable] Attribute
Marks a field for recursive patching.
Requirements:
- The types of fields with
#[patchable]must implementPatchable - Currently only supports simple generic types (not complex types like
Vec<T>)
Patchable Trait
-
Patch: The associated patch type (automatically generated as{StructName}Stateif#[derive(Patchable)]is applied) -
patch: Method to apply a patch to the current instance
TryPatch Trait
A fallible variant of Patchable for cases where applying a patch might fail.
try_patch: Applies the patch, returning aResult. A blanket implementation exists for all types that implementPatchable(whereErrorisstd::convert::Infallible).
License
MIT
Contributing
Contributions are welcome! Please feel free to submit issues or pull requests.