1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#![warn(missing_docs)]
//! A small helper that can
//! 1. Serialize the fields that differ between two structs of the same type
//! 2. Apply previously serialized field differences to other structs
//!
//! The SerdeDiff trait impl can serialize field paths recursively,
//! greatly reducing the amount of data that needs to be serialized
//! when only a small part of a struct has changed.

#[cfg(test)]
mod tests;

#[doc(hidden)]
pub use serde as _serde;
use serde::{de, ser::SerializeSeq};
pub use serde_diff_derive::SerdeDiff;

#[doc(hidden)]
pub(crate) mod apply;
pub(crate) mod config;
pub(crate) mod counting_serializer;
#[doc(hidden)]
pub(crate) mod difference;
pub(crate) mod implementation;

pub use apply::Apply;
pub use config::Config;
pub use difference::Diff;

// Used by the proc_macro
pub use apply::ApplyContext;
pub use difference::DiffContext;
pub use difference::DiffPathElementValue;

// NEXT STEPS:
// - Decouple from serde_json as much as possible. We might need to use a "stream" format with
//   well-defined data order to be able to use serde Deserializer trait. DONE
// - Make all fields work again. DONE
// - Make it work via proc macro. DONE
// - Blanket impl or impl-via-macro common std types (i.e f32, i32, String). DONE
// - Handle containers. DONE
// - Ignore type mismatches instead of propagating the error. IMPOSSIBLE??
//
// A problem occurs when encoding the command stream for bincode:
// We need to know the size of the list before we start serializing.
// To do so, we need to implement the serde::ser::Serializer trait and
// make the implementation only count up every time an element is serialized, doing nothing else.
// This is implemented as CountingSerializer

/// Anything diffable implements this trait
pub trait SerdeDiff {
    /// Recursively walk the struct, invoking serialize_element on each member if the element is
    /// different. Returns true if any changes exist, otherwise false. After this call, the
    /// DiffContext will contain the data that has changed.
    fn diff<'a, S: SerializeSeq>(
        &self,
        ctx: &mut difference::DiffContext<'a, S>,
        other: &Self,
    ) -> Result<bool, S::Error>;

    /// Applies the diff to the struct. Returns true if the struct was changed, otherwise false.
    fn apply<'de, A>(
        &mut self,
        seq: &mut A,
        ctx: &mut apply::ApplyContext,
    ) -> Result<bool, <A as de::SeqAccess<'de>>::Error>
    where
        A: de::SeqAccess<'de>;
}

/// Configures how to serialize field identifiers
#[derive(Copy, Clone)]
pub enum FieldPathMode {
    /// Use the field's string name as its identifier
    Name,
    /// Use the field's index in the struct as its identifier
    Index,
}

pub(crate) enum ElementStackEntry<'a, S: SerializeSeq> {
    PathElement(difference::DiffPathElementValue<'a>),
    Closure(&'a dyn Fn(&mut S) -> Result<(), S::Error>),
}