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}