visit_diff/
impls.rs

1use super::*;
2
3////////////////////////////////////////////////////////////////////////////////
4// Unit-shaped things
5
6impl Diff for () {
7    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
8    where
9        D: Differ,
10    {
11        out.same(a, b)
12    }
13}
14
15impl<T: ?Sized> Diff for core::marker::PhantomData<T> {
16    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
17    where
18        D: Differ,
19    {
20        out.same(a, b)
21    }
22}
23
24////////////////////////////////////////////////////////////////////////////////
25// Tuple boilerplate
26
27macro_rules! tuple_impl {
28    ($($p:ident / $n:tt),*) => {
29        impl<$($p),*> Diff for ($($p,)*)
30        where
31            $($p: Diff),*
32        {
33            fn diff<DD>(a: &Self, b: &Self, out: DD) -> Result<DD::Ok, DD::Err>
34            where
35                DD: Differ,
36            {
37                let mut out = out.begin_tuple("");
38                $(out.diff_field(&a.$n, &b.$n);)*
39                out.end()
40            }
41        }
42    };
43}
44
45tuple_impl!(A / 0);
46tuple_impl!(A / 0, B / 1);
47tuple_impl!(A / 0, B / 1, C / 2);
48tuple_impl!(A / 0, B / 1, C / 2, D / 3);
49tuple_impl!(A / 0, B / 1, C / 2, D / 3, E / 4);
50tuple_impl!(A / 0, B / 1, C / 2, D / 3, E / 4, F / 5);
51tuple_impl!(A / 0, B / 1, C / 2, D / 3, E / 4, F / 5, G / 6);
52tuple_impl!(A / 0, B / 1, C / 2, D / 3, E / 4, F / 5, G / 6, H / 7);
53tuple_impl!(
54    A / 0,
55    B / 1,
56    C / 2,
57    D / 3,
58    E / 4,
59    F / 5,
60    G / 6,
61    H / 7,
62    I / 8
63);
64
65////////////////////////////////////////////////////////////////////////////////
66// Slice and array boilerplate
67
68impl<T> Diff for [T]
69where
70    T: Diff,
71{
72    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
73    where
74        D: Differ,
75    {
76        let mut s = out.begin_seq();
77        s.diff_elements(a, b);
78        s.end()
79    }
80}
81
82macro_rules! array_impl {
83    ($n:tt) => {
84        impl<T> Diff for [T; $n]
85        where
86            T: Diff,
87        {
88            fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
89            where
90                D: Differ,
91            {
92                Diff::diff(a as &[T], b as &[T], out)
93            }
94        }
95    };
96}
97
98array_impl!(0);
99array_impl!(1);
100array_impl!(2);
101array_impl!(3);
102array_impl!(4);
103array_impl!(5);
104array_impl!(6);
105array_impl!(7);
106array_impl!(8);
107array_impl!(9);
108array_impl!(10);
109array_impl!(11);
110array_impl!(12);
111array_impl!(13);
112array_impl!(14);
113array_impl!(15);
114array_impl!(16);
115array_impl!(17);
116array_impl!(18);
117array_impl!(19);
118array_impl!(20);
119array_impl!(21);
120array_impl!(22);
121array_impl!(23);
122array_impl!(24);
123array_impl!(25);
124array_impl!(26);
125array_impl!(27);
126array_impl!(28);
127array_impl!(29);
128array_impl!(30);
129array_impl!(31);
130array_impl!(32);
131
132////////////////////////////////////////////////////////////////////////////////
133// References
134
135/// Diff references by dereferencing.
136impl<T> Diff for &T
137where
138    T: Diff + ?Sized,
139{
140    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
141    where
142        D: Differ,
143    {
144        Diff::diff(*a, *b, out)
145    }
146}
147
148/// Diff references by dereferencing.
149impl<T> Diff for &mut T
150where
151    T: Diff + ?Sized,
152{
153    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
154    where
155        D: Differ,
156    {
157        Diff::diff(*a, *b, out)
158    }
159}
160
161impl<'a, T: ?Sized + Diff> Diff for core::cell::Ref<'a, T> {
162    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
163    where
164        D: Differ,
165    {
166        Diff::diff(&**a, &**b, out)
167    }
168}
169
170impl<'a, T: ?Sized + Diff> Diff for core::cell::RefMut<'a, T> {
171    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
172    where
173        D: Differ,
174    {
175        Diff::diff(&**a, &**b, out)
176    }
177}
178
179////////////////////////////////////////////////////////////////////////////////
180// "Atomic" types that can be diffed using PartialEq.
181
182macro_rules! impl_diff_partial_eq {
183    // Specialization for unsized types: adds a reference on the way to the
184    // differ.
185    (unsized $ty:ty) => {
186        impl Diff for $ty {
187            fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
188            where
189                D: Differ,
190            {
191                if a != b {
192                    out.difference(&a, &b)
193                } else {
194                    out.same(&a, &b)
195                }
196            }
197        }
198    };
199    ($ty:ty | $p:ident) => {
200        impl<$p> Diff for $ty
201        where
202            $ty: PartialEq + Debug,
203        {
204            fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
205            where
206                D: Differ,
207            {
208                if a != b {
209                    out.difference(&a, &b)
210                } else {
211                    out.same(&a, &b)
212                }
213            }
214        }
215    };
216    ($ty:ty) => {
217        impl Diff for $ty {
218            fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
219            where
220                D: Differ,
221            {
222                if a != b {
223                    out.difference(a, b)
224                } else {
225                    out.same(a, b)
226                }
227            }
228        }
229    };
230}
231
232impl_diff_partial_eq!(bool);
233impl_diff_partial_eq!(char);
234impl_diff_partial_eq!(u8);
235impl_diff_partial_eq!(u16);
236impl_diff_partial_eq!(u32);
237impl_diff_partial_eq!(u64);
238impl_diff_partial_eq!(u128);
239impl_diff_partial_eq!(usize);
240impl_diff_partial_eq!(i8);
241impl_diff_partial_eq!(i16);
242impl_diff_partial_eq!(i32);
243impl_diff_partial_eq!(i64);
244impl_diff_partial_eq!(i128);
245impl_diff_partial_eq!(isize);
246impl_diff_partial_eq!(f32);
247impl_diff_partial_eq!(f64);
248impl_diff_partial_eq!(unsized str);
249impl_diff_partial_eq!(core::cmp::Ordering);
250impl_diff_partial_eq!(core::time::Duration);
251
252// Ranges are treated as atomic values in this version, because they have
253// strange Debug impls that would otherwise require explicit support in the
254// Differ traits.
255impl_diff_partial_eq!(core::ops::Range<T> | T);
256impl_diff_partial_eq!(core::ops::RangeFrom<T> | T);
257impl_diff_partial_eq!(core::ops::RangeFull);
258impl_diff_partial_eq!(core::ops::RangeTo<T> | T);
259impl_diff_partial_eq!(core::ops::RangeToInclusive<T> | T);
260
261/// Pointers diff by address, not by contents.
262impl<T: ?Sized> Diff for *const T {
263    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
264    where
265        D: Differ,
266    {
267        if a != b {
268            out.difference(a, b)
269        } else {
270            out.same(a, b)
271        }
272    }
273}
274
275/// Pointers diff by address, not by contents.
276impl<T: ?Sized> Diff for *mut T {
277    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
278    where
279        D: Differ,
280    {
281        if a != b {
282            out.difference(a, b)
283        } else {
284            out.same(a, b)
285        }
286    }
287}
288
289////////////////////////////////////////////////////////////////////////////////
290// Trivial containers and cells. The trivial containers in core vary on whether
291// they want to be represented as a simple newtype, or as a struct containing a
292// single field. We follow their Debug implementations.
293
294impl<T: Copy + Diff> Diff for core::cell::Cell<T> {
295    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
296    where
297        D: Differ,
298    {
299        let mut out = out.begin_struct("Cell");
300        out.diff_field("value", &a.get(), &b.get());
301        out.end()
302    }
303}
304
305impl<T: ?Sized + Diff> Diff for core::mem::ManuallyDrop<T> {
306    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
307    where
308        D: Differ,
309    {
310        let mut out = out.begin_struct("ManuallyDrop");
311        out.diff_field("value", &*a, &*b);
312        out.end()
313    }
314}
315
316impl<T: Diff> Diff for core::num::Wrapping<T> {
317    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
318    where
319        D: Differ,
320    {
321        Diff::diff(&a.0, &b.0, out)
322    }
323}
324
325/// Note that this *will* panic if the RefCell is mutably borrowed.
326impl<T: ?Sized + Diff> Diff for core::cell::RefCell<T> {
327    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
328    where
329        D: Differ,
330    {
331        let mut out = out.begin_struct("RefCell");
332        out.diff_field("value", &*a.borrow(), &*b.borrow());
333        out.end()
334    }
335}
336
337impl<T: Diff> Diff for core::option::Option<T> {
338    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
339    where
340        D: Differ,
341    {
342        match (a, b) {
343            (None, None) => out.same(a, b),
344            (Some(a), Some(b)) => {
345                let mut out = out.begin_tuple_variant("Option", "Some");
346                out.diff_field(a, b);
347                out.end()
348            }
349            _ => out.difference(a, b),
350        }
351    }
352}
353
354impl<T: Diff, E: Diff> Diff for core::result::Result<T, E> {
355    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
356    where
357        D: Differ,
358    {
359        match (a, b) {
360            (Ok(a), Ok(b)) => {
361                let mut out = out.begin_tuple_variant("Result", "Ok");
362                out.diff_field(a, b);
363                out.end()
364            }
365            (Err(a), Err(b)) => {
366                let mut out = out.begin_tuple_variant("Result", "Err");
367                out.diff_field(a, b);
368                out.end()
369            }
370            _ => out.difference(a, b),
371        }
372    }
373}
374
375#[cfg(test)]
376mod tests {
377    use super::*;
378
379    #[allow(unused)]
380    #[derive(Clone, Debug)]
381    pub enum TestEnum {
382        First,
383        Second,
384        Struct { a: usize, b: bool },
385    }
386
387    impl Diff for TestEnum {
388        fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
389        where
390            D: Differ,
391        {
392            match (a, b) {
393                (TestEnum::First, TestEnum::First) => out.same(a, b),
394                (TestEnum::Second, TestEnum::Second) => out.same(a, b),
395                (
396                    TestEnum::Struct { a: aa, b: ab },
397                    TestEnum::Struct { a: ba, b: bb },
398                ) => {
399                    let mut s = out.begin_struct_variant("TestEnum", "Struct");
400                    s.diff_field("a", &aa, &ba);
401                    s.diff_field("b", &ab, &bb);
402                    s.end()
403                }
404                _ => out.difference(a, b),
405            }
406        }
407    }
408
409    #[derive(Clone, Debug)]
410    pub struct TestStruct {
411        pub distance: usize,
412        pub silly: bool,
413    }
414
415    impl Diff for TestStruct {
416        fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
417        where
418            D: Differ,
419        {
420            let mut s = out.begin_struct("TestStruct");
421            s.diff_field("distance", &a.distance, &b.distance);
422            s.diff_field("silly", &a.silly, &b.silly);
423            s.end()
424        }
425    }
426}