1use serde::{Deserialize, Deserializer, Serialize};
2use std::borrow::Cow;
3use std::fmt::Debug;
4use std::marker::PhantomData;
5
6use indexmap::{IndexMap, IndexSet};
7use serde::__private::de::{Content, ContentRefDeserializer};
8use serde_json::Value;
9use std::ops::Deref;
10use std::sync::Arc;
11
12pub trait Prepare {
13 fn prepare(self) -> Self;
14}
15
16pub trait DiffContext {
17 fn removing(&self) -> Self;
18 fn switch_flow(&self) -> Self;
19
20 fn is_direct_flow(&self) -> bool;
21
22 fn add_visited_reference_source(&self, reference: &str) -> Self;
23 fn check_visited_reference_source(&self, reference: &str) -> usize;
24 fn add_visited_reference_target(&self, reference: &str) -> Self;
25 fn check_visited_reference_target(&self, reference: &str) -> usize;
26}
27
28pub trait ComponentContainer<T> {
29 fn deref_source(&self, reference: &str) -> Option<&T>;
30 fn deref_target(&self, reference: &str) -> Option<&T>;
31}
32
33pub trait DiffCache<O> {
34 fn get_diff(&self, reference: &str) -> Option<Arc<DiffResult<O>>>;
35 fn set_diff(&self, reference: &str, component: Arc<DiffResult<O>>);
36}
37
38#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
39#[serde(rename_all = "lowercase", tag = "t", content = "v")]
40pub enum DiffResult<T> {
41 #[serde(rename = "n")]
42 None,
43 #[serde(rename = "=")]
44 Same(T),
45 #[serde(rename = "+")]
46 Added(T),
47 #[serde(rename = "~")]
48 Updated(T, Option<Box<T>>),
49 #[serde(rename = "-")]
50 Removed(T),
51}
52
53impl<T> DiffResult<T> {
54 pub fn is_none(&self) -> bool {
55 matches!(self, DiffResult::None)
56 }
57
58 pub fn is_same(&self) -> bool {
59 matches!(self, DiffResult::Same(_))
60 }
61
62 pub fn is_added(&self) -> bool {
63 matches!(self, DiffResult::Added(_))
64 }
65
66 pub fn is_updated(&self) -> bool {
67 matches!(self, DiffResult::Updated(_, _))
68 }
69
70 pub fn is_upserted(&self) -> bool {
71 self.is_added() || self.is_updated()
72 }
73
74 pub fn is_removed(&self) -> bool {
75 matches!(self, DiffResult::Removed(_))
76 }
77
78 pub fn is_same_or_none(&self) -> bool {
79 self.is_same() || self.is_none()
80 }
81
82 pub fn exists(&self) -> bool {
83 !(self.is_none() || self.is_removed())
84 }
85
86 pub fn new<C: DiffContext>(mut value: DiffResult<T>, context: &C) -> Self {
87 if !context.is_direct_flow() {
88 value = match value {
89 DiffResult::Added(v) => DiffResult::Removed(v),
90 DiffResult::Removed(v) => DiffResult::Added(v),
91
92 DiffResult::Updated(new, Some(old)) => {
93 DiffResult::Updated(*old, Some(Box::new(new)))
94 }
95 result => result,
96 }
97 }
98
99 value
100 }
101
102 pub fn get(&self) -> Option<&T> {
103 match self {
104 DiffResult::None => None,
105
106 DiffResult::Same(v) => Some(v),
107 DiffResult::Added(v) => Some(v),
108 DiffResult::Removed(v) => Some(v),
109 DiffResult::Updated(v, _) => Some(v),
110 }
111 }
112
113 pub fn take(self) -> Option<T> {
114 match self {
115 DiffResult::None => None,
116
117 DiffResult::Same(v) => Some(v),
118 DiffResult::Added(v) => Some(v),
119 DiffResult::Removed(v) => Some(v),
120 DiffResult::Updated(v, _) => Some(v),
121 }
122 }
123
124 pub fn as_ref(&self) -> DiffResult<&T> {
125 match &self {
126 DiffResult::None => DiffResult::None,
127 DiffResult::Same(v) => DiffResult::Same(v),
128 DiffResult::Added(v) => DiffResult::Added(v),
129 DiffResult::Removed(v) => DiffResult::Removed(v),
130
131 DiffResult::Updated(new, old) => DiffResult::Updated(
132 new,
133 old.as_ref().map(|old| Box::new(&**old)),
134 ),
135 }
136 }
137}
138
139pub trait Referencable {}
141
142impl Referencable for Value {}
143
144pub trait Diff<With, Output, Context: DiffContext> {
145 fn diff(
146 &self,
147 new: Option<&With>,
148 context: &Context,
149 ) -> DiffResult<Output>;
150}
151
152pub trait Empty {
153 fn is_empty(&self) -> bool;
154}
155
156pub trait Keyed<C> {
157 fn key(&self, c: C) -> String;
158}
159
160impl<T, O, C: DiffContext> Diff<T, O, C> for Option<T>
161where
162 T: Diff<T, O, C> + Debug,
163{
164 fn diff(&self, new: Option<&T>, context: &C) -> DiffResult<O> {
165 match (self, new) {
166 (None, None) => DiffResult::new(DiffResult::None, context),
167 (Some(v1), Some(v2)) => v1.diff(Some(v2), context),
168 (Some(v1), None) => v1.diff(None, context),
169 (None, Some(v2)) => {
170 if context.is_direct_flow() {
171 v2.diff(None, &context.switch_flow())
172 } else {
173 v2.diff(None, context)
174 }
175 }
176 }
177 }
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize)]
181#[serde(untagged)]
182pub enum Either<L, R> {
183 Left(L),
184 Right(Box<R>),
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
188#[serde(rename_all = "lowercase", tag = "t", content = "v")]
189pub enum EitherDiff<LD, RD> {
190 #[serde(rename = "l")]
191 Left(DiffResult<LD>),
192 #[serde(rename = "r")]
193 Right(Box<DiffResult<RD>>),
194
195 #[serde(rename = "tr")]
196 ToRight(Box<DiffResult<RD>>),
197 #[serde(rename = "tl")]
198 ToLeft(Box<DiffResult<LD>>),
199}
200
201impl<LD, RD> Empty for EitherDiff<LD, RD> {
202 fn is_empty(&self) -> bool {
203 match self {
204 EitherDiff::Left(l) => l.is_same_or_none(),
205 EitherDiff::Right(r) => r.is_same_or_none(),
206 _ => false,
207 }
208 }
209}
210
211impl<L, R, LD, RD, C: DiffContext> Diff<Either<L, R>, EitherDiff<LD, RD>, C>
212 for Either<L, R>
213where
214 L: Diff<L, LD, C>,
215 R: Diff<R, RD, C>,
216{
217 fn diff(
218 &self,
219 new: Option<&Either<L, R>>,
220 context: &C,
221 ) -> DiffResult<EitherDiff<LD, RD>> {
222 let diff = match new {
223 None => DiffResult::Removed(match self {
224 Either::Left(l) => {
225 EitherDiff::Left(l.diff(None, &context.removing()))
226 }
227 Either::Right(r) => EitherDiff::Right(Box::new(
228 r.diff(None, &context.removing()),
229 )),
230 }),
231 Some(value) => {
232 let diff = match value {
233 Either::Left(vl) => match self {
234 Either::Left(l) => {
235 EitherDiff::Left(l.diff(Option::from(vl), context))
236 }
237 Either::Right(_) => EitherDiff::ToLeft(Box::new(
238 vl.diff(None, context),
239 )),
240 },
241 Either::Right(vr) => match self {
242 Either::Left(_) => EitherDiff::ToRight(Box::new(
243 vr.diff(None, context),
244 )),
245 Either::Right(r) => EitherDiff::Right(Box::new(
246 r.diff(Some(vr), context),
247 )),
248 },
249 };
250
251 if diff.is_empty() {
252 DiffResult::Same(diff)
253 } else {
254 DiffResult::Updated(diff, None)
255 }
256 }
257 };
258 DiffResult::new(diff, context)
259 }
260}
261
262pub trait ReferenceDescriptor {
263 fn reference(&self) -> &str;
264}
265
266#[derive(Debug, Clone, Serialize)]
267#[serde(untagged)]
268pub enum MayBeRefCore<T, R: ReferenceDescriptor> {
269 Ref(R),
270 Value(T),
271}
272
273impl<'de, T, R: ReferenceDescriptor> Deserialize<'de> for MayBeRefCore<T, R>
274where
275 T: Deserialize<'de>,
276 R: Deserialize<'de>,
277{
278 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
279 where
280 D: Deserializer<'de>,
281 {
282 let content = match <Content as Deserialize>::deserialize(deserializer)
283 {
284 Ok(val) => val,
285 Err(err) => {
286 return Err(err);
287 }
288 };
289
290 if let Ok(ok) = Result::map(
291 <R as Deserialize>::deserialize(
292 ContentRefDeserializer::<D::Error>::new(&content),
293 ),
294 MayBeRefCore::Ref,
295 ) {
296 return Ok(ok);
297 }
298
299 let mut track = serde_path_to_error::Track::new();
300 let de = serde_path_to_error::Deserializer::new(
301 ContentRefDeserializer::<D::Error>::new(&content),
302 &mut track,
303 );
304
305 match <T as Deserialize>::deserialize(de) {
306 Ok(t) => Ok(MayBeRefCore::Value(t)),
307 Err(err) => {
308 eprintln!("Err path: {} --- {}", track.path(), &err);
309 Err(err)
310 }
311 }
312 }
313}
314
315impl<T, R: ReferenceDescriptor> MayBeRefCore<T, R> {
316 pub fn is_ref(&self) -> bool {
317 matches!(self, MayBeRefCore::Ref(_))
318 }
319
320 pub fn reference(&self) -> Option<&str> {
321 match self {
322 MayBeRefCore::Ref(rd) => Some(rd.reference()),
323 _ => None,
324 }
325 }
326
327 pub fn value(&self) -> Option<&T> {
328 match self {
329 MayBeRefCore::Value(v) => Some(v),
330 _ => None,
331 }
332 }
333
334 pub fn value_mut(&mut self) -> Option<&mut T> {
335 match self {
336 MayBeRefCore::Value(v) => Some(v),
337 _ => None,
338 }
339 }
340}
341
342#[derive(Debug, Clone, Serialize, Deserialize)]
343#[serde(rename_all = "lowercase", tag = "t", content = "v")]
344pub enum MayBeRefCoreDiff<T: Referencable, R: ReferenceDescriptor> {
345 #[serde(rename = "r")]
346 Ref(R),
347 #[serde(rename = "v")]
348 Value(Arc<DiffResult<T>>),
349}
350
351impl<T, R> Keyed<usize> for MayBeRefCore<T, R>
352where
353 T: Keyed<usize>,
354 R: ReferenceDescriptor,
355{
356 fn key(&self, c: usize) -> String {
357 match self {
358 MayBeRefCore::Value(value) => value.key(c),
359 MayBeRefCore::Ref(value) => value.reference().to_owned(),
360 }
361 }
362}
363
364impl<T, O, R, C: DiffContext>
365 Diff<MayBeRefCore<T, R>, MayBeRefCoreDiff<O, R>, C> for MayBeRefCore<T, R>
366where
367 T: Diff<T, O, C> + Clone + Debug + 'static,
368 O: Referencable + Clone + Debug + 'static,
369 R: ReferenceDescriptor + Clone + Debug + 'static,
370 C: DiffContext + ComponentContainer<T> + DiffCache<O> + ToOwned<Owned = C>,
371{
372 fn diff(
373 &self,
374 new: Option<&MayBeRefCore<T, R>>,
375 context: &C,
376 ) -> DiffResult<MayBeRefCoreDiff<O, R>> {
377 let diff = match new {
378 None => DiffResult::Removed(match self {
379 MayBeRefCore::Ref(value) => {
380 MayBeRefCoreDiff::Ref(value.clone())
381 }
382 MayBeRefCore::Value(value) => MayBeRefCoreDiff::Value(
383 Arc::new(value.diff(None, context)),
384 ),
385 }),
386 Some(value) => {
387 let cached_diff = if let (
388 MayBeRefCore::Ref(old_ref),
389 MayBeRefCore::Ref(new_ref),
390 ) = (self, value)
391 {
392 if old_ref.reference() == new_ref.reference() {
393 context.get_diff(old_ref.reference())
394 } else {
395 None
396 }
397 } else {
398 None
399 };
400
401 let diff = if let Some(diff) = &cached_diff {
402 Arc::clone(diff)
403 } else {
404 let context =
405 if let MayBeRefCore::Ref(old_ref) = self {
406 Cow::Owned(context.add_visited_reference_source(
407 old_ref.reference(),
408 ))
409 } else {
410 Cow::Borrowed(context)
411 };
412 let context =
413 if let MayBeRefCore::Ref(new_ref) = value {
414 Cow::Owned(context.add_visited_reference_target(
415 new_ref.reference(),
416 ))
417 } else {
418 context
419 };
420
421 let (old_value, new_value) = match (self, value) {
422 (
423 MayBeRefCore::Ref(old_ref),
424 MayBeRefCore::Ref(new_ref),
425 ) => {
426 let old_reference = old_ref.reference();
427 let new_reference = new_ref.reference();
428
429 let old_visited_count = context
430 .check_visited_reference_source(old_reference);
431 let new_visited_count = context
432 .check_visited_reference_target(new_reference);
433
434 if old_visited_count > 1 && new_visited_count > 1 {
435 return DiffResult::None;
436 }
437
438 let source = context.deref_source(old_reference);
439 let target = context.deref_target(new_reference);
440
441 (source, target)
442 }
443 (
444 MayBeRefCore::Value(old_value),
445 MayBeRefCore::Value(new_value),
446 ) => (Some(old_value), Some(new_value)),
447
448 (
449 MayBeRefCore::Value(old_value),
450 MayBeRefCore::Ref(new_ref),
451 ) => {
452 let target =
453 context.deref_target(new_ref.reference());
454 (Some(old_value), target)
455 }
456
457 (
458 MayBeRefCore::Ref(old_ref),
459 MayBeRefCore::Value(new_value),
460 ) => {
461 let source =
462 context.deref_source(old_ref.reference());
463 (source, Some(new_value))
464 }
465 };
466
467 let old_value = if let Some(value) = old_value {
468 value
469 } else {
470 let diff = None.diff(new_value, &*context);
471 return if diff.is_none() {
472 DiffResult::new(DiffResult::None, &*context)
473 } else {
474 DiffResult::new(
475 DiffResult::Added(MayBeRefCoreDiff::Value(
476 Arc::new(diff),
477 )),
478 &*context,
479 )
480 };
481 };
482
483 let new_value = if let Some(value) = new_value {
484 value
485 } else {
486 return self.diff(None, &*context);
488 };
489
490 Arc::new(old_value.diff(Some(new_value), &*context))
491 };
492
493 match (self, value) {
494 (
495 MayBeRefCore::Ref(old_ref),
496 MayBeRefCore::Ref(new_ref),
497 ) if old_ref.reference() == new_ref.reference() => {
498 let result = match &*diff {
499 DiffResult::None => DiffResult::None,
500 DiffResult::Same(_) => DiffResult::Same(
501 MayBeRefCoreDiff::Ref(old_ref.clone()),
502 ),
503 DiffResult::Added(_) => DiffResult::Added(
504 MayBeRefCoreDiff::Ref(old_ref.clone()),
505 ),
506 DiffResult::Removed(_) => DiffResult::Removed(
507 MayBeRefCoreDiff::Ref(old_ref.clone()),
508 ),
509 DiffResult::Updated(_, _) => DiffResult::Updated(
510 MayBeRefCoreDiff::Ref(old_ref.clone()),
511 None,
512 ),
513 };
514
515 if cached_diff.is_none() {
516 context.set_diff(old_ref.reference(), diff);
517 }
518
519 result
520 }
521 (_, _) => {
525 if diff.is_same_or_none() {
526 DiffResult::Same(MayBeRefCoreDiff::Value(diff))
527 } else {
528 DiffResult::Updated(
529 MayBeRefCoreDiff::Value(diff),
530 None,
531 )
532 }
533 }
534 }
535 }
536 };
537
538 DiffResult::new(diff, context)
539 }
540}
541
542impl<V> Keyed<usize> for IndexMap<String, V> {
543 fn key(&self, idx: usize) -> String {
544 idx.to_string()
545 }
546}
547
548pub trait PathResolver {
549 fn new<'a, T>(k1: T, k2: T) -> Self
552 where
553 T: Iterator<Item = &'a String>;
554
555 fn k1tok2(&self, k1: &String) -> String;
558
559 fn k2tok1(&self, k2: &String) -> String;
562}
563
564#[derive(Debug, Clone)]
565pub struct DefaultMapPathResolver;
566
567impl PathResolver for DefaultMapPathResolver {
568 fn new<'a, T>(_k1: T, _k2: T) -> Self
569 where
570 T: Iterator<Item = &'a String>,
571 {
572 Self
573 }
574
575 fn k1tok2(&self, k1: &String) -> String {
576 k1.to_owned()
577 }
578
579 fn k2tok1(&self, k2: &String) -> String {
580 k2.to_owned()
581 }
582}
583
584#[derive(Debug, Default, Clone, Serialize, Deserialize)]
585#[serde(transparent)]
586pub struct MapDiff<V, R = DefaultMapPathResolver>(
587 pub(crate) IndexMap<String, DiffResult<V>>,
588 #[serde(skip)] PhantomData<R>,
589);
590
591impl<V, R> Deref for MapDiff<V, R> {
592 type Target = IndexMap<String, DiffResult<V>>;
593
594 fn deref(&self) -> &Self::Target {
595 &self.0
596 }
597}
598
599impl<V, O, C, R> Diff<IndexMap<String, V>, MapDiff<O, R>, C>
600 for IndexMap<String, V>
601where
602 V: Diff<V, O, C> + Clone + Debug,
603 R: PathResolver,
604 C: DiffContext,
605 O: Debug,
606{
607 fn diff(
608 &self,
609 new: Option<&IndexMap<String, V>>,
610 context: &C,
611 ) -> DiffResult<MapDiff<O, R>> {
612 let diff = match new {
613 None => DiffResult::Removed(MapDiff(
614 self.iter()
615 .map(|(key, value)| {
616 (key.to_owned(), value.diff(None, &context.removing()))
617 })
618 .collect(),
619 PhantomData,
620 )),
621 Some(other) => {
622 let resolver = R::new(self.keys(), other.keys());
623
624 let mut result: IndexMap<String, DiffResult<O>> =
625 Default::default();
626
627 for (k1, v1) in self.iter() {
628 let k2 = resolver.k1tok2(k1);
629
630 if let Some(v2) = other.get(&k2) {
631 result.insert(k2, v1.diff(Some(v2), context));
632 } else {
633 result.insert(k2, v1.diff(None, context));
634 }
635 }
636
637 result.extend(other.iter().filter_map(|(k2, value)| {
638 let k1 = resolver.k2tok1(k2);
639 if self.contains_key(&k1) {
640 None
641 } else {
642 Some((k1, None.diff(Some(value), context)))
643 }
644 }));
645
646 let is_same =
647 result.iter().all(|(_key, value)| value.is_same_or_none());
648
649 let diff = MapDiff(result, PhantomData);
650
651 if is_same {
652 DiffResult::Same(diff)
653 } else {
654 DiffResult::Updated(diff, None)
655 }
656 }
657 };
658 DiffResult::new(diff, context)
659 }
660}
661
662pub trait VecDiffTransformer<T> {
663 fn transform(collection: T) -> T;
664}
665
666#[derive(Default, Debug, Clone)]
667pub struct DefaultVecDiffTransformer;
668
669impl<T> VecDiffTransformer<T> for DefaultVecDiffTransformer {
670 fn transform(collection: T) -> T {
671 collection
672 }
673}
674
675#[derive(Debug, Default, Clone, Serialize, Deserialize)]
676#[serde(transparent)]
677pub struct VecDiff<T, S = DefaultVecDiffTransformer>(
678 pub Vec<DiffResult<T>>,
679 #[serde(skip)] PhantomData<S>,
680);
681
682impl<T, S> Deref for VecDiff<T, S> {
683 type Target = Vec<DiffResult<T>>;
684
685 fn deref(&self) -> &Self::Target {
686 &self.0
687 }
688}
689
690impl<T, O, C: DiffContext, S> Diff<Vec<T>, VecDiff<O, S>, C> for Vec<T>
691where
692 T: Diff<T, O, C> + Keyed<usize> + Debug,
693 S: VecDiffTransformer<Vec<DiffResult<O>>>,
694 O: Debug,
695{
696 fn diff(
697 &self,
698 new: Option<&Vec<T>>,
699 context: &C,
700 ) -> DiffResult<VecDiff<O, S>> {
701 let diff = match new {
702 None => DiffResult::Removed(VecDiff(
703 self.iter().map(|x| x.diff(None, context)).collect(),
704 PhantomData,
705 )),
706 Some(value) => {
707 let o: IndexMap<_, _> = self
708 .iter()
709 .enumerate()
710 .map(|(idx, v)| (v.key(idx), v))
711 .collect();
712
713 let n: IndexMap<_, _> = value
714 .iter()
715 .enumerate()
716 .map(|(idx, v)| (v.key(idx), v))
717 .collect();
718
719 let o_keys: IndexSet<_> = o.keys().collect();
720 let n_keys: IndexSet<_> = n.keys().collect();
721
722 let new_keys: IndexSet<_> =
723 n_keys.difference(&o_keys).collect();
724 let removed_keys: IndexSet<_> =
725 o_keys.difference(&n_keys).collect();
726 let updated_keys: IndexSet<_> =
727 o_keys.intersection(&n_keys).collect();
728
729 let added: Vec<_> = new_keys
730 .into_iter()
731 .map(|key| {
732 let new = n.get(*key).expect("key must present");
733 None.diff(Some(*new), context)
734 })
735 .collect();
736
737 let removed: Vec<_> = removed_keys
738 .into_iter()
739 .map(|key| {
740 let old = o.get(*key).expect("key must present");
741 old.diff(None, context)
742 })
743 .collect();
744
745 let updated: Vec<_> = updated_keys
746 .into_iter()
747 .map(|key| {
748 let old = o.get(*key).expect("key must present");
749 let new = n.get(*key).expect("key must present");
750 old.diff(Some(*new), context)
751 })
752 .collect();
753
754 let values: Vec<_> = added
755 .into_iter()
756 .chain(updated.into_iter())
757 .chain(removed.into_iter())
758 .collect();
759
760 let is_same =
761 values.iter().all(|value| value.is_same_or_none());
762
763 let values = S::transform(values);
764
765 let diff = VecDiff(values, PhantomData);
766
767 if is_same {
768 DiffResult::Same(diff)
769 } else {
770 DiffResult::Updated(diff, None)
771 }
772 }
773 };
774 DiffResult::new(diff, context)
775 }
776}
777
778impl<C: DiffContext> Diff<Value, Value, C> for Value {
779 fn diff(&self, new: Option<&Value>, context: &C) -> DiffResult<Value> {
780 let diff = match new {
781 None => DiffResult::Removed(self.clone()),
782 Some(value) => {
783 if self == value {
784 DiffResult::Same(value.clone())
785 } else {
786 DiffResult::Updated(
787 value.clone(),
788 Some(Box::new(self.clone())),
789 )
790 }
791 }
792 };
793 DiffResult::new(diff, context)
794 }
795}
796
797impl Keyed<usize> for Value {
798 fn key(&self, idx: usize) -> String {
799 match self {
800 Value::Null => "null".to_owned(),
801 Value::Bool(value) => format!("[bool]:{value}"),
802 Value::Number(value) => format!("[number]:{value}"),
803 Value::String(value) => format!("[string]:{value}"),
804 Value::Array(_value) => format!("[array]: {idx}"),
806 Value::Object(_value) => format!("[object]: {idx}"),
807 }
808 }
809}
810
811impl<'a> Keyed<usize> for &'a str {
812 fn key(&self, _: usize) -> String {
813 self.to_string()
814 }
815}
816
817impl Keyed<usize> for String {
818 fn key(&self, _: usize) -> String {
819 self.clone()
820 }
821}
822
823impl Keyed<usize> for (String, String) {
824 fn key(&self, _: usize) -> String {
825 self.0.clone()
826 }
827}
828
829macro_rules! impl_keyed_diff {
830 ($typ:ty) => {
831 impl Keyed<usize> for $typ {
832 fn key(&self, _: usize) -> String {
833 self.to_string()
834 }
835 }
836
837 impl<C: DiffContext> Diff<$typ, $typ, C> for $typ {
838 fn diff(
839 &self,
840 new: Option<&$typ>,
841 context: &C,
842 ) -> DiffResult<$typ> {
843 let diff = match new {
844 None => DiffResult::Removed(*self),
845 Some(value) => {
846 if self == value {
847 DiffResult::Same(*value)
848 } else {
849 DiffResult::Updated(*value, Some(Box::new(*self)))
850 }
851 }
852 };
853 DiffResult::new(diff, context)
854 }
855 }
856 };
857}
858
859impl_keyed_diff!(u32);
860impl_keyed_diff!(u64);
861impl_keyed_diff!(i32);
862impl_keyed_diff!(i64);
863impl_keyed_diff!(f32);
864impl_keyed_diff!(f64);
865impl_keyed_diff!(bool);
866impl_keyed_diff!(usize);
867
868impl<C: DiffContext> Diff<Self, String, C> for String {
869 fn diff(&self, new: Option<&String>, context: &C) -> DiffResult<String> {
870 let diff = match new {
871 None => DiffResult::Removed(self.clone()),
872 Some(value) => {
873 if self == value {
874 DiffResult::Same(value.to_string())
875 } else {
876 DiffResult::Updated(
877 value.to_string(),
878 Some(Box::new(self.to_string())),
879 )
880 }
881 }
882 };
883 DiffResult::new(diff, context)
884 }
885}