serde_patch/apply_patch_mut.rs
1use serde::{Serialize, de::DeserializeOwned};
2use serde_json::{Map, Value};
3
4/// Applies a JSON Merge Patch (RFC 7396) in-place.
5///
6/// Modifies `current` directly by merging the patch.
7/// Fields present in the patch replace the corresponding fields.
8/// `null` in the patch removes the field (if the target type supports it, e.g. `Option<T>`).
9/// Absent fields remain unchanged.
10///
11/// The patch can be any type that implements `AsRef<[u8]>` (`&str`, `String`, `Vec<u8>`, `&[u8]`, etc.).
12///
13/// # Errors
14///
15/// Returns an error if serialization, deserialization, or patch parsing fails.
16#[allow(dead_code)]
17pub fn apply_merge_patch_mut<T, P>(current: &mut T, patch: P) -> Result<(), serde_json::Error>
18where
19 T: Serialize + DeserializeOwned,
20 P: AsRef<[u8]>,
21{
22 let mut current_val = serde_json::to_value(¤t)?;
23 let patch_val: Value = serde_json::from_slice(patch.as_ref())?;
24 merge_patch(&mut current_val, &patch_val);
25 *current = serde_json::from_value(current_val)?;
26 Ok(())
27}
28
29/// Recursively merges a patch into a target JSON value (internal).
30fn merge_patch(target: &mut Value, patch: &Value) {
31 if let Value::Object(patch_map) = patch {
32 if !target.is_object() {
33 *target = Value::Object(Map::new());
34 }
35 let target_map = target.as_object_mut().unwrap();
36 for (key, patch_value) in patch_map {
37 if patch_value.is_null() {
38 target_map.remove(key);
39 } else {
40 let target_entry = target_map.entry(key.clone()).or_insert(Value::Null);
41 merge_patch(target_entry, patch_value);
42 }
43 }
44 } else {
45 *target = patch.clone();
46 }
47}
48
49/// Applies a JSON Merge Patch (RFC 7396) in-place.
50///
51/// Modifies the current value directly.
52///
53/// # Example
54///
55/// ```
56/// use serde_patch::apply_mut;
57///
58/// #[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug)]
59/// struct User { id: u32, name: String }
60///
61/// let mut user = User { id: 1, name: "old".to_string() };
62/// let patch = r#"{ "name": "new" }"#;
63///
64/// apply_mut!(&mut user, patch).unwrap();
65/// assert_eq!(user.name, "new");
66/// assert_eq!(user.id, 1);
67/// ```
68#[macro_export]
69macro_rules! apply_mut {
70 ($current:expr, $patch:expr) => {{ $crate::apply_patch_mut::apply_merge_patch_mut($current, $patch) }};
71}