visit_diff/
lib.rs

1//! Analyzing structural differences in Rust values using visitors.
2//!
3//! # Simple application
4//!
5//! This crate provides three functions that you can use immediately without
6//! having to learn a bunch of traits.
7//!
8//! - [`debug_diff`] enables you to print the differences between two values of
9//!   a [`Diff`] type using debug formatting.
10//!
11//! - [`any_difference`] and [`all_different`] scan values for differences and
12//!   return a `bool`.
13//!
14//! You can derive [`Diff`] for any custom type that implements `Debug`.
15//!
16//! # Under the hood
17//!
18//! This scheme is modeled after a combination of `core::fmt::Formatter` and
19//! `serde::Serialize`. There are two main traits:
20//!
21//! - [`Diff`] is implemented by types that can be diff'd.
22//! - [`Differ`] is implemented by types that can process differences.
23//!
24//! You'll typically derive [`Diff`]. Derived impls will simply present the
25//! structure of the type honestly, much like a derived `Debug` impl would.
26//! However, you can also implement it by hand if you need special
27//! functionality.
28//!
29//! The most detailed docs are on the [`Differ`] trait.
30//!
31//! # Visitors
32//!
33//! Together, [`Diff`] and [`Differ`] implement the [Visitor Pattern] for
34//! climbing over a data structure. This is a little different than some other
35//! applications of visitors you might have encountered. In particular:
36//!
37//! 1. The structure being visited is *the Rust notion of types*: here is a
38//!    struct, the struct has fields, etc. A custom impl of [`Diff`] can fake
39//!    the internals of a type to abstract away details, but the model is still
40//!    the same.
41//!
42//! 2. Instead of visiting the parts of a *single* data structure, here we are
43//!    visiting *two* data structures of the same type in parallel. This means
44//!    we stop visiting if the structures diverge -- for example, if we discover
45//!    two *different* variants of an `enum` type. (When this happens we notify
46//!    the [`Differ`] through the [`difference`] method.)
47//!
48//! 3. The [double dispatch] aspect of the visitor pattern occurs *at compile
49//!    time,* rather than at runtime, so there's very little overhead.
50//!    The description of the pattern on Wikipedia (and the book *Design
51//!    Patterns* that originated the name "visitor") doesn't discuss this
52//!    version, only considering `dyn`-style runtime dispatch.
53//!
54//! # `no_std` support
55//!
56//! This crate is `no_std` compatible, in case you want to diff data structures
57//! in a deeply-embedded system.
58//!
59//! [`Diff`]: trait.Diff.html
60//! [`Differ`]: trait.Differ.html
61//! [`any_difference`]: fn.any_difference.html
62//! [`all_different`]: fn.all_different.html
63//! [`debug_diff`]: fn.debug_diff.html
64//! [Visitor Pattern]: https://en.wikipedia.org/wiki/Visitor_pattern
65//! [double dispatch]: https://en.wikipedia.org/wiki/Double_dispatch
66//! [`difference`]: trait.Differ.html#tymethod.difference
67
68#![cfg_attr(not(feature = "std"), no_std)]
69
70#[cfg(feature = "visit_diff_derive")]
71pub use visit_diff_derive::*;
72
73mod debug;
74mod detect;
75mod unit;
76pub mod constant;
77#[macro_use]
78mod impls;
79#[cfg(feature = "std")]
80mod std_impls;
81
82pub mod record;
83
84use core::fmt::Debug;
85use itertools::{EitherOrBoth, Itertools};
86
87pub use debug::debug_diff;
88pub use detect::{all_different, any_difference};
89
90/// A type that can be compared structurally to discover differences.
91///
92/// The job of a `Diff` impl is to use knowledge of the structure of some type
93/// (`Self`) to check two copies for differences, and report findings to a
94/// [`Differ`].
95///
96/// [`Differ`] has methods for each different flavor of Rust type, and you can
97/// only call one of them (as they consume the `Differ`). So, the first task
98/// when implementing `Diff` is to decide which one to call.
99///
100/// Very simple types may just dispatch to [`same`] or [`difference`], like this
101/// impl for a newtype around `u32`:
102///
103/// ```
104/// use visit_diff::{Diff, Differ};
105///
106/// #[derive(Debug)]
107/// struct MyInt(u32);
108///
109/// impl Diff for MyInt {
110///     fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
111///     where D: Differ
112///     {
113///         if a.0 == b.0 {
114///             out.same(&a, &b)
115///         } else {
116///             out.difference(&a, &b)
117///         }
118///     }
119/// }
120///
121/// use visit_diff::any_difference;
122///
123/// assert_eq!(any_difference(&MyInt(1), &MyInt(1)), false);
124/// assert_eq!(any_difference(&MyInt(1), &MyInt(0)), true);
125/// ```
126///
127/// (Note: in reality, you'd probably want to `#[derive(Diff)]` for a type this
128/// simple.)
129///
130/// More complicated types would use other methods on [`Differ`] to describe
131/// their structure. See the documentation of that trait for more.
132///
133/// [`Differ`]: trait.Differ.html
134/// [`same`]: trait.Differ.html#tymethod.same
135/// [`difference`]: trait.Differ.html#tymethod.difference
136pub trait Diff: Debug {
137    /// Inspect `a` and `b` and tell `out` about any differences.
138    ///
139    /// All (reasonable) implementations of this method have the same basic
140    /// structure: they call a method on `out`, and then follow the instructions
141    /// from that method to get a result.
142    fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
143    where
144        D: Differ;
145}
146
147/// A type that can do something with information about structural differences.
148///
149/// If you think that sounds vague, you're right! This trait is very general and
150/// covers a lot of use cases, which can make it hard to understand at first
151/// glance. Don't worry! It's straightforward once you get the hang of it,
152/// though it *is* pretty wordy.
153///
154/// # How to use a `Differ`
155///
156/// Normally, you'll only call the methods on `Differ` from within an
157/// implementation of [`Diff::diff`]. Also, normally, you won't write your own
158/// implementation of [`Diff::diff`] in the first place -- you'll
159/// `#[derive(Diff)]`. This section will explain how to use `Differ` manually to
160/// produce the same results as the derived impls, should you ever need to.
161///
162/// An implementation of `Differ` is actually a small *family* of types. There's
163/// the type implementing `Differ` (which we'll call "the differ") for short,
164/// and then there are the *associated types*. All of the methods on `Differ`
165/// either produce a result immediately, or convert the differ into one of the
166/// associated types because more information is needed to produce a result.
167///
168/// In the end, every complete interaction with a differ type `D` produces the
169/// same type: `Result<D::Ok, D::Err>`. This means each implementation can
170/// decide what its output and failure types look like.
171///
172/// The basic methods [`difference`], [`same`], and [`diff_newtype`] produce a
173/// result immediately without further work.
174///
175/// The methods starting with `begin` require more than one step.
176///
177/// ## `struct`
178///
179/// If a type is a struct with named fields, call [`begin_struct`] to convert
180/// the `Differ` into a [`StructDiffer`]. `StructDiffer` has methods for
181/// describing struct fields. See the example on [`begin_struct`] for more.
182///
183/// Not all structs have named fields: there are also tuple structs. For a tuple
184/// struct, call [`begin_tuple`] to convert the `Differ` into a [`TupleDiffer`].
185/// `TupleDiffer` has methods for describing tuple struct fields. See the
186/// example on [`begin_tuple`] for more.
187///
188/// ## `enum`
189///
190/// Rust enums are more complex than structs, because each variant of an enum
191/// can have a *different shape*: some may have named fields, some may have
192/// unnamed fields, and some may be *unit variants* without fields at all.
193///
194/// Typically you only want to treat two values of an enum type as "same" if
195/// they have the same variant. This means an implementation of `diff` for an
196/// enum will usually have a "parallel match" shape like this:
197///
198/// ```
199/// use visit_diff::{Differ, Diff};
200///
201/// #[derive(Debug)]
202/// enum ExampleEnum { Variant1, Variant2 }
203///
204/// impl Diff for ExampleEnum {
205///     fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
206///     where D: Differ
207///     {
208///         match (a, b) {
209///             (ExampleEnum::Variant1, ExampleEnum::Variant1) => {
210///                 out.same(a, b)
211///             }
212///             (ExampleEnum::Variant2, ExampleEnum::Variant2) => {
213///                 out.same(a, b)
214///             }
215///             _ => out.difference(a, b),
216///         }
217///     }
218/// }
219/// ```
220///
221/// In that example, both variants are *unit variants* without fields. Let's
222/// consider the other flavors.
223///
224/// For struct variants with named fields, use [`begin_struct_variant`] to
225/// convert the differ into a [`StructVariantDiffer`]. See the example on
226/// [`begin_struct_variant`] for more.
227///
228/// For tuple variants with unnamed fields, use [`begin_tuple_variant`] to
229/// convert the differ into a [`TupleVariantDiffer`]. See the example on
230/// [`begin_tuple_variant`] for more.
231///
232/// ## Abstract types
233///
234/// This crate recognizes three kinds of *abstract types*, which don't directly
235/// map to any native Rust type, but are really common library types. (They also
236/// happen to be the three kinds of abstract types recognized by
237/// `std::fmt::Formatter`.)
238///
239/// *Sequences* are variable-length ordered collections of things, such as a
240/// slice or a `Vec`. Not only can the individual elements be different between
241/// two sequences, but elements can be added or removed, too. For types that
242/// want to be treated like sequences, use [`begin_seq`] to convert the differ
243/// into a [`SeqDiffer`]. See the example on [`begin_seq`] for more.
244///
245/// *Sets* are variable-length collections of things where each thing appears
246/// only once, such as a `HashSet`. Sets may or may not be ordered. They're
247/// otherwise treated a lot like sequences. For set-like types, use
248/// [`begin_set`] to convert the differ into a [`SetDiffer`].
249///
250/// *Maps* are variable-length collections of key-value pairs, like a `HashMap`.
251/// Maps may or may not be ordered. For map-like types, use [`begin_map`] to
252/// convert the differ into a [`MapDiffer`].
253///
254/// [`Diff::diff`]: trait.Diff.html#tymethod.diff
255/// [`difference`]: #tymethod.difference
256/// [`same`]: #tymethod.same
257/// [`diff_newtype`]: #tymethod.diff_newtype
258/// [`begin_struct`]: #tymethod.begin_struct
259/// [`begin_struct_variant`]: #tymethod.begin_struct_variant
260/// [`begin_tuple`]: #tymethod.begin_tuple
261/// [`begin_tuple_variant`]: #tymethod.begin_tuple_variant
262/// [`begin_seq`]: #tymethod.begin_seq
263/// [`begin_set`]: #tymethod.begin_set
264/// [`begin_map`]: #tymethod.begin_map
265/// [`StructDiffer`]: trait.StructDiffer.html
266/// [`StructVariantDiffer`]: trait.StructVariantDiffer.html
267/// [`TupleDiffer`]: trait.TupleDiffer.html
268/// [`TupleVariantDiffer`]: trait.TupleVariantDiffer.html
269/// [`SeqDiffer`]: trait.SeqDiffer.html
270/// [`SetDiffer`]: trait.SetDiffer.html
271/// [`MapDiffer`]: trait.MapDiffer.html
272pub trait Differ {
273    /// Type returned on success.
274    type Ok;
275    /// Type returned on failure.
276    ///
277    /// If your differ can't fail, consider using the [`void`] crate. It
278    /// provides an extension method on `Result`, `unwrap_void`, that never
279    /// panics.
280    ///
281    /// [`void`]: http://docs.rs/void/
282    type Err;
283
284    /// The type we turn into when diffing a struct.
285    type StructDiffer: StructDiffer<Ok = Self::Ok, Err = Self::Err>;
286    /// The type we turn into when diffing a struct variant of an enum.
287    ///
288    /// This is often the same type as `StructDiffer`.
289    type StructVariantDiffer: StructDiffer<Ok = Self::Ok, Err = Self::Err>;
290    /// The type we turn into when diffing a tuple or tuple struct.
291    type TupleDiffer: TupleDiffer<Ok = Self::Ok, Err = Self::Err>;
292    /// The type we turn into when diffing a tuple variant of an enum.
293    ///
294    /// This is often the same type as `TupleDiffer`.
295    type TupleVariantDiffer: TupleDiffer<Ok = Self::Ok, Err = Self::Err>;
296    /// The type we turn into when diffing an abstract sequence.
297    type SeqDiffer: SeqDiffer<Ok = Self::Ok, Err = Self::Err>;
298    /// The type we turn into when diffing an abstract map.
299    type MapDiffer: MapDiffer<Ok = Self::Ok, Err = Self::Err>;
300    /// The type we turn into when diffing an abstract set.
301    type SetDiffer: SetDiffer<Ok = Self::Ok, Err = Self::Err>;
302
303    /// Two atomic values have been discovered to be different, such as
304    /// different numbers or different variants of an enum.
305    fn difference(self, a: &Debug, b: &Debug) -> Result<Self::Ok, Self::Err>;
306
307    /// Two atomic values are the same, such as equal numbers or identical unit
308    /// variants of an enum.
309    fn same(self, a: &Debug, b: &Debug) -> Result<Self::Ok, Self::Err>;
310
311    /// Encounter a newtype. `a` and `b` are the contents of the sole fields of
312    /// the left-hand and right-hand value, respectively.
313    fn diff_newtype<T: ?Sized>(
314        self,
315        ty: &'static str,
316        a: &T,
317        b: &T,
318    ) -> Result<Self::Ok, Self::Err>
319    where
320        T: Diff;
321
322    /// Begin traversing a struct with named fields.
323    ///
324    /// This converts `self` into an implementation of [`StructDiffer`], which
325    /// in turn has methods for describing a struct.
326    ///
327    /// Here's an example of using `begin_struct` to manually implement [`Diff`]
328    /// for a struct with named fields:
329    ///
330    /// ```
331    /// use visit_diff::{Diff, Differ};
332    ///
333    /// #[derive(Debug)]
334    /// struct ExampleStruct {
335    ///     name: String,
336    ///     age: usize,
337    /// }
338    ///
339    /// impl Diff for ExampleStruct {
340    ///     fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
341    ///     where D: Differ
342    ///     {
343    ///         // Bring the struct operations into scope. This could also go at
344    ///         // the top.
345    ///         use visit_diff::StructDiffer;
346    ///
347    ///         let mut out = out.begin_struct("ExampleStruct");
348    ///
349    ///         // Visit each field in turn.
350    ///         out.diff_field("name", &a.name, &b.name);
351    ///         out.diff_field("age", &a.age, &b.age);
352    ///
353    ///         // Finish the diff and generate the result.
354    ///         out.end()
355    ///     }
356    /// }
357    /// ```
358    ///
359    /// [`StructDiffer`]: trait.StructDiffer.html
360    /// [`Diff`]: trait.Diff.html
361    fn begin_struct(self, ty: &'static str) -> Self::StructDiffer;
362
363    /// Begin traversing a struct variant of an enum.
364    ///
365    /// The rest is very similar to dealing with a normal struct, except that we
366    /// have to use pattern matching to get at the fields.
367    ///
368    /// ```
369    /// use visit_diff::{Diff, Differ};
370    ///
371    /// #[derive(Debug)]
372    /// enum ExampleEnum {
373    ///     Unit,
374    ///     Struct {
375    ///         name: String,
376    ///         age: usize,
377    ///     },
378    /// }
379    ///
380    /// impl Diff for ExampleEnum {
381    ///     fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
382    ///     where D: Differ
383    ///     {
384    ///         match (a, b) {
385    ///             (ExampleEnum::Unit, ExampleEnum::Unit) => out.same(a, b),
386    ///             (ExampleEnum::Struct { name: a_name, age: a_age },
387    ///              ExampleEnum::Struct { name: b_name, age: b_age }) => {
388    ///                 // Bring the struct operations into scope. This could
389    ///                 // also go at the top. Note that struct variants use the
390    ///                 // same trait as normal structs.
391    ///                 use visit_diff::StructDiffer;
392    ///
393    ///                 let mut out = out.begin_struct_variant(
394    ///                     "ExampleEnum", // type name
395    ///                     "Struct",      // variant name
396    ///                 );
397    ///
398    ///                 // Visit each field in turn.
399    ///                 out.diff_field("name", a_name, b_name);
400    ///                 out.diff_field("age", a_age, b_age);
401    ///
402    ///                 // Finish the diff and generate the result.
403    ///                 out.end()
404    ///             }
405    ///             _ => out.difference(a, b),
406    ///         }
407    ///     }
408    /// }
409    /// ```
410    fn begin_struct_variant(
411        self,
412        ty: &'static str,
413        var: &'static str,
414    ) -> Self::StructVariantDiffer;
415
416    /// Begin traversing a tuple struct or raw tuple.
417    ///
418    /// This converts `self` into an implementation of [`TupleDiffer`], which
419    /// in turn has methods for describing a tuple struct.
420    ///
421    /// To describe something as a raw tuple (even if it isn't necessarily),
422    /// pass an empty string for the type name.
423    ///
424    /// Here's an example of using `begin_tuple` to manually implement [`Diff`]
425    /// for a struct with unnamed fields:
426    ///
427    /// ```
428    /// use visit_diff::{Diff, Differ};
429    ///
430    /// #[derive(Debug)]
431    /// struct ExampleStruct(String, usize);
432    ///
433    /// impl Diff for ExampleStruct {
434    ///     fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
435    ///     where D: Differ
436    ///     {
437    ///         // Bring the tuple operations into scope. This could also go at
438    ///         // the top.
439    ///         use visit_diff::TupleDiffer;
440    ///
441    ///         let mut out = out.begin_tuple("ExampleStruct");
442    ///
443    ///         // Visit each field in turn.
444    ///         out.diff_field(&a.0, &b.0);
445    ///         out.diff_field(&a.1, &b.1);
446    ///
447    ///         // Finish the diff and generate the result.
448    ///         out.end()
449    ///     }
450    /// }
451    /// ```
452    ///
453    /// [`TupleDiffer`]: trait.TupleDiffer.html
454    /// [`Diff`]: trait.Diff.html
455    fn begin_tuple(self, ty: &'static str) -> Self::TupleDiffer;
456
457    /// Begin traversing a tuple variant of an enum.
458    ///
459    /// The rest is very similar to dealing with a normal tuple, except that we
460    /// have to use pattern matching to get at the fields.
461    ///
462    /// ```
463    /// use visit_diff::{Diff, Differ};
464    ///
465    /// #[derive(Debug)]
466    /// enum ExampleEnum {
467    ///     Unit,
468    ///     Tuple(String, usize),
469    /// }
470    ///
471    /// impl Diff for ExampleEnum {
472    ///     fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
473    ///     where D: Differ
474    ///     {
475    ///         match (a, b) {
476    ///             (ExampleEnum::Unit, ExampleEnum::Unit) => out.same(a, b),
477    ///             (ExampleEnum::Tuple(a_name, a_age),
478    ///              ExampleEnum::Tuple(b_name, b_age)) => {
479    ///                 // Bring the tuple operations into scope. This could
480    ///                 // also go at the top. Note that tuple variants use the
481    ///                 // same trait as normal tuples.
482    ///                 use visit_diff::TupleDiffer;
483    ///
484    ///                 let mut out = out.begin_tuple_variant(
485    ///                     "ExampleEnum", // type name
486    ///                     "Tuple",      // variant name
487    ///                 );
488    ///
489    ///                 // Visit each field in turn.
490    ///                 out.diff_field(a_name, b_name);
491    ///                 out.diff_field(a_age, b_age);
492    ///
493    ///                 // Finish the diff and generate the result.
494    ///                 out.end()
495    ///             }
496    ///             _ => out.difference(a, b),
497    ///         }
498    ///     }
499    /// }
500    /// ```
501    fn begin_tuple_variant(
502        self,
503        ty: &'static str,
504        var: &'static str,
505    ) -> Self::TupleVariantDiffer;
506
507    /// Begin traversing a sequence.
508    ///
509    /// This is quite general; it's up to you to decide how exactly your type
510    /// looks like a sequence.
511    ///
512    /// Here's a simple implementation for slices -- which we wrap in a newtype
513    /// here because there's already an implementation for slices. This uses the
514    /// provided [`diff_elements`] method that makes diffing two iterators easy.
515    ///
516    /// ```
517    /// use visit_diff::{Diff, Differ};
518    ///
519    /// #[derive(Debug)]
520    /// struct Slice<'a, T>(&'a [T]);
521    ///
522    /// impl<'a, T: Diff> Diff for Slice<'a, T> {
523    ///     fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
524    ///     where D: Differ
525    ///     {
526    ///         // Bring the sequence operations into scope. This could also go
527    ///         // at the top.
528    ///         use visit_diff::SeqDiffer;
529    ///
530    ///         let mut out = out.begin_seq();
531    ///         out.diff_elements(a.0, b.0);
532    ///         out.end()
533    ///     }
534    /// }
535    /// ```
536    ///
537    /// [`diff_elements`]: trait.SeqDiffer.html#method.diff_elements
538    fn begin_seq(self) -> Self::SeqDiffer;
539
540    /// Begin traversing a map.
541    fn begin_map(self) -> Self::MapDiffer;
542
543    /// Begin traversing a set.
544    fn begin_set(self) -> Self::SetDiffer;
545}
546
547/// A type that can deal with differences in a `struct`.
548pub trait StructDiffer {
549    /// Type returned on success.
550    type Ok;
551    /// Type returned on failure.
552    type Err;
553
554    /// Visits a field `name` with values `a` and `b` in the respective
555    /// structures.
556    fn diff_field<T: ?Sized>(&mut self, name: &'static str, a: &T, b: &T)
557    where
558        T: Diff;
559
560    /// Skips a field that is excluded from differencing.
561    ///
562    /// Some differs may e.g. print a placeholder for skipped fields.
563    fn skip_field<T: ?Sized>(&mut self, _name: &'static str) {}
564
565    /// Completes traversal of the struct.
566    fn end(self) -> Result<Self::Ok, Self::Err>;
567}
568
569/// A type that can do something with information about differences in a
570/// tuple or tuple-like struct.
571///
572/// For two tuples to be of the same type (and thus be able to be diffed), they
573/// must be the same length. For types that vary in length, you want a
574/// [`SeqDiffer`] instead.
575///
576/// [`SeqDiffer`]: trait.SeqDiffer.html
577pub trait TupleDiffer {
578    /// Type returned on success.
579    type Ok;
580    /// Type returned on failure.
581    type Err;
582
583    /// Visits the *next* field in each tuple. The field number is implicit.
584    fn diff_field<T: ?Sized>(&mut self, a: &T, b: &T)
585    where
586        T: Diff;
587
588    /// Signals that a field is being skipped. Some differs may do something
589    /// with this information.
590    fn skip_field<T: ?Sized>(&mut self) {}
591
592    /// Finish diffing the tuples and return a result.
593    fn end(self) -> Result<Self::Ok, Self::Err>;
594}
595
596/// A type that can do something with information about differences in a
597/// sequence, like a slice or `Vec`.
598pub trait SeqDiffer {
599    /// Type returned on success.
600    type Ok;
601    /// Type returned on failure.
602    type Err;
603
604    /// We've found elements in corresponding positions in both sequences.
605    fn diff_element<T: ?Sized>(&mut self, a: &T, b: &T)
606    where
607        T: Diff;
608
609    /// We've found an element that only appears in the left-hand sequence.
610    fn left_excess<T: ?Sized>(&mut self, a: &T)
611    where
612        T: Diff;
613
614    /// We've found an element that only appears in the right-hand sequence.
615    fn right_excess<T: ?Sized>(&mut self, b: &T)
616    where
617        T: Diff;
618
619    /// Consumes two iterators, diffing their contents. This is a convenience
620    /// method implemented in terms of the others.
621    fn diff_elements<T, I>(&mut self, a: I, b: I)
622    where
623        T: Diff,
624        I: IntoIterator<Item = T>,
625    {
626        for ab in a.into_iter().zip_longest(b) {
627            match ab {
628                EitherOrBoth::Both(a, b) => self.diff_element(&a, &b),
629                EitherOrBoth::Left(a) => self.left_excess(&a),
630                EitherOrBoth::Right(b) => self.right_excess(&b),
631            }
632        }
633    }
634
635    /// Complete the sequence and produce the result.
636    fn end(self) -> Result<Self::Ok, Self::Err>;
637}
638
639/// A type that can do something with information about differences in a
640/// map-like, key-value type.
641pub trait MapDiffer {
642    /// Type returned on success.
643    type Ok;
644    /// Type returned on failure.
645    type Err;
646
647    /// Both maps contain entries for `key`; check them for differences.
648    fn diff_entry<K, V>(&mut self, key: &K, a: &V, b: &V)
649    where
650        K: ?Sized + Debug,
651        V: ?Sized + Diff;
652
653    /// Key `key` is only present in the left map, with value `a`.
654    fn only_in_left<K, V>(&mut self, key: &K, a: &V)
655    where
656        K: ?Sized + Debug,
657        V: ?Sized + Diff;
658
659    /// Key `key` is only present in the right map, with value `b`.
660    fn only_in_right<K, V>(&mut self, key: &K, b: &V)
661    where
662        K: ?Sized + Debug,
663        V: ?Sized + Diff;
664
665    /// We've reached the end of the maps.
666    fn end(self) -> Result<Self::Ok, Self::Err>;
667}
668
669/// A type that can do something with information about differences in a
670/// set-like sequence type, i.e. one in which elements are expected to be
671/// unique.
672pub trait SetDiffer {
673    /// Type returned on success.
674    type Ok;
675    /// Type returned on failure.
676    type Err;
677
678    /// The sets contain `a` and `b` which compare as equal. Check them for
679    /// differences.
680    fn diff_equal<V>(&mut self, a: &V, b: &V)
681    where
682        V: ?Sized + Diff;
683
684    /// Value `a` is only in the left-hand set.
685    fn only_in_left<V>(&mut self, a: &V)
686    where
687        V: ?Sized + Diff;
688
689    /// Value `b` is only in the right-hand set.
690    fn only_in_right<V>(&mut self, b: &V)
691    where
692        V: ?Sized + Diff;
693
694    /// We've reached the end of the sets.
695    fn end(self) -> Result<Self::Ok, Self::Err>;
696}
697
698#[cfg(test)]
699mod tests {
700    use super::*;
701
702    #[derive(Clone, Debug)]
703    pub enum TestEnum {
704        First,
705        Second,
706        Struct { a: usize, b: bool },
707    }
708
709    impl Diff for TestEnum {
710        fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
711        where
712            D: Differ,
713        {
714            match (a, b) {
715                (TestEnum::First, TestEnum::First) => out.same(a, b),
716                (TestEnum::Second, TestEnum::Second) => out.same(a, b),
717                (
718                    TestEnum::Struct { a: aa, b: ab },
719                    TestEnum::Struct { a: ba, b: bb },
720                ) => {
721                    let mut s = out.begin_struct_variant("TestEnum", "Struct");
722                    s.diff_field("a", &aa, &ba);
723                    s.diff_field("b", &ab, &bb);
724                    s.end()
725                }
726                _ => out.difference(a, b),
727            }
728        }
729    }
730
731    #[derive(Clone, Debug)]
732    pub struct TestStruct {
733        pub distance: usize,
734        pub silly: bool,
735    }
736
737    impl Diff for TestStruct {
738        fn diff<D>(a: &Self, b: &Self, out: D) -> Result<D::Ok, D::Err>
739        where
740            D: Differ,
741        {
742            let mut s = out.begin_struct("TestStruct");
743            s.diff_field("distance", &a.distance, &b.distance);
744            s.diff_field("silly", &a.silly, &b.silly);
745            s.end()
746        }
747    }
748}