comparable/
types.rs

1use std::fmt::Debug;
2
3#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4#[derive(PartialEq, Debug)]
5pub enum Changed<T> {
6	Unchanged,
7	Changed(T),
8}
9
10impl<T> Changed<T> {
11	#[inline]
12	pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Changed<U> {
13		match self {
14			Changed::Unchanged => Changed::Unchanged,
15			Changed::Changed(x) => Changed::Changed(f(x)),
16		}
17	}
18
19	pub fn take(&mut self) -> Option<T> {
20		match std::mem::take(self) {
21			Changed::Unchanged => None,
22			Changed::Changed(x) => Some(x),
23		}
24	}
25
26	pub fn to_changes(&mut self) -> Vec<T> {
27		match std::mem::take(self) {
28			Changed::Unchanged => vec![],
29			Changed::Changed(x) => vec![x],
30		}
31	}
32
33	pub fn is_unchanged(&self) -> bool {
34		match self {
35			Changed::Unchanged => true,
36			Changed::Changed(_) => false,
37		}
38	}
39}
40
41impl<T: Default> Changed<T> {
42	#[inline]
43	pub fn unwrap_or_default(self) -> T {
44		match self {
45			Changed::Changed(x) => x,
46			Changed::Unchanged => Default::default(),
47		}
48	}
49}
50
51impl<T> Default for Changed<T> {
52	#[inline]
53	fn default() -> Self {
54		Changed::Unchanged
55	}
56}
57
58impl<T> From<Option<T>> for Changed<T> {
59	#[inline]
60	fn from(opt: Option<T>) -> Self {
61		match opt {
62			None => Changed::Unchanged,
63			Some(x) => Changed::Changed(x),
64		}
65	}
66}
67
68impl<T> Iterator for Changed<T> {
69	type Item = T;
70	fn next(&mut self) -> Option<T> {
71		self.take()
72	}
73}
74
75pub trait Comparable {
76	/// Describes the type under consideration. For types that use
77	/// `#[derive(Comparable)]` this is a mirror of the type itself, where all
78	/// field types refer to the `Comparable::Desc` associated type of the
79	/// original type.
80	type Desc: PartialEq + Debug;
81
82	/// Describe a value of a type.
83	fn describe(&self) -> Self::Desc;
84
85	/// Reflects all changes between two values of a type. The exact nature of
86	/// this type depends on the type being compared, for example, singleton
87	/// struts vary from structs with multiple fields. Please see the [full
88	/// documentation](https://docs.rs/comparable) for more details.
89	type Change: PartialEq + Debug;
90
91	/// Compare two values of a type, reporting whether they differ and what
92	/// the complete set of differences looks like. This is used by the
93	/// `comparable::assert_changes` function so that tests can ensure that
94	/// what was expected to happen did happen -- and nothing more.
95	fn comparison(&self, other: &Self) -> Changed<Self::Change>;
96}
97
98impl<T: Comparable> Comparable for &T {
99	type Desc = T::Desc;
100
101	fn describe(&self) -> Self::Desc {
102		(*self).describe()
103	}
104
105	type Change = T::Change;
106
107	fn comparison(&self, other: &Self) -> Changed<Self::Change> {
108		(*self).comparison(other)
109	}
110}