structdiff/
lib.rs

1#[cfg(feature = "nanoserde")]
2use nanoserde::{DeBin, SerBin};
3
4#[cfg(feature = "serde")]
5use serde::{de::DeserializeOwned, Serialize};
6
7pub use structdiff_derive::Difference;
8
9pub mod collections;
10
11#[cfg(all(feature = "nanoserde", feature = "serde", feature = "debug_diffs"))]
12pub(crate) mod __private {
13    use super::*;
14    pub trait StructDiffOwnedBound:
15        SerBin + DeBin + Serialize + DeserializeOwned + Clone + std::fmt::Debug
16    {
17    }
18    impl<T: SerBin + DeBin + Serialize + DeserializeOwned + Clone + std::fmt::Debug>
19        StructDiffOwnedBound for T
20    {
21    }
22
23    pub trait StructDiffRefBound: SerBin + Serialize + Clone + std::fmt::Debug {}
24    impl<T: SerBin + Serialize + Clone + std::fmt::Debug> StructDiffRefBound for T {}
25}
26
27#[cfg(all(feature = "nanoserde", not(feature = "serde"), feature = "debug_diffs"))]
28pub(crate) mod __private {
29    use super::*;
30
31    pub trait StructDiffOwnedBound: SerBin + DeBin + Clone + std::fmt::Debug {}
32    impl<T: SerBin + DeBin + Clone + std::fmt::Debug> StructDiffOwnedBound for T {}
33
34    pub trait StructDiffRefBound: SerBin + Clone + std::fmt::Debug {}
35    impl<T: SerBin + Clone + std::fmt::Debug> StructDiffRefBound for T {}
36}
37
38#[cfg(all(feature = "serde", not(feature = "nanoserde"), feature = "debug_diffs"))]
39pub(crate) mod __private {
40    use super::*;
41
42    pub trait StructDiffOwnedBound: Serialize + DeserializeOwned + Clone + std::fmt::Debug {}
43    impl<T: Serialize + DeserializeOwned + Clone + std::fmt::Debug> StructDiffOwnedBound for T {}
44
45    pub trait StructDiffRefBound: Serialize + Clone + std::fmt::Debug {}
46    impl<T: Serialize + Clone + std::fmt::Debug> StructDiffRefBound for T {}
47}
48
49#[cfg(all(
50    not(feature = "serde"),
51    not(feature = "nanoserde"),
52    feature = "debug_diffs"
53))]
54pub(crate) mod __private {
55    use super::*;
56
57    pub trait StructDiffOwnedBound: Clone + std::fmt::Debug {}
58    impl<T: Clone + std::fmt::Debug> StructDiffOwnedBound for T {}
59
60    pub trait StructDiffRefBound: Clone + std::fmt::Debug {}
61    impl<T: Clone + std::fmt::Debug> StructDiffRefBound for T {}
62}
63
64#[cfg(all(feature = "nanoserde", feature = "serde", not(feature = "debug_diffs")))]
65pub(crate) mod __private {
66    use super::*;
67    pub trait StructDiffOwnedBound: SerBin + DeBin + Serialize + DeserializeOwned + Clone {}
68    impl<T: SerBin + DeBin + Serialize + DeserializeOwned + Clone> StructDiffOwnedBound for T {}
69
70    pub trait StructDiffRefBound: SerBin + Serialize + Clone {}
71    impl<T: SerBin + Serialize + Clone> StructDiffRefBound for T {}
72}
73
74#[cfg(all(
75    feature = "nanoserde",
76    not(feature = "serde"),
77    not(feature = "debug_diffs")
78))]
79pub(crate) mod __private {
80    use super::*;
81
82    pub trait StructDiffOwnedBound: SerBin + DeBin + Clone {}
83    impl<T: SerBin + DeBin + Clone> StructDiffOwnedBound for T {}
84
85    pub trait StructDiffRefBound: SerBin + Clone {}
86    impl<T: SerBin + Clone> StructDiffRefBound for T {}
87}
88
89#[cfg(all(
90    feature = "serde",
91    not(feature = "nanoserde"),
92    not(feature = "debug_diffs")
93))]
94pub(crate) mod __private {
95    use super::*;
96
97    pub trait StructDiffOwnedBound: Serialize + DeserializeOwned + Clone {}
98    impl<T: Serialize + DeserializeOwned + Clone> StructDiffOwnedBound for T {}
99
100    pub trait StructDiffRefBound: Serialize + Clone {}
101    impl<T: Serialize + Clone> StructDiffRefBound for T {}
102}
103
104#[cfg(all(
105    not(feature = "serde"),
106    not(feature = "nanoserde"),
107    not(feature = "debug_diffs")
108))]
109pub(crate) mod __private {
110
111    pub trait StructDiffOwnedBound: Clone {}
112    impl<T: Clone> StructDiffOwnedBound for T {}
113
114    pub trait StructDiffRefBound: Clone {}
115    impl<T: Clone> StructDiffRefBound for T {}
116}
117
118pub trait StructDiff {
119    /// A generated type used to represent the difference
120    /// between two instances of a struct which implements
121    /// the StructDiff trait.
122    type Diff: __private::StructDiffOwnedBound;
123
124    /// A generated type used to represent the difference
125    /// between two instances of a struct which implements
126    /// the StructDiff trait (using references).
127    type DiffRef<'target>: __private::StructDiffRefBound + Into<Self::Diff>
128    where
129        Self: 'target;
130
131    /// Generate a diff between two instances of a struct.
132    /// This diff may be serialized if one of the serialization
133    /// features is enabled.
134    ///
135    /// ```
136    /// use structdiff::{Difference, StructDiff};
137    ///
138    /// #[derive(Debug, PartialEq, Clone, Difference)]
139    /// struct Example {
140    ///     field1: f64,
141    /// }
142    ///
143    /// let first = Example {
144    ///     field1: 0.0,
145    /// };
146    ///
147    /// let second = Example {
148    ///     field1: 3.14,
149    /// };
150    ///
151    /// let diffs: Vec<<Example as StructDiff>::Diff> = first.diff(&second);
152    ///
153    /// let diffed = first.apply(diffs);
154    /// assert_eq!(diffed, second);
155    /// ```
156    fn diff(&self, updated: &Self) -> Vec<Self::Diff>;
157
158    /// Generate a diff between two instances of a struct, for
159    /// use in passing to serializer. Much more efficient for
160    /// structs with large fields where the diff will not be stored.
161    ///
162    /// ```
163    /// use structdiff::{Difference, StructDiff};
164    ///
165    /// #[derive(Debug, PartialEq, Clone, Difference)]
166    /// struct Example {
167    ///     field1: f64,
168    /// }
169    ///
170    /// let first = Example {
171    ///     field1: 0.0,
172    /// };
173    ///
174    /// let second = Example {
175    ///     field1: 3.14,
176    /// };
177    ///
178    /// let diffs: Vec<<Example as StructDiff>::DiffRef<'_>> = first.diff_ref(&second);
179    ///
180    /// let diffed = first.clone().apply(diffs.into_iter().map(Into::into).collect());
181    /// assert_eq!(diffed, second);
182    /// ```
183    fn diff_ref<'target>(&'target self, updated: &'target Self) -> Vec<Self::DiffRef<'target>>;
184
185    /// Apply a single-field diff to a mutable self ref
186    fn apply_single(&mut self, diff: Self::Diff);
187
188    /// Apply a full diff to an owned self
189    fn apply(mut self, diffs: Vec<Self::Diff>) -> Self
190    where
191        Self: Sized,
192    {
193        for diff in diffs {
194            self.apply_single(diff);
195        }
196        self
197    }
198
199    /// Apply a full diff to a self ref, returning a cloned version of self
200    /// after diff is applied
201    fn apply_ref(&self, diffs: Vec<Self::Diff>) -> Self
202    where
203        Self: Clone,
204    {
205        self.clone().apply(diffs)
206    }
207
208    /// Apply a full diff to a mutable self ref
209    fn apply_mut(&mut self, diffs: Vec<Self::Diff>) {
210        for diff in diffs {
211            self.apply_single(diff);
212        }
213    }
214}