1use std::cell::Cell;
10use std::collections::HashSet;
11
12use serde::Serialize;
13use serde::ser::{Impossible, SerializeMap, SerializeSeq, SerializeStruct, Serializer};
14use serde_json::{Map, Value};
15
16pub struct Diff {
18 pub patch: Value,
20
21 pub forced_snapshot: bool,
26}
27
28pub fn diff<T: Serialize>(old: &Value, new: &T) -> Diff {
33 let forced = Cell::new(false);
34 let node = new.serialize(Differ {
35 baseline: old,
36 forced: &forced,
37 });
38
39 match node {
40 Ok(Node::Same) => Diff {
42 patch: Value::Object(Map::new()),
43 forced_snapshot: forced.get(),
44 },
45 Ok(Node::Diff(patch)) => {
48 let non_object_root = !patch.is_object() || !old.is_object();
49 Diff {
50 patch,
51 forced_snapshot: forced.get() || non_object_root,
52 }
53 }
54 Err(_) => Diff {
57 patch: Value::Object(Map::new()),
58 forced_snapshot: true,
59 },
60 }
61}
62
63enum Node {
65 Same,
67 Diff(Value),
69}
70
71const NULL: Value = Value::Null;
72
73#[derive(Copy, Clone)]
76struct Differ<'a> {
77 baseline: &'a Value,
78 forced: &'a Cell<bool>,
79}
80
81impl<'a> Differ<'a> {
82 fn child(&self, key: &str) -> (Differ<'a>, bool) {
85 let (baseline, existed) = match self.baseline {
86 Value::Object(m) => match m.get(key) {
87 Some(value) => (value, true),
88 None => (&NULL, false),
89 },
90 _ => (&NULL, false),
91 };
92 (
93 Differ {
94 baseline,
95 forced: self.forced,
96 },
97 existed,
98 )
99 }
100
101 fn scalar(self, value: Value) -> Result<Node, Error> {
103 if self.baseline == &value {
104 Ok(Node::Same)
105 } else {
106 if value.is_null() {
108 self.forced.set(true);
109 }
110 Ok(Node::Diff(value))
111 }
112 }
113}
114
115#[derive(Debug)]
117struct Error(String);
118
119impl std::fmt::Display for Error {
120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 f.write_str(&self.0)
122 }
123}
124
125impl std::error::Error for Error {}
126
127impl serde::ser::Error for Error {
128 fn custom<M: std::fmt::Display>(msg: M) -> Self {
129 Error(msg.to_string())
130 }
131}
132
133fn to_plain<T: Serialize + ?Sized>(value: &T) -> Result<Value, Error> {
135 serde_json::to_value(value).map_err(|e| Error(e.to_string()))
136}
137
138impl<'a> Serializer for Differ<'a> {
139 type Ok = Node;
140 type Error = Error;
141 type SerializeSeq = SeqDiff<'a>;
142 type SerializeTuple = SeqDiff<'a>;
143 type SerializeTupleStruct = SeqDiff<'a>;
144 type SerializeTupleVariant = VariantSeq<'a>;
145 type SerializeMap = MapDiff<'a>;
146 type SerializeStruct = MapDiff<'a>;
147 type SerializeStructVariant = VariantMap<'a>;
148
149 fn serialize_bool(self, v: bool) -> Result<Node, Error> {
150 self.scalar(Value::Bool(v))
151 }
152 fn serialize_i8(self, v: i8) -> Result<Node, Error> {
153 self.scalar(Value::from(v))
154 }
155 fn serialize_i16(self, v: i16) -> Result<Node, Error> {
156 self.scalar(Value::from(v))
157 }
158 fn serialize_i32(self, v: i32) -> Result<Node, Error> {
159 self.scalar(Value::from(v))
160 }
161 fn serialize_i64(self, v: i64) -> Result<Node, Error> {
162 self.scalar(Value::from(v))
163 }
164 fn serialize_i128(self, v: i128) -> Result<Node, Error> {
165 self.scalar(to_plain(&v)?)
166 }
167 fn serialize_u8(self, v: u8) -> Result<Node, Error> {
168 self.scalar(Value::from(v))
169 }
170 fn serialize_u16(self, v: u16) -> Result<Node, Error> {
171 self.scalar(Value::from(v))
172 }
173 fn serialize_u32(self, v: u32) -> Result<Node, Error> {
174 self.scalar(Value::from(v))
175 }
176 fn serialize_u64(self, v: u64) -> Result<Node, Error> {
177 self.scalar(Value::from(v))
178 }
179 fn serialize_u128(self, v: u128) -> Result<Node, Error> {
180 self.scalar(to_plain(&v)?)
181 }
182 fn serialize_f32(self, v: f32) -> Result<Node, Error> {
183 self.scalar(Value::from(v))
184 }
185 fn serialize_f64(self, v: f64) -> Result<Node, Error> {
186 self.scalar(Value::from(v))
187 }
188 fn serialize_char(self, v: char) -> Result<Node, Error> {
189 self.scalar(Value::from(v.to_string()))
190 }
191 fn serialize_str(self, v: &str) -> Result<Node, Error> {
192 if matches!(self.baseline, Value::String(b) if b == v) {
195 Ok(Node::Same)
196 } else {
197 Ok(Node::Diff(Value::from(v)))
198 }
199 }
200 fn serialize_bytes(self, v: &[u8]) -> Result<Node, Error> {
201 self.scalar(to_plain(v)?)
202 }
203 fn serialize_none(self) -> Result<Node, Error> {
204 self.scalar(Value::Null)
205 }
206 fn serialize_some<T: Serialize + ?Sized>(self, value: &T) -> Result<Node, Error> {
207 value.serialize(self)
208 }
209 fn serialize_unit(self) -> Result<Node, Error> {
210 self.scalar(Value::Null)
211 }
212 fn serialize_unit_struct(self, _name: &'static str) -> Result<Node, Error> {
213 self.scalar(Value::Null)
214 }
215 fn serialize_unit_variant(self, _name: &'static str, _idx: u32, variant: &'static str) -> Result<Node, Error> {
216 self.scalar(Value::from(variant))
217 }
218 fn serialize_newtype_struct<T: Serialize + ?Sized>(self, _name: &'static str, value: &T) -> Result<Node, Error> {
219 value.serialize(self)
220 }
221 fn serialize_newtype_variant<T: Serialize + ?Sized>(
222 self,
223 _name: &'static str,
224 _idx: u32,
225 variant: &'static str,
226 value: &T,
227 ) -> Result<Node, Error> {
228 variant_object(variant, to_plain(value)?).serialize(self)
232 }
233 fn serialize_seq(self, len: Option<usize>) -> Result<SeqDiff<'a>, Error> {
234 Ok(SeqDiff {
235 differ: self,
236 items: Vec::with_capacity(len.unwrap_or(0)),
237 })
238 }
239 fn serialize_tuple(self, len: usize) -> Result<SeqDiff<'a>, Error> {
240 self.serialize_seq(Some(len))
241 }
242 fn serialize_tuple_struct(self, _name: &'static str, len: usize) -> Result<SeqDiff<'a>, Error> {
243 self.serialize_seq(Some(len))
244 }
245 fn serialize_tuple_variant(
246 self,
247 _name: &'static str,
248 _idx: u32,
249 variant: &'static str,
250 len: usize,
251 ) -> Result<VariantSeq<'a>, Error> {
252 Ok(VariantSeq {
254 differ: self,
255 variant,
256 items: Vec::with_capacity(len),
257 })
258 }
259 fn serialize_map(self, _len: Option<usize>) -> Result<MapDiff<'a>, Error> {
260 Ok(MapDiff {
261 differ: self,
262 patch: Map::new(),
263 seen: Vec::new(),
264 added_key: false,
265 pending_key: None,
266 })
267 }
268 fn serialize_struct(self, _name: &'static str, len: usize) -> Result<MapDiff<'a>, Error> {
269 self.serialize_map(Some(len))
270 }
271 fn serialize_struct_variant(
272 self,
273 _name: &'static str,
274 _idx: u32,
275 variant: &'static str,
276 _len: usize,
277 ) -> Result<VariantMap<'a>, Error> {
278 Ok(VariantMap {
280 differ: self,
281 variant,
282 fields: Map::new(),
283 })
284 }
285}
286
287fn variant_object(variant: &str, value: Value) -> Value {
289 let mut object = Map::new();
290 object.insert(variant.to_owned(), value);
291 Value::Object(object)
292}
293
294struct VariantSeq<'a> {
296 differ: Differ<'a>,
297 variant: &'static str,
298 items: Vec<Value>,
299}
300
301impl serde::ser::SerializeTupleVariant for VariantSeq<'_> {
302 type Ok = Node;
303 type Error = Error;
304 fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
305 self.items.push(to_plain(value)?);
306 Ok(())
307 }
308 fn end(self) -> Result<Node, Error> {
309 variant_object(self.variant, Value::Array(self.items)).serialize(self.differ)
310 }
311}
312
313struct VariantMap<'a> {
315 differ: Differ<'a>,
316 variant: &'static str,
317 fields: Map<String, Value>,
318}
319
320impl serde::ser::SerializeStructVariant for VariantMap<'_> {
321 type Ok = Node;
322 type Error = Error;
323 fn serialize_field<T: Serialize + ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error> {
324 self.fields.insert(key.to_owned(), to_plain(value)?);
325 Ok(())
326 }
327 fn end(self) -> Result<Node, Error> {
328 variant_object(self.variant, Value::Object(self.fields)).serialize(self.differ)
329 }
330}
331
332struct SeqDiff<'a> {
335 differ: Differ<'a>,
336 items: Vec<Value>,
337}
338
339impl SerializeSeq for SeqDiff<'_> {
340 type Ok = Node;
341 type Error = Error;
342 fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
343 self.items.push(to_plain(value)?);
344 Ok(())
345 }
346 fn end(self) -> Result<Node, Error> {
347 self.differ.scalar(Value::Array(self.items))
348 }
349}
350
351impl serde::ser::SerializeTuple for SeqDiff<'_> {
352 type Ok = Node;
353 type Error = Error;
354 fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
355 SerializeSeq::serialize_element(self, value)
356 }
357 fn end(self) -> Result<Node, Error> {
358 SerializeSeq::end(self)
359 }
360}
361
362impl serde::ser::SerializeTupleStruct for SeqDiff<'_> {
363 type Ok = Node;
364 type Error = Error;
365 fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
366 SerializeSeq::serialize_element(self, value)
367 }
368 fn end(self) -> Result<Node, Error> {
369 SerializeSeq::end(self)
370 }
371}
372
373struct MapDiff<'a> {
376 differ: Differ<'a>,
377 patch: Map<String, Value>,
378 seen: Vec<String>,
379 added_key: bool,
382 pending_key: Option<String>,
383}
384
385impl MapDiff<'_> {
386 fn entry(&mut self, key: String, existed: bool, node: Node) {
387 self.added_key |= !existed;
388 if let Node::Diff(value) = node {
389 self.patch.insert(key.clone(), value);
390 }
391 self.seen.push(key);
392 }
393
394 fn finish(self) -> Result<Node, Error> {
395 let mut patch = self.patch;
396 if let Value::Object(base) = self.differ.baseline {
397 if self.added_key || self.seen.len() != base.len() {
402 let seen: HashSet<&str> = self.seen.iter().map(String::as_str).collect();
403 for key in base.keys() {
404 if !seen.contains(key.as_str()) {
405 patch.insert(key.clone(), Value::Null);
406 }
407 }
408 }
409 }
410 if patch.is_empty() {
411 Ok(Node::Same)
412 } else {
413 Ok(Node::Diff(Value::Object(patch)))
414 }
415 }
416}
417
418impl SerializeMap for MapDiff<'_> {
419 type Ok = Node;
420 type Error = Error;
421 fn serialize_key<T: Serialize + ?Sized>(&mut self, key: &T) -> Result<(), Error> {
422 self.pending_key = Some(key.serialize(KeySer)?);
424 Ok(())
425 }
426 fn serialize_value<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
427 let key = self.pending_key.take().expect("serialize_key precedes serialize_value");
428 let (child, existed) = self.differ.child(&key);
429 let node = value.serialize(child)?;
430 self.entry(key, existed, node);
431 Ok(())
432 }
433 fn end(self) -> Result<Node, Error> {
434 self.finish()
435 }
436}
437
438impl SerializeStruct for MapDiff<'_> {
439 type Ok = Node;
440 type Error = Error;
441 fn serialize_field<T: Serialize + ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error> {
442 let (child, existed) = self.differ.child(key);
443 let node = value.serialize(child)?;
444 self.entry(key.to_owned(), existed, node);
445 Ok(())
446 }
447 fn end(self) -> Result<Node, Error> {
450 self.finish()
451 }
452}
453
454struct KeySer;
457
458impl Serializer for KeySer {
459 type Ok = String;
460 type Error = Error;
461 type SerializeSeq = Impossible<String, Error>;
462 type SerializeTuple = Impossible<String, Error>;
463 type SerializeTupleStruct = Impossible<String, Error>;
464 type SerializeTupleVariant = Impossible<String, Error>;
465 type SerializeMap = Impossible<String, Error>;
466 type SerializeStruct = Impossible<String, Error>;
467 type SerializeStructVariant = Impossible<String, Error>;
468
469 fn serialize_str(self, v: &str) -> Result<String, Error> {
470 Ok(v.to_owned())
471 }
472 fn serialize_char(self, v: char) -> Result<String, Error> {
473 Ok(v.to_string())
474 }
475 fn serialize_bool(self, v: bool) -> Result<String, Error> {
476 Ok(v.to_string())
477 }
478 fn serialize_i8(self, v: i8) -> Result<String, Error> {
479 Ok(v.to_string())
480 }
481 fn serialize_i16(self, v: i16) -> Result<String, Error> {
482 Ok(v.to_string())
483 }
484 fn serialize_i32(self, v: i32) -> Result<String, Error> {
485 Ok(v.to_string())
486 }
487 fn serialize_i64(self, v: i64) -> Result<String, Error> {
488 Ok(v.to_string())
489 }
490 fn serialize_u8(self, v: u8) -> Result<String, Error> {
491 Ok(v.to_string())
492 }
493 fn serialize_u16(self, v: u16) -> Result<String, Error> {
494 Ok(v.to_string())
495 }
496 fn serialize_u32(self, v: u32) -> Result<String, Error> {
497 Ok(v.to_string())
498 }
499 fn serialize_u64(self, v: u64) -> Result<String, Error> {
500 Ok(v.to_string())
501 }
502 fn serialize_unit_variant(self, _name: &'static str, _idx: u32, variant: &'static str) -> Result<String, Error> {
503 Ok(variant.to_owned())
504 }
505 fn serialize_newtype_struct<T: Serialize + ?Sized>(self, _name: &'static str, value: &T) -> Result<String, Error> {
506 value.serialize(self)
507 }
508 fn serialize_some<T: Serialize + ?Sized>(self, value: &T) -> Result<String, Error> {
509 value.serialize(self)
510 }
511 fn serialize_f32(self, _v: f32) -> Result<String, Error> {
512 Err(Error("float map key".into()))
513 }
514 fn serialize_f64(self, _v: f64) -> Result<String, Error> {
515 Err(Error("float map key".into()))
516 }
517 fn serialize_bytes(self, _v: &[u8]) -> Result<String, Error> {
518 Err(Error("bytes map key".into()))
519 }
520 fn serialize_none(self) -> Result<String, Error> {
521 Err(Error("null map key".into()))
522 }
523 fn serialize_unit(self) -> Result<String, Error> {
524 Err(Error("unit map key".into()))
525 }
526 fn serialize_unit_struct(self, _name: &'static str) -> Result<String, Error> {
527 Err(Error("unit struct map key".into()))
528 }
529 fn serialize_newtype_variant<T: Serialize + ?Sized>(
530 self,
531 _name: &'static str,
532 _idx: u32,
533 _variant: &'static str,
534 _value: &T,
535 ) -> Result<String, Error> {
536 Err(Error("newtype variant map key".into()))
537 }
538 fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Error> {
539 Err(Error("seq map key".into()))
540 }
541 fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Error> {
542 Err(Error("tuple map key".into()))
543 }
544 fn serialize_tuple_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeTupleStruct, Error> {
545 Err(Error("tuple struct map key".into()))
546 }
547 fn serialize_tuple_variant(
548 self,
549 _name: &'static str,
550 _idx: u32,
551 _variant: &'static str,
552 _len: usize,
553 ) -> Result<Self::SerializeTupleVariant, Error> {
554 Err(Error("tuple variant map key".into()))
555 }
556 fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Error> {
557 Err(Error("map map key".into()))
558 }
559 fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct, Error> {
560 Err(Error("struct map key".into()))
561 }
562 fn serialize_struct_variant(
563 self,
564 _name: &'static str,
565 _idx: u32,
566 _variant: &'static str,
567 _len: usize,
568 ) -> Result<Self::SerializeStructVariant, Error> {
569 Err(Error("struct variant map key".into()))
570 }
571}
572
573#[cfg(test)]
574mod test {
575 use super::*;
576 use serde_json::json;
577
578 fn reference(old: &Value, new: &Value) -> Diff {
581 fn objects(
582 old: &Map<String, Value>,
583 new: &Map<String, Value>,
584 patch: &mut Map<String, Value>,
585 forced: &mut bool,
586 ) {
587 for key in old.keys() {
588 if !new.contains_key(key) {
589 patch.insert(key.clone(), Value::Null);
590 }
591 }
592 for (key, new_val) in new {
593 let old_val = old.get(key);
594 if old_val == Some(new_val) {
595 continue;
596 }
597 if let (Some(Value::Object(old_obj)), Value::Object(new_obj)) = (old_val, new_val) {
598 let mut sub = Map::new();
599 objects(old_obj, new_obj, &mut sub, forced);
600 if !sub.is_empty() {
601 patch.insert(key.clone(), Value::Object(sub));
602 }
603 continue;
604 }
605 if new_val.is_null() {
606 *forced = true;
607 }
608 patch.insert(key.clone(), new_val.clone());
609 }
610 }
611
612 if let (Value::Object(old_obj), Value::Object(new_obj)) = (old, new) {
613 let mut patch = Map::new();
614 let mut forced = false;
615 objects(old_obj, new_obj, &mut patch, &mut forced);
616 Diff {
617 patch: Value::Object(patch),
618 forced_snapshot: forced,
619 }
620 } else {
621 Diff {
622 patch: new.clone(),
623 forced_snapshot: true,
624 }
625 }
626 }
627
628 fn check(old: Value, new: Value) {
631 let want = reference(&old, &new);
632 let got = diff(&old, &new);
633 assert_eq!(got.patch, want.patch, "patch mismatch for {old} -> {new}");
634 assert_eq!(
635 got.forced_snapshot, want.forced_snapshot,
636 "forced mismatch for {old} -> {new}"
637 );
638 if !got.forced_snapshot {
639 let mut applied = old.clone();
640 json_patch::merge(&mut applied, &got.patch);
641 assert_eq!(applied, new, "patch did not roundtrip for {old} -> {new}");
642 }
643 }
644
645 #[test]
646 fn changed_scalar() {
647 check(json!({ "a": 1, "b": 2 }), json!({ "a": 1, "b": 3 }));
648 }
649
650 #[test]
651 fn added_key() {
652 let result = diff(&json!({ "a": 1 }), &json!({ "a": 1, "b": 2 }));
653 assert!(!result.forced_snapshot);
654 assert_eq!(result.patch, json!({ "b": 2 }));
655 check(json!({ "a": 1 }), json!({ "a": 1, "b": 2 }));
656 }
657
658 #[test]
659 fn removed_key_is_null() {
660 let result = diff(&json!({ "a": 1, "b": 2 }), &json!({ "a": 1 }));
661 assert!(!result.forced_snapshot, "removing a key is a clean delete");
662 assert_eq!(result.patch, json!({ "b": null }));
663 check(json!({ "a": 1, "b": 2 }), json!({ "a": 1 }));
664 }
665
666 #[test]
667 fn nested_object_only_includes_changed_keys() {
668 let result = diff(&json!({ "o": { "x": 1, "y": 2 } }), &json!({ "o": { "x": 1, "y": 9 } }));
669 assert!(!result.forced_snapshot);
670 assert_eq!(result.patch, json!({ "o": { "y": 9 } }));
671 check(json!({ "o": { "x": 1, "y": 2 } }), json!({ "o": { "x": 1, "y": 9 } }));
672 }
673
674 #[test]
675 fn unchanged_object_is_empty_patch() {
676 let result = diff(&json!({ "a": 1, "o": { "x": 1 } }), &json!({ "a": 1, "o": { "x": 1 } }));
677 assert!(!result.forced_snapshot);
678 assert_eq!(result.patch, json!({}));
679 }
680
681 #[test]
682 fn changed_array_is_wholesale_delta() {
683 let result = diff(&json!({ "a": [1, 2] }), &json!({ "a": [1, 2, 3] }));
684 assert!(!result.forced_snapshot);
685 assert_eq!(result.patch, json!({ "a": [1, 2, 3] }));
686 check(json!({ "a": [1, 2] }), json!({ "a": [1, 2, 3] }));
687 }
688
689 #[test]
690 fn unchanged_array_is_pruned() {
691 let result = diff(&json!({ "a": [1, 2, 3], "b": 1 }), &json!({ "a": [1, 2, 3], "b": 2 }));
692 assert_eq!(
693 result.patch,
694 json!({ "b": 2 }),
695 "an unchanged array stays out of the patch"
696 );
697 }
698
699 #[test]
700 fn added_array_is_delta() {
701 check(json!({ "a": 1 }), json!({ "a": 1, "b": [1] }));
702 }
703
704 #[test]
705 fn nested_array_is_delta() {
706 check(json!({ "o": { "x": 1 } }), json!({ "o": { "x": 1, "list": [1] } }));
707 }
708
709 #[test]
710 fn array_of_objects_replaces_wholesale() {
711 check(
712 json!({ "items": [{ "id": 1, "v": 1 }, { "id": 2, "v": 2 }] }),
713 json!({ "items": [{ "id": 1, "v": 9 }, { "id": 2, "v": 2 }] }),
714 );
715 }
716
717 #[test]
718 fn set_to_null_forces_snapshot() {
719 let result = diff(&json!({ "a": 1 }), &json!({ "a": null }));
721 assert!(result.forced_snapshot);
722 assert!(reference(&json!({ "a": 1 }), &json!({ "a": null })).forced_snapshot);
723 }
724
725 #[test]
726 fn nested_null_forces_snapshot() {
727 let old = json!({ "o": { "x": 1 } });
728 let new = json!({ "o": { "x": null } });
729 assert!(diff(&old, &new).forced_snapshot);
730 assert_eq!(diff(&old, &new).forced_snapshot, reference(&old, &new).forced_snapshot);
731 }
732
733 #[test]
734 fn replacing_object_with_scalar() {
735 check(json!({ "a": { "x": 1 } }), json!({ "a": 5 }));
736 }
737
738 #[test]
739 fn replacing_scalar_with_object() {
740 check(json!({ "a": 5 }), json!({ "a": { "x": 1 } }));
741 }
742
743 #[test]
744 fn non_object_root_forces_snapshot() {
745 let result = diff(&json!(1), &json!(2));
746 assert!(result.forced_snapshot);
747 assert_eq!(result.patch, json!(2));
748 }
749
750 #[test]
751 fn array_root_forces_snapshot() {
752 let result = diff(&json!([1, 2]), &json!([1, 2, 3]));
753 assert!(result.forced_snapshot);
754 assert_eq!(result.patch, json!([1, 2, 3]));
755 }
756
757 #[test]
758 fn unchanged_scalar_root_is_not_forced() {
759 let result = diff(&json!(7), &json!(7));
761 assert!(!result.forced_snapshot);
762 assert_eq!(result.patch, json!({}));
763 }
764
765 #[test]
766 fn floats_and_bools_and_strings() {
767 check(
768 json!({ "f": 1.5, "b": true, "s": "hi" }),
769 json!({ "f": 2.5, "b": false, "s": "bye" }),
770 );
771 }
772
773 #[derive(serde::Serialize, serde::Deserialize, Default, PartialEq, Debug)]
776 struct Doc {
777 #[serde(skip_serializing_if = "Option::is_none")]
778 video: Option<String>,
779 #[serde(skip_serializing_if = "Option::is_none")]
780 scte35: Option<u32>,
781 count: u64,
782 tags: Vec<String>,
783 }
784
785 fn check_struct(old: &Doc, new: &Doc) {
787 let old_value = serde_json::to_value(old).unwrap();
788 let result = diff(&old_value, new);
789
790 let new_value = serde_json::to_value(new).unwrap();
792 let want = reference(&old_value, &new_value);
793 assert_eq!(result.patch, want.patch, "struct patch differs from oracle");
794 assert_eq!(result.forced_snapshot, want.forced_snapshot);
795
796 if !result.forced_snapshot {
797 let mut applied = old_value;
798 json_patch::merge(&mut applied, &result.patch);
799 assert_eq!(applied, new_value, "struct patch did not roundtrip");
800 }
801 }
802
803 #[test]
804 fn struct_field_change() {
805 check_struct(
806 &Doc {
807 count: 1,
808 tags: vec!["a".into()],
809 ..Default::default()
810 },
811 &Doc {
812 count: 2,
813 tags: vec!["a".into()],
814 ..Default::default()
815 },
816 );
817 }
818
819 #[test]
820 fn struct_option_some_to_none_is_deletion() {
821 let result = diff(
823 &serde_json::to_value(Doc {
824 video: Some("v1".into()),
825 count: 1,
826 ..Default::default()
827 })
828 .unwrap(),
829 &Doc {
830 video: None,
831 count: 1,
832 ..Default::default()
833 },
834 );
835 assert!(!result.forced_snapshot, "deleting a skipped key is clean");
836 assert_eq!(result.patch, json!({ "video": null }));
837 check_struct(
838 &Doc {
839 video: Some("v1".into()),
840 count: 1,
841 ..Default::default()
842 },
843 &Doc {
844 video: None,
845 count: 1,
846 ..Default::default()
847 },
848 );
849 }
850
851 #[test]
852 fn struct_option_none_to_some_is_addition() {
853 check_struct(
854 &Doc {
855 count: 1,
856 ..Default::default()
857 },
858 &Doc {
859 scte35: Some(42),
860 count: 1,
861 ..Default::default()
862 },
863 );
864 }
865
866 #[test]
867 fn struct_unchanged_is_empty_patch() {
868 let doc = Doc {
869 video: Some("v".into()),
870 scte35: Some(1),
871 count: 7,
872 tags: vec!["x".into(), "y".into()],
873 };
874 let result = diff(&serde_json::to_value(&doc).unwrap(), &doc);
875 assert!(!result.forced_snapshot);
876 assert_eq!(result.patch, json!({}));
877 }
878
879 #[test]
880 fn struct_vec_changes_wholesale() {
881 check_struct(
882 &Doc {
883 count: 1,
884 tags: vec!["a".into(), "b".into()],
885 ..Default::default()
886 },
887 &Doc {
888 count: 1,
889 tags: vec!["a".into(), "c".into()],
890 ..Default::default()
891 },
892 );
893 }
894
895 #[derive(serde::Serialize)]
896 struct Nested {
897 inner: Inner,
898 name: String,
899 }
900 #[derive(serde::Serialize)]
901 struct Inner {
902 a: u32,
903 b: u32,
904 }
905
906 #[test]
907 fn nested_struct_only_changed_field() {
908 let old = serde_json::to_value(Nested {
909 inner: Inner { a: 1, b: 2 },
910 name: "n".into(),
911 })
912 .unwrap();
913 let new = Nested {
914 inner: Inner { a: 1, b: 9 },
915 name: "n".into(),
916 };
917 let result = diff(&old, &new);
918 assert_eq!(result.patch, json!({ "inner": { "b": 9 } }));
919 assert!(!result.forced_snapshot);
920 }
921
922 #[derive(serde::Serialize)]
923 enum Tag {
924 Active,
925 Idle,
926 }
927
928 #[derive(serde::Serialize)]
929 struct Stated {
930 state: Tag,
931 seq: u32,
932 }
933
934 #[test]
935 fn unit_enum_variant_is_string() {
936 let old = serde_json::to_value(Stated {
938 state: Tag::Active,
939 seq: 1,
940 })
941 .unwrap();
942 assert_eq!(old, json!({ "state": "Active", "seq": 1 }));
943 let result = diff(
944 &old,
945 &Stated {
946 state: Tag::Idle,
947 seq: 1,
948 },
949 );
950 assert!(!result.forced_snapshot);
951 assert_eq!(result.patch, json!({ "state": "Idle" }));
952 }
953
954 fn check_typed<T: Serialize>(old: &Value, new: &T) {
957 let new_value = serde_json::to_value(new).unwrap();
958 let want = reference(old, &new_value);
959 let got = diff(old, new);
960 assert_eq!(got.patch, want.patch, "patch differs from oracle");
961 assert_eq!(got.forced_snapshot, want.forced_snapshot, "forced differs from oracle");
962 if !got.forced_snapshot {
963 let mut applied = old.clone();
964 json_patch::merge(&mut applied, &got.patch);
965 assert_eq!(applied, new_value, "patch did not roundtrip");
966 }
967 }
968
969 #[derive(serde::Serialize)]
970 enum Payload {
971 Newtype(u32),
972 Tuple(u32, String),
973 Struct { x: u32, y: u32 },
974 }
975
976 #[derive(serde::Serialize)]
977 struct Holder {
978 payload: Payload,
979 seq: u32,
980 }
981
982 #[test]
983 fn newtype_variant_keeps_its_tag() {
984 let old = serde_json::to_value(Holder {
986 payload: Payload::Newtype(1),
987 seq: 0,
988 })
989 .unwrap();
990 assert_eq!(old, json!({ "payload": { "Newtype": 1 }, "seq": 0 }));
991 let result = diff(
992 &old,
993 &Holder {
994 payload: Payload::Newtype(2),
995 seq: 0,
996 },
997 );
998 assert_eq!(result.patch, json!({ "payload": { "Newtype": 2 } }));
999 check_typed(
1000 &old,
1001 &Holder {
1002 payload: Payload::Newtype(2),
1003 seq: 0,
1004 },
1005 );
1006 }
1007
1008 #[test]
1009 fn tuple_variant_keeps_its_tag() {
1010 let old = serde_json::to_value(Holder {
1011 payload: Payload::Tuple(1, "a".into()),
1012 seq: 0,
1013 })
1014 .unwrap();
1015 assert_eq!(old, json!({ "payload": { "Tuple": [1, "a"] }, "seq": 0 }));
1016 check_typed(
1017 &old,
1018 &Holder {
1019 payload: Payload::Tuple(2, "a".into()),
1020 seq: 0,
1021 },
1022 );
1023 }
1024
1025 #[test]
1026 fn struct_variant_keeps_its_tag() {
1027 let old = serde_json::to_value(Holder {
1028 payload: Payload::Struct { x: 1, y: 2 },
1029 seq: 0,
1030 })
1031 .unwrap();
1032 assert_eq!(old, json!({ "payload": { "Struct": { "x": 1, "y": 2 } }, "seq": 0 }));
1033 check_typed(
1034 &old,
1035 &Holder {
1036 payload: Payload::Struct { x: 1, y: 9 },
1037 seq: 0,
1038 },
1039 );
1040 }
1041
1042 #[derive(serde::Deserialize)]
1043 struct Vector {
1044 name: String,
1045 old: Value,
1046 new: Value,
1047 forced: bool,
1048 patch: Option<Value>,
1049 }
1050
1051 #[test]
1054 fn golden_vectors() {
1055 let vectors: Vec<Vector> = serde_json::from_str(include_str!("../tests/vectors.json")).unwrap();
1056 for case in vectors {
1057 let result = diff(&case.old, &case.new);
1058 assert_eq!(result.forced_snapshot, case.forced, "{}: forced_snapshot", case.name);
1059
1060 if let Some(expected) = case.patch {
1061 assert_eq!(result.patch, expected, "{}: patch", case.name);
1062 let mut applied = case.old.clone();
1063 json_patch::merge(&mut applied, &result.patch);
1064 assert_eq!(applied, case.new, "{}: roundtrip", case.name);
1065 }
1066 }
1067 }
1068
1069 #[test]
1072 fn evolving_document_matches_oracle() {
1073 let mut docs = Vec::new();
1074 for tick in 0u64..40 {
1075 docs.push(json!({
1076 "id": "device-1",
1077 "static": { "model": "x", "tags": ["a", "b", "c"] },
1078 "counters": { "n": tick, "errors": tick / 10 },
1079 "reading": (tick as f64 * 0.5),
1080 "flags": { "online": tick % 2 == 0, "charging": tick % 3 == 0 },
1081 "list": [tick, tick + 1],
1082 }));
1083 }
1084 for pair in docs.windows(2) {
1085 check(pair[0].clone(), pair[1].clone());
1086 }
1087 }
1088}