serde_diff/
lib.rs

1#![warn(missing_docs)]
2//! A small helper that can
3//! 1. Serialize the fields that differ between two structs of the same type
4//! 2. Apply previously serialized field differences to other structs
5//!
6//! The SerdeDiff trait impl can serialize field paths recursively,
7//! greatly reducing the amount of data that needs to be serialized
8//! when only a small part of a struct has changed.
9
10#[cfg(test)]
11mod tests;
12
13#[doc(hidden)]
14pub use serde as _serde;
15use serde::{de, ser::SerializeSeq};
16pub use serde_diff_derive::SerdeDiff;
17
18#[doc(hidden)]
19pub(crate) mod apply;
20pub(crate) mod config;
21pub(crate) mod counting_serializer;
22#[doc(hidden)]
23pub(crate) mod difference;
24pub(crate) mod implementation;
25
26pub use apply::Apply;
27pub use config::Config;
28pub use difference::Diff;
29
30// Used by the proc_macro
31pub use apply::ApplyContext;
32pub use difference::DiffContext;
33pub use difference::DiffPathElementValue;
34
35// NEXT STEPS:
36// - Decouple from serde_json as much as possible. We might need to use a "stream" format with
37//   well-defined data order to be able to use serde Deserializer trait. DONE
38// - Make all fields work again. DONE
39// - Make it work via proc macro. DONE
40// - Blanket impl or impl-via-macro common std types (i.e f32, i32, String). DONE
41// - Handle containers. DONE
42// - Ignore type mismatches instead of propagating the error. IMPOSSIBLE??
43//
44// A problem occurs when encoding the command stream for bincode:
45// We need to know the size of the list before we start serializing.
46// To do so, we need to implement the serde::ser::Serializer trait and
47// make the implementation only count up every time an element is serialized, doing nothing else.
48// This is implemented as CountingSerializer
49
50/// Anything diffable implements this trait
51pub trait SerdeDiff {
52    /// Recursively walk the struct, invoking serialize_element on each member if the element is
53    /// different. Returns true if any changes exist, otherwise false. After this call, the
54    /// DiffContext will contain the data that has changed.
55    fn diff<'a, S: SerializeSeq>(
56        &self,
57        ctx: &mut difference::DiffContext<'a, S>,
58        other: &Self,
59    ) -> Result<bool, S::Error>;
60
61    /// Applies the diff to the struct. Returns true if the struct was changed, otherwise false.
62    fn apply<'de, A>(
63        &mut self,
64        seq: &mut A,
65        ctx: &mut apply::ApplyContext,
66    ) -> Result<bool, <A as de::SeqAccess<'de>>::Error>
67    where
68        A: de::SeqAccess<'de>;
69}
70
71/// Configures how to serialize field identifiers
72#[derive(Copy, Clone)]
73pub enum FieldPathMode {
74    /// Use the field's string name as its identifier
75    Name,
76    /// Use the field's index in the struct as its identifier
77    Index,
78}
79
80pub(crate) enum ElementStackEntry<'a, S: SerializeSeq> {
81    PathElement(difference::DiffPathElementValue<'a>),
82    Closure(&'a dyn Fn(&mut S) -> Result<(), S::Error>),
83}