Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ logic. See Features and How It Works for details.
- **Automatic Patch Type Generation**: Derives a companion `Patch` struct for any struct annotated with `#[derive(Patchable)]`
- **Recursive Patching**: Use the `#[patchable]` attribute to mark fields that require recursive patching
- **Smart Exclusion**: Excludes fields marked with `#[patchable(skip)]`
- **Serde Integration (default)**: Generated patch types automatically implement `serde::Deserialize` and `Clone`
- **Serde Integration (optional, default)**: Generated patch types automatically implement `serde::Deserialize` (exclude
the `serde` feature to opt out)
- **Clone Support (optional, default)**: Generated patch types automatically implement `Clone` (exclude the `cloneable`
feature to opt out)
- **Generic Support**: Full support for generic types with automatic trait bound inference
- **Optional `From` Derive**: Enable `From<Struct>` for `StructPatch` with the `impl_from` feature
- **`#[patchable_model]` Attribute Macro**: Auto-derives `Patchable` and `Patch`, and (with default `serde`) adds `serde::Serialize`
Expand Down Expand Up @@ -83,6 +86,13 @@ Enable `From<Struct>` generation:
patchable = { version = "0.5.3", features = ["impl_from"] }
```

Enable `Clone` derivation for patch types:

```toml
[dependencies]
patchable = { version = "0.5.3", features = ["cloneable"] }
```

## Usage

### Basic Example
Expand Down Expand Up @@ -244,7 +254,7 @@ impl TryPatch for Config {
- Only structs are supported (enums and unions are not).
- Lifetime parameters are not supported.
- `#[patchable]` currently only supports simple generic types (not complex types like `Vec<T>`).
- Generated patch types derive `Clone` and `Deserialize` but not `Serialize` (by design).
- Generated patch types derive `Deserialize` (default) and `Clone` (optional with `cloneable` feature) but not `Serialize` (by design).

## How It Works

Expand Down Expand Up @@ -319,7 +329,7 @@ Marks a field for recursive patching.

```rust
pub trait Patchable {
type Patch: Clone;
type Patch;
}
```

Expand Down
14 changes: 5 additions & 9 deletions patchable/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,15 @@ pub use patchable_macro::{Patch, Patchable, patchable_model};
/// // `impl_from` feature is enabled. For derived implementations, mark non-state fields with
/// // `#[patchable(skip)]` (and add `#[serde(skip)]` as needed when using serde).
///
/// #[derive(Clone, PartialEq, Deserialize)]
/// // Derive `Clone` if needed by enabling "cloneable" feature or manually.
/// // "cloneable" is enabled by default.
/// #[derive(PartialEq, Deserialize)]
/// pub struct AccumulatorPatch<T> {
/// prev_control_signal: T,
/// accumulated: u32,
/// }
///
/// impl<T> Patchable for Accumulator<T>
/// where
/// T: Clone,
/// {
/// impl<T> Patchable for Accumulator<T> {
/// type Patch = AccumulatorPatch<T>;
/// }
///
Expand All @@ -61,10 +60,7 @@ pub use patchable_macro::{Patch, Patchable, patchable_model};
/// }
/// }
///
/// impl<T> Patch for Accumulator<T>
/// where
/// T: Clone,
/// {
/// impl<T> Patch for Accumulator<T> {
/// #[inline(always)]
/// fn patch(&mut self, patch: Self::Patch) {
/// self.prev_control_signal = patch.prev_control_signal;
Expand Down