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
//! # Patchable
//!
//! A crate for handling partial updates to data structures.
//!
//! This crate provides the [`Patchable`], [`Patch`], and [`TryPatch`] traits, along with
//! derive macros for `Patchable` and `Patch`, and an attribute macro `patchable_model`
//! re-exported from `patchable_macro` for easy derivation.
//!
//! ## Motivation
//!
//! Many systems receive incremental updates where only a subset of fields change or can be
//! considered part of the state. This crate formalizes this pattern by defining a patch type for a
//! structure and providing a consistent way to apply such patches safely.
// Re-export the derive macros.
extern crate self as patchable;
pub use ;
/// A type that declares a companion patch type.
///
/// ## Usage
///
/// ```rust
/// use patchable::{Patch, Patchable};
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Debug, Serialize)]
/// pub struct Accumulator<T> {
/// prev_control_signal: T,
/// #[serde(skip)]
/// filter: fn(&i32) -> bool,
/// accumulated: u32,
/// }
///
/// //vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
/// // If we derive `Patchable` and `Patch` for `Accumulator`, the following `AccumulatorPatch` type
/// // and the `Patchable`/`Patch` implementations can be generated automatically.
/// //
/// // When deriving `Patchable`, a `From<Accumulator>` implementation is generated if the
/// // `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` 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> {
/// type Patch = AccumulatorPatch<T>;
/// }
///
/// impl<T> From<Accumulator<T>> for AccumulatorPatch<T> {
/// fn from(acc: Accumulator<T>) -> Self {
/// Self {
/// prev_control_signal: acc.prev_control_signal,
/// accumulated: acc.accumulated,
/// }
/// }
/// }
///
/// impl<T> Patch for Accumulator<T> {
/// #[inline(always)]
/// fn patch(&mut self, patch: Self::Patch) {
/// self.prev_control_signal = patch.prev_control_signal;
/// self.accumulated = patch.accumulated;
/// }
/// }
/// //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
///
/// fn main() {
/// let accumulator = Accumulator {
/// prev_control_signal: 6,
/// filter: |x: &i32| *x > 300,
/// accumulated: 15,
/// };
///
/// let state_bytes = postcard::to_vec::<_, 128>(&accumulator).unwrap();
/// let accumulator_patch: AccumulatorPatch<i32> = postcard::from_bytes(&state_bytes).unwrap();
///
/// let mut recovered_accumulator = Accumulator {
/// prev_control_signal: -1,
/// accumulated: 0,
/// ..accumulator
/// };
///
/// recovered_accumulator.patch(accumulator_patch);
///
/// assert_eq!(recovered_accumulator.prev_control_signal, accumulator.prev_control_signal);
/// assert_eq!(recovered_accumulator.accumulated, accumulator.accumulated);
/// }
/// ```
/// Declares the associated patch type.
/// A type that can be updated using its companion patch.
/// A fallible variant of [`Patch`].
///
/// This trait lets you apply a patch with validation and return a custom error
/// if it cannot be applied.
///
/// ## Usage
///
/// ```rust
/// use patchable::{TryPatch, Patchable};
/// use core::fmt;
///
/// #[derive(Debug)]
/// struct Config {
/// concurrency: u32,
/// }
///
/// #[derive(Clone, PartialEq)]
/// struct ConfigPatch {
/// concurrency: u32,
/// }
///
/// #[derive(Debug)]
/// struct PatchError(String);
///
/// impl fmt::Display for PatchError {
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// write!(f, "{}", self.0)
/// }
/// }
///
/// impl core::error::Error for PatchError {}
///
/// impl Patchable for Config {
/// type Patch = ConfigPatch;
/// }
///
/// impl From<Config> for ConfigPatch {
/// fn from(c: Config) -> Self {
/// Self { concurrency: c.concurrency }
/// }
/// }
///
/// impl TryPatch for Config {
/// type Error = PatchError;
///
/// fn try_patch(&mut self, patch: Self::Patch) -> Result<(), Self::Error> {
/// if patch.concurrency == 0 {
/// return Err(PatchError("Concurrency must be > 0".into()));
/// }
/// self.concurrency = patch.concurrency;
/// Ok(())
/// }
/// }
///
/// fn main() {
/// let mut config = Config { concurrency: 1 };
/// let valid_patch = ConfigPatch { concurrency: 4 };
/// config.try_patch(valid_patch).unwrap();
/// assert_eq!(config.concurrency, 4);
///
/// let invalid_patch = ConfigPatch { concurrency: 0 };
/// assert!(config.try_patch(invalid_patch).is_err());
/// }
/// ```
/// Blanket implementation for all [`Patch`] types, where patching is
/// infallible.