#![warn(missing_docs)]
#[cfg(test)]
mod tests;
use crate as serde_diff;
#[doc(hidden)]
pub use serde as _serde;
use serde::{
de,
ser::{self, SerializeSeq},
Deserialize, Serialize, Serializer,
};
pub use serde_diff_derive::SerdeDiff;
use std::{
borrow::Cow,
cell::Cell,
collections::{BTreeMap, HashMap},
hash::Hash,
};
pub trait SerdeDiff {
fn diff<'a, S: SerializeSeq>(
&self,
ctx: &mut DiffContext<'a, S>,
other: &Self,
) -> Result<bool, S::Error>;
fn apply<'de, A>(
&mut self,
seq: &mut A,
ctx: &mut ApplyContext,
) -> Result<bool, <A as de::SeqAccess<'de>>::Error>
where
A: de::SeqAccess<'de>;
}
#[derive(Copy, Clone)]
pub enum FieldPathMode {
Name,
Index,
}
enum ElementStackEntry<'a, S: SerializeSeq> {
PathElement(DiffPathElementValue<'a>),
Closure(&'a dyn Fn(&mut S) -> Result<(), S::Error>),
}
#[doc(hidden)]
pub struct DiffContext<'a, S: SerializeSeq> {
element_stack: Option<Vec<ElementStackEntry<'a, S>>>,
serializer: &'a mut S,
implicit_exit_written: bool,
parent_element_stack: Option<&'a mut Option<Vec<ElementStackEntry<'a, S>>>>,
element_stack_start: usize,
field_path_mode: FieldPathMode,
has_changes: bool,
}
impl<'a, S: SerializeSeq> Drop for DiffContext<'a, S> {
fn drop(&mut self) {
if let Some(parent) = self.parent_element_stack.take() {
if let Some(mut stack) = self.element_stack.take() {
if self.element_stack_start < stack.len() {
stack.drain(self.element_stack_start..);
}
parent.replace(stack);
}
}
}
}
#[doc(hidden)]
impl<'a, S: SerializeSeq> DiffContext<'a, S> {
pub fn field_path_mode(&self) -> FieldPathMode {
self.field_path_mode
}
pub fn has_changes(&self) -> bool {
self.has_changes
}
pub fn push_field(&mut self, field_name: &'static str) {
self.element_stack
.as_mut()
.unwrap()
.push(ElementStackEntry::PathElement(DiffPathElementValue::Field(
Cow::Borrowed(field_name),
)));
}
pub fn push_field_index(&mut self, field_idx: u16) {
self.element_stack
.as_mut()
.unwrap()
.push(ElementStackEntry::PathElement(
DiffPathElementValue::FieldIndex(field_idx),
));
}
pub fn push_collection_index(&mut self, idx: usize) {
self.element_stack
.as_mut()
.unwrap()
.push(ElementStackEntry::PathElement(
DiffPathElementValue::CollectionIndex(idx),
));
}
pub fn push_collection_add(&mut self) {
self.element_stack
.as_mut()
.unwrap()
.push(ElementStackEntry::PathElement(
DiffPathElementValue::AddToCollection,
));
}
pub fn push_field_element(&mut self, f: &'a dyn Fn(&mut S) -> Result<(), S::Error>) {
self.element_stack
.as_mut()
.unwrap()
.push(ElementStackEntry::Closure(f));
}
pub fn pop_path_element(&mut self) -> Result<(), S::Error> {
let element_stack = self.element_stack.as_mut().unwrap();
if element_stack.is_empty() {
if !self.implicit_exit_written {
let cmd = DiffCommandRef::<()>::Exit;
self.serializer.serialize_element(&cmd)
} else {
self.implicit_exit_written = false;
Ok(())
}
} else {
element_stack.pop();
self.element_stack_start = std::cmp::min(element_stack.len(), self.element_stack_start);
Ok(())
}
}
pub fn save_value<T: Serialize>(&mut self, value: &T) -> Result<(), S::Error> {
self.save_command(&DiffCommandRef::Value(value), true, true)
}
pub fn save_command<'b, T: Serialize>(
&mut self,
value: &DiffCommandRef<'b, T>,
implicit_exit: bool,
is_change: bool,
) -> Result<(), S::Error> {
let element_stack = self.element_stack.as_mut().unwrap();
if !element_stack.is_empty() {
for element in element_stack.drain(0..element_stack.len()) {
match element {
ElementStackEntry::PathElement(element) => self
.serializer
.serialize_element(&DiffCommandRef::<()>::Enter(element))?,
ElementStackEntry::Closure(closure) => (closure)(&mut self.serializer)?,
};
}
self.element_stack_start = 0;
}
self.has_changes |= is_change;
self.implicit_exit_written = implicit_exit;
self.serializer.serialize_element(value)
}
pub fn reborrow<'c, 'd: 'c>(&'d mut self) -> DiffContext<'c, S>
where
'a: 'c,
'a: 'd,
{
let element_stack = self.element_stack.take();
let element_stack_ref = unsafe {
std::mem::transmute::<
&'d mut Option<Vec<ElementStackEntry<'a, S>>>,
&'c mut Option<Vec<ElementStackEntry<'c, S>>>,
>(&mut self.element_stack)
};
DiffContext {
element_stack_start: element_stack.as_ref().unwrap().len(),
element_stack,
parent_element_stack: Some(element_stack_ref),
serializer: &mut *self.serializer,
implicit_exit_written: self.implicit_exit_written,
field_path_mode: self.field_path_mode,
has_changes: false,
}
}
}
pub struct Config {
field_path_mode: FieldPathMode,
}
impl Default for Config {
fn default() -> Self {
Self {
field_path_mode: FieldPathMode::Name,
}
}
}
impl Config {
pub fn new() -> Self {
<Self as Default>::default()
}
pub fn with_field_path_mode(mut self, mode: FieldPathMode) -> Self {
self.field_path_mode = mode;
self
}
pub fn serializable_diff<'a, 'b, T: SerdeDiff + 'a + 'b>(
self,
old: &'a T,
new: &'b T,
) -> Diff<'a, 'b, T> {
Diff {
old,
new,
field_path_mode: self.field_path_mode,
has_changes: Cell::new(false),
}
}
pub fn diff<'a, 'b, S: Serializer, T: SerdeDiff + 'a + 'b>(
self,
serializer: S,
old: &'a T,
new: &'b T,
) -> Result<S::Ok, S::Error> {
self.serializable_diff(old, new).serialize(serializer)
}
pub fn deserializable_apply<'a, T: SerdeDiff>(self, target: &'a mut T) -> Apply<'a, T> {
Apply { target }
}
pub fn apply<'de, D, T: SerdeDiff>(
self,
deserializer: D,
target: &mut T,
) -> Result<(), <D as de::Deserializer<'de>>::Error>
where
D: de::Deserializer<'de>,
{
deserializer.deserialize_seq(self.deserializable_apply(target))
}
}
pub struct Diff<'a, 'b, T> {
old: &'a T,
new: &'b T,
field_path_mode: FieldPathMode,
has_changes: Cell<bool>,
}
impl<'a, 'b, T: SerdeDiff + 'a + 'b> Diff<'a, 'b, T> {
pub fn serializable(old: &'a T, new: &'b T) -> Self {
Config::default().serializable_diff(old, new)
}
pub fn diff<S: Serializer>(serializer: S, old: &'a T, new: &'b T) -> Result<S::Ok, S::Error> {
Config::default().diff(serializer, old, new)
}
pub fn has_changes(&self) -> bool {
self.has_changes.get()
}
}
impl<'a, 'b, T: SerdeDiff> Serialize for Diff<'a, 'b, T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.has_changes.set(false);
let num_elements = if !serializer.is_human_readable() {
let mut serializer = CountingSerializer { num_elements: 0 };
let mut seq = serializer.serialize_seq(None).unwrap();
{
let mut ctx = DiffContext {
element_stack_start: 0,
element_stack: Some(Vec::new()),
serializer: &mut seq,
implicit_exit_written: false,
parent_element_stack: None,
field_path_mode: self.field_path_mode,
has_changes: false,
};
self.old.diff(&mut ctx, &self.new).unwrap();
}
seq.end().unwrap();
Some(serializer.num_elements)
} else {
None
};
let mut seq = serializer.serialize_seq(num_elements)?;
{
let mut ctx = DiffContext {
element_stack_start: 0,
element_stack: Some(Vec::new()),
serializer: &mut seq,
implicit_exit_written: false,
parent_element_stack: None,
field_path_mode: self.field_path_mode,
has_changes: false,
};
self.old.diff(&mut ctx, &self.new)?;
self.has_changes.set(ctx.has_changes);
}
Ok(seq.end()?)
}
}
pub struct Apply<'a, T: SerdeDiff> {
target: &'a mut T,
}
impl<'a, 'de, T: SerdeDiff> Apply<'a, T> {
pub fn deserializable(target: &'a mut T) -> Self {
Config::default().deserializable_apply(target)
}
pub fn apply<D>(
deserializer: D,
target: &mut T,
) -> Result<(), <D as de::Deserializer<'de>>::Error>
where
D: de::Deserializer<'de>,
{
Config::default().apply(deserializer, target)
}
}
impl<'a, 'de, T: SerdeDiff> de::DeserializeSeed<'de> for Apply<'a, T> {
type Value = ();
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: de::Deserializer<'de>,
{
deserializer.deserialize_seq(self)
}
}
impl<'a, 'de, T: SerdeDiff> de::Visitor<'de> for Apply<'a, T> {
type Value = ();
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "a sequence containing DiffCommands")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, <A as de::SeqAccess<'de>>::Error>
where
A: de::SeqAccess<'de>,
{
let mut ctx = ApplyContext {};
self.target.apply(&mut seq, &mut ctx)?;
Ok(())
}
}
#[doc(hidden)]
pub struct ApplyContext {}
impl ApplyContext {
pub fn next_path_element<'de, A>(
&mut self,
seq: &mut A,
) -> Result<Option<DiffPathElementValue<'de>>, <A as de::SeqAccess<'de>>::Error>
where
A: de::SeqAccess<'de>,
{
use DiffCommandValue::*;
let element = match seq.next_element_seed(DiffCommandIgnoreValue {})? {
Some(Enter(element)) => Ok(Some(element)),
Some(AddKey(_)) | Some(EnterKey(_)) | Some(RemoveKey(_)) => {
Ok(None)
}
Some(Value(_)) | Some(Remove(_)) => panic!("unexpected DiffCommand Value or Remove"),
Some(Exit) | Some(Nothing) | Some(DeserializedValue) | None => Ok(None),
};
element
}
pub fn skip_value<'de, A>(
&mut self,
seq: &mut A,
) -> Result<(), <A as de::SeqAccess<'de>>::Error>
where
A: de::SeqAccess<'de>,
{
self.skip_value_internal(seq, 1)
}
fn skip_value_internal<'de, A>(
&mut self,
seq: &mut A,
mut depth: i32,
) -> Result<(), <A as de::SeqAccess<'de>>::Error>
where
A: de::SeqAccess<'de>,
{
while let Some(cmd) = seq.next_element_seed(DiffCommandIgnoreValue {})? {
match cmd {
DiffCommandValue::Enter(_)
| DiffCommandValue::AddKey(_)
| DiffCommandValue::EnterKey(_) => depth += 1,
DiffCommandValue::Exit => depth -= 1,
DiffCommandValue::Value(_) | DiffCommandValue::Remove(_) => depth -= 1,
DiffCommandValue::RemoveKey(_) => {}
DiffCommandValue::Nothing | DiffCommandValue::DeserializedValue => {
panic!("should never serialize cmd Nothing or DeserializedValue")
}
}
if depth == 0 {
break;
}
}
if depth != 0 {
panic!("mismatched DiffCommand::Enter/Exit ")
}
Ok(())
}
pub fn read_value<'de, A, T: for<'c> Deserialize<'c>>(
&mut self,
seq: &mut A,
val: &mut T,
) -> Result<bool, <A as de::SeqAccess<'de>>::Error>
where
A: de::SeqAccess<'de>,
{
let cmd = seq.next_element_seed::<DiffCommandDeserWrapper<T>>(DiffCommandDeserWrapper {
val_wrapper: DeserWrapper { val },
})?;
match cmd {
Some(DiffCommandValue::DeserializedValue) => return Ok(true),
Some(DiffCommandValue::Enter(_)) => {
self.skip_value_internal(seq, 1)?;
}
Some(DiffCommandValue::Exit) => panic!("unexpected Exit command"),
_ => {}
}
Ok(false)
}
pub fn read_next_command<'de, A, T: for<'c> Deserialize<'c>>(
&mut self,
seq: &mut A,
) -> Result<Option<DiffCommandValue<'de, T>>, <A as de::SeqAccess<'de>>::Error>
where
A: de::SeqAccess<'de>,
{
let cmd = seq.next_element::<DiffCommandValue<'de, T>>()?;
Ok(match cmd {
cmd @ Some(DiffCommandValue::Remove(_))
| cmd @ Some(DiffCommandValue::Value(_))
| cmd @ Some(DiffCommandValue::Enter(_))
| cmd @ Some(DiffCommandValue::AddKey(_))
| cmd @ Some(DiffCommandValue::EnterKey(_))
| cmd @ Some(DiffCommandValue::RemoveKey(_))
| cmd @ Some(DiffCommandValue::Exit) => cmd,
_ => None,
})
}
}
struct DeserWrapper<'a, T> {
val: &'a mut T,
}
struct DiffCommandDeserWrapper<'a, T> {
val_wrapper: DeserWrapper<'a, T>,
}
enum DiffCommandField {
Enter,
Value,
Remove,
AddKey,
EnterKey,
RemoveKey,
Exit,
}
struct DiffCommandFieldVisitor;
const VARIANTS: &'static [&'static str] = &[
"Enter",
"Value",
"Remove",
"AddKey",
"EnterKey",
"RemoveKey",
"Exit",
];
impl<'de> de::Visitor<'de> for DiffCommandFieldVisitor {
type Value = DiffCommandField;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Formatter::write_str(formatter, "variant identifier")
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
match value {
0u64 => Ok(DiffCommandField::Enter),
1u64 => Ok(DiffCommandField::Value),
2u64 => Ok(DiffCommandField::Remove),
3u64 => Ok(DiffCommandField::AddKey),
4u64 => Ok(DiffCommandField::EnterKey),
5u64 => Ok(DiffCommandField::RemoveKey),
6u64 => Ok(DiffCommandField::Exit),
_ => Err(de::Error::invalid_value(
de::Unexpected::Unsigned(value),
&"variant index 0 <= i < 7",
)),
}
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
match value {
"Enter" => Ok(DiffCommandField::Enter),
"Value" => Ok(DiffCommandField::Value),
"Remove" => Ok(DiffCommandField::Remove),
"AddKey" => Ok(DiffCommandField::AddKey),
"EnterKey" => Ok(DiffCommandField::EnterKey),
"RemoveKey" => Ok(DiffCommandField::RemoveKey),
"Exit" => Ok(DiffCommandField::Exit),
_ => Err(de::Error::unknown_variant(value, VARIANTS)),
}
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
match value {
b"Enter" => Ok(DiffCommandField::Enter),
b"Value" => Ok(DiffCommandField::Value),
b"Remove" => Ok(DiffCommandField::Remove),
b"AddKey" => Ok(DiffCommandField::AddKey),
b"EnterKey" => Ok(DiffCommandField::EnterKey),
b"RemoveKey" => Ok(DiffCommandField::RemoveKey),
b"Exit" => Ok(DiffCommandField::Exit),
_ => {
let value = &serde::export::from_utf8_lossy(value);
Err(de::Error::unknown_variant(value, VARIANTS))
}
}
}
}
impl<'de> Deserialize<'de> for DiffCommandField {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
de::Deserializer::deserialize_identifier(deserializer, DiffCommandFieldVisitor)
}
}
impl<'a, 'de, T> de::DeserializeSeed<'de> for DiffCommandDeserWrapper<'a, T>
where
T: de::Deserialize<'de>,
{
type Value = DiffCommandValue<'de, T>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor<'de, 'a, T>
where
T: de::Deserialize<'de>,
{
seed: DeserWrapper<'a, T>,
lifetime: std::marker::PhantomData<&'de ()>,
}
impl<'de, 'a, T> de::Visitor<'de> for Visitor<'de, 'a, T>
where
T: de::Deserialize<'de>,
{
type Value = DiffCommandValue<'de, T>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Formatter::write_str(formatter, "enum DiffCommandValueTest")
}
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
where
A: de::EnumAccess<'de>,
{
match de::EnumAccess::variant(data)? {
(DiffCommandField::Enter, variant) => {
let enter =
de::VariantAccess::newtype_variant::<DiffPathElementValue>(variant)?;
Ok(DiffCommandValue::Enter(enter))
}
(DiffCommandField::Value, variant)
| (DiffCommandField::AddKey, variant)
| (DiffCommandField::EnterKey, variant)
| (DiffCommandField::RemoveKey, variant) => {
de::VariantAccess::newtype_variant_seed::<DeserWrapper<T>>(
variant, self.seed,
)?;
Ok(DiffCommandValue::DeserializedValue)
}
(DiffCommandField::Remove, variant) => {
let num_elements = de::VariantAccess::newtype_variant::<usize>(variant)?;
Ok(DiffCommandValue::Remove(num_elements))
}
(DiffCommandField::Exit, variant) => {
de::VariantAccess::unit_variant(variant)?;
Ok(DiffCommandValue::Exit)
}
}
}
}
de::Deserializer::deserialize_enum(
deserializer,
"DiffCommandValueTest",
VARIANTS,
Visitor {
seed: self.val_wrapper,
lifetime: std::marker::PhantomData,
},
)
}
}
impl<'a, 'de, T: Deserialize<'de>> de::DeserializeSeed<'de> for DeserWrapper<'a, T> {
type Value = Self;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: de::Deserializer<'de>,
{
Deserialize::deserialize_in_place(deserializer, self.val)?;
Ok(self)
}
}
struct DiffCommandIgnoreValue;
impl<'de> de::DeserializeSeed<'de> for DiffCommandIgnoreValue {
type Value = DiffCommandValue<'de, ()>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor<'de> {
lifetime: std::marker::PhantomData<&'de ()>,
}
impl<'de> de::Visitor<'de> for Visitor<'de> {
type Value = DiffCommandValue<'de, ()>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Formatter::write_str(formatter, "enum DiffCommandValueTest")
}
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
where
A: de::EnumAccess<'de>,
{
match de::EnumAccess::variant(data)? {
(DiffCommandField::Enter, variant) => {
let enter =
de::VariantAccess::newtype_variant::<DiffPathElementValue>(variant)?;
Ok(DiffCommandValue::Enter(enter))
}
(DiffCommandField::Value, variant)
| (DiffCommandField::AddKey, variant)
| (DiffCommandField::EnterKey, variant)
| (DiffCommandField::RemoveKey, variant) => {
de::VariantAccess::newtype_variant::<de::IgnoredAny>(variant)?;
Ok(DiffCommandValue::Value(()))
}
(DiffCommandField::Remove, variant) => {
let num_elements = de::VariantAccess::newtype_variant::<usize>(variant)?;
Ok(DiffCommandValue::Remove(num_elements))
}
(DiffCommandField::Exit, variant) => {
de::VariantAccess::unit_variant(variant)?;
Ok(DiffCommandValue::Exit)
}
}
}
}
de::Deserializer::deserialize_enum(
deserializer,
"DiffCommandValueTest",
VARIANTS,
Visitor {
lifetime: std::marker::PhantomData,
},
)
}
}
#[doc(hidden)]
#[derive(Serialize, Debug)]
pub enum DiffCommandRef<'a, T: Serialize> {
Enter(DiffPathElementValue<'a>),
Value(&'a T),
Remove(usize),
AddKey(&'a T),
EnterKey(&'a T),
RemoveKey(&'a T),
Exit,
}
#[doc(hidden)]
#[derive(Deserialize, Debug)]
pub enum DiffCommandValue<'a, T> {
#[serde(borrow)]
Enter(DiffPathElementValue<'a>),
Value(T),
Remove(usize),
AddKey(T),
EnterKey(T),
RemoveKey(T),
Exit,
Nothing,
DeserializedValue,
}
#[doc(hidden)]
#[derive(Serialize, Deserialize, Debug)]
pub enum DiffPathElementValue<'a> {
#[serde(borrow)]
Field(Cow<'a, str>),
FieldIndex(u16),
CollectionIndex(usize),
AddToCollection,
}
impl<T: SerdeDiff + Serialize + for<'a> Deserialize<'a>> SerdeDiff for Vec<T> {
fn diff<'a, S: SerializeSeq>(
&self,
ctx: &mut DiffContext<'a, S>,
other: &Self,
) -> Result<bool, S::Error> {
let mut self_iter = self.iter();
let mut other_iter = other.iter();
let mut idx = 0;
let mut need_exit = false;
let mut changed = false;
loop {
let self_item = self_iter.next();
let other_item = other_iter.next();
match (self_item, other_item) {
(None, None) => break,
(Some(_), None) => {
let mut num_to_remove = 1;
while self_iter.next().is_some() {
num_to_remove += 1;
}
ctx.save_command::<()>(&DiffCommandRef::Remove(num_to_remove), true, true)?;
changed = true;
need_exit = false;
}
(None, Some(other_item)) => {
ctx.save_command::<()>(
&DiffCommandRef::Enter(DiffPathElementValue::AddToCollection),
false,
true,
)?;
ctx.save_command(&DiffCommandRef::Value(other_item), true, true)?;
need_exit = true;
changed = true;
}
(Some(self_item), Some(other_item)) => {
ctx.push_collection_index(idx);
if <T as SerdeDiff>::diff(self_item, ctx, other_item)? {
need_exit = true;
changed = true;
}
ctx.pop_path_element()?;
}
}
idx += 1;
}
if need_exit {
ctx.save_command::<()>(&DiffCommandRef::Exit, true, false)?;
}
Ok(changed)
}
fn apply<'de, A>(
&mut self,
seq: &mut A,
ctx: &mut ApplyContext,
) -> Result<bool, <A as de::SeqAccess<'de>>::Error>
where
A: de::SeqAccess<'de>,
{
let mut changed = false;
while let Some(cmd) = ctx.read_next_command::<A, T>(seq)? {
use DiffCommandValue::*;
use DiffPathElementValue::*;
match cmd {
Enter(Field(_)) => {
ctx.skip_value(seq)?;
break;
}
Enter(CollectionIndex(idx)) => {
if let Some(value_ref) = self.get_mut(idx) {
changed |= <T as SerdeDiff>::apply(value_ref, seq, ctx)?;
} else {
ctx.skip_value(seq)?;
}
}
Enter(AddToCollection) => {
if let Value(v) = ctx
.read_next_command(seq)?
.expect("Expected value after AddToCollection")
{
changed = true;
self.push(v);
} else {
panic!("Expected value after AddToCollection");
}
}
Remove(num_elements) => {
let new_length = self.len().saturating_sub(num_elements);
self.truncate(new_length);
changed = true;
break;
}
_ => break,
}
}
Ok(changed)
}
}
macro_rules! array_impls {
($($len:tt)+) => {
$(
impl<T: $crate::SerdeDiff + serde::Serialize + for<'a> serde::Deserialize<'a>> $crate::SerdeDiff for [T; $len] {
fn diff<'a, S: serde::ser::SerializeSeq>(
&self,
ctx: &mut $crate::DiffContext<'a, S>,
other: &Self,
) -> Result<bool, S::Error> {
use $crate::DiffCommandRef;
let mut need_exit = false;
let mut changed = false;
for (idx, (self_item, other_item)) in self.iter().zip(other.iter()).enumerate() {
ctx.push_collection_index(idx);
if <T as $crate::SerdeDiff>::diff(self_item, ctx, other_item)? {
need_exit = true;
changed = true;
}
ctx.pop_path_element()?;
}
if need_exit {
ctx.save_command::<()>(&DiffCommandRef::Exit, true, false)?;
}
Ok(changed)
}
fn apply<'de, A>(
&mut self,
seq: &mut A,
ctx: &mut $crate::ApplyContext,
) -> Result<bool, <A as serde::de::SeqAccess<'de>>::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut changed = false;
while let Some(cmd) = ctx.read_next_command::<A, T>(seq)? {
use $crate::DiffCommandValue::*;
use $crate::DiffPathElementValue::*;
match cmd {
Enter(Field(_)) => {
ctx.skip_value(seq)?;
break;
}
Enter(CollectionIndex(idx)) => {
if let Some(value_ref) = self.get_mut(idx) {
changed |= <T as $crate::SerdeDiff>::apply(value_ref, seq, ctx)?;
} else {
ctx.skip_value(seq)?;
}
}
_ => break,
}
}
Ok(changed)
}
}
)+
}
}
array_impls! {
01 02 03 04 05 06 07 08 09 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32
40 48 50 56 64 72 96 100 128 160 192 200 224 256 384 512
768 1024 2048 4096 8192 16384 32768 65536
}
macro_rules! tuple_impls {
($($len:expr => ($($n:tt $name:ident)+))+) => {
$(
impl<$($name),+> $crate::SerdeDiff for ($($name,)+)
where
$($name: $crate::SerdeDiff + serde::Serialize + for<'a> serde::Deserialize<'a>,)+
{
fn diff<'a, S: serde::ser::SerializeSeq>(
&self,
ctx: &mut $crate::DiffContext<'a, S>,
other: &Self,
) -> Result<bool, S::Error> {
let mut changed = false;
$(
ctx.push_field(stringify!($n));
changed |= <$name as serde_diff::SerdeDiff>::diff(&self.$n, ctx, &other.$n)?;
ctx.pop_path_element()?;
)+
Ok(changed)
}
fn apply<'de, A>(
&mut self,
seq: &mut A,
ctx: &mut $crate::ApplyContext,
) -> Result<bool, <A as serde::de::SeqAccess<'de>>::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut changed = false;
while let Some(serde_diff::DiffPathElementValue::Field(element)) = ctx.next_path_element(seq)? {
match element.as_ref() {
$(
stringify!($n) => changed |= <$name as serde_diff::SerdeDiff>::apply(&mut self.$n, seq, ctx)?,
)+
_ => ctx.skip_value(seq)?,
}
}
Ok(changed)
}
}
)+
}
}
tuple_impls! {
1 => (0 T0)
2 => (0 T0 1 T1)
3 => (0 T0 1 T1 2 T2)
4 => (0 T0 1 T1 2 T2 3 T3)
5 => (0 T0 1 T1 2 T2 3 T3 4 T4)
6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12)
14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13)
15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14)
16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15)
}
macro_rules! map_serde_diff {
($t:ty, $($extra_traits:path),*) => {
impl<K, V> SerdeDiff for $t
where
K: SerdeDiff + Serialize + for<'a> Deserialize<'a> $(+ $extra_traits)*,
V: SerdeDiff + Serialize + for<'a> Deserialize<'a>,
{
fn diff<'a, S: SerializeSeq>(
&self,
ctx: &mut DiffContext<'a, S>,
other: &Self,
) -> Result<bool, S::Error> {
let mut changed = false;
for (key, self_value) in self.iter() {
match other.get(key) {
Some(other_value) => {
let save_closure = |serializer: &mut S| serializer.serialize_element(&DiffCommandRef::EnterKey(key));
let mut subctx = ctx.reborrow();
subctx.push_field_element(&save_closure);
if <V as SerdeDiff>::diff(self_value, &mut subctx, other_value)? {
changed = true;
}
},
None => {
ctx.save_command(&DiffCommandRef::RemoveKey(key), true, true)?;
changed = true;
},
}
}
for (key, other_value) in other.iter() {
if !self.contains_key(key) {
ctx.save_command(&DiffCommandRef::AddKey(key), true, true)?;
ctx.save_command(&DiffCommandRef::Value(other_value), true, true)?;
changed = true;
}
}
if changed {
ctx.save_command::<()>(&DiffCommandRef::Exit, true, false)?;
}
Ok(changed)
}
fn apply<'de, A>(
&mut self,
seq: &mut A,
ctx: &mut ApplyContext,
) -> Result<bool, <A as de::SeqAccess<'de>>::Error>
where
A: de::SeqAccess<'de>,
{
let mut changed = false;
while let Some(cmd) = ctx.read_next_command::<A, K>(seq)? {
use DiffCommandValue::*;
use DiffPathElementValue::*;
match cmd {
Enter(Field(_)) => {
ctx.skip_value(seq)?;
break;
}
AddKey(key) => if let Some(Value(v)) = ctx.read_next_command(seq)? {
self.insert(key, v);
changed = true;
} else {
panic!("Expected value after AddKey");
}
EnterKey(key) => if let Some(value_ref) = self.get_mut(&key) {
changed |= <V as SerdeDiff>::apply(value_ref, seq, ctx)?;
} else {
ctx.skip_value(seq)?;
}
RemoveKey(key) => changed |= self.remove(&key).is_some(),
_ => break,
}
}
Ok(changed)
}
}
};
}
map_serde_diff!(HashMap<K, V>, Hash, Eq);
map_serde_diff!(BTreeMap<K, V>, Ord);
#[macro_export]
macro_rules! opaque_serde_diff {
($t:ty) => {
impl SerdeDiff for $t {
fn diff<'a, S: serde_diff::_serde::ser::SerializeSeq>(
&self,
ctx: &mut serde_diff::DiffContext<'a, S>,
other: &Self,
) -> Result<bool, S::Error> {
if self != other {
ctx.save_value(other)?;
Ok(true)
} else {
Ok(false)
}
}
fn apply<'de, A>(
&mut self,
seq: &mut A,
ctx: &mut serde_diff::ApplyContext,
) -> Result<bool, <A as serde_diff::_serde::de::SeqAccess<'de>>::Error>
where
A: serde_diff::_serde::de::SeqAccess<'de>,
{
ctx.read_value(seq, self)
}
}
};
}
opaque_serde_diff!(bool);
opaque_serde_diff!(isize);
opaque_serde_diff!(i8);
opaque_serde_diff!(i16);
opaque_serde_diff!(i32);
opaque_serde_diff!(i64);
opaque_serde_diff!(usize);
opaque_serde_diff!(u8);
opaque_serde_diff!(u16);
opaque_serde_diff!(u32);
opaque_serde_diff!(u64);
opaque_serde_diff!(i128);
opaque_serde_diff!(u128);
opaque_serde_diff!(f32);
opaque_serde_diff!(f64);
opaque_serde_diff!(char);
opaque_serde_diff!(String);
opaque_serde_diff!(std::ffi::CString);
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
opaque_serde_diff!(std::ffi::OsString);
opaque_serde_diff!(std::num::NonZeroU8);
opaque_serde_diff!(std::num::NonZeroU16);
opaque_serde_diff!(std::num::NonZeroU32);
opaque_serde_diff!(std::num::NonZeroU64);
opaque_serde_diff!(std::time::Duration);
opaque_serde_diff!(std::time::SystemTime);
opaque_serde_diff!(std::net::IpAddr);
opaque_serde_diff!(std::net::Ipv4Addr);
opaque_serde_diff!(std::net::Ipv6Addr);
opaque_serde_diff!(std::net::SocketAddr);
opaque_serde_diff!(std::net::SocketAddrV4);
opaque_serde_diff!(std::net::SocketAddrV6);
opaque_serde_diff!(std::path::PathBuf);
impl<T: SerdeDiff + Serialize + for<'a> Deserialize<'a>> SerdeDiff for Option<T> {
fn diff<'a, S: SerializeSeq>(
&self,
ctx: &mut DiffContext<'a, S>,
other: &Self,
) -> Result<bool, S::Error> {
let mut self_iter = self.iter();
let mut other_iter = other.iter();
let mut idx = 0;
let mut need_exit = false;
let mut changed = false;
loop {
let self_item = self_iter.next();
let other_item = other_iter.next();
match (self_item, other_item) {
(None, None) => break,
(Some(_), None) => {
let mut num_to_remove = 1;
while self_iter.next().is_some() {
num_to_remove += 1;
}
ctx.save_command::<()>(&DiffCommandRef::Remove(num_to_remove), true, true)?;
changed = true;
}
(None, Some(other_item)) => {
ctx.save_command::<()>(
&DiffCommandRef::Enter(DiffPathElementValue::AddToCollection),
false,
true,
)?;
ctx.save_command(&DiffCommandRef::Value(other_item), true, true)?;
need_exit = true;
changed = true;
}
(Some(self_item), Some(other_item)) => {
ctx.push_collection_index(idx);
if <T as SerdeDiff>::diff(self_item, ctx, other_item)? {
need_exit = true;
changed = true;
}
ctx.pop_path_element()?;
}
}
idx += 1;
}
if need_exit {
ctx.save_command::<()>(&DiffCommandRef::Exit, true, false)?;
}
Ok(changed)
}
fn apply<'de, A>(
&mut self,
seq: &mut A,
ctx: &mut ApplyContext,
) -> Result<bool, <A as de::SeqAccess<'de>>::Error>
where
A: de::SeqAccess<'de>,
{
let mut changed = false;
while let Some(cmd) = ctx.read_next_command::<A, T>(seq)? {
use DiffCommandValue::*;
use DiffPathElementValue::*;
match cmd {
Enter(Field(_)) => {
ctx.skip_value(seq)?;
break;
}
Enter(CollectionIndex(0)) => {
if let Some(value_ref) = self {
changed |= <T as SerdeDiff>::apply(value_ref, seq, ctx)?;
} else {
ctx.skip_value(seq)?;
}
}
Enter(AddToCollection) => {
if let Value(v) = ctx
.read_next_command(seq)?
.expect("Expected value after AddToCollection")
{
debug_assert!(self.is_none());
changed = true;
*self = Some(v);
} else {
panic!("Expected value after AddToCollection");
}
}
Remove(1) => {
*self = None;
changed = true;
break;
}
_ => break,
}
}
Ok(changed)
}
}
type Unit = ();
opaque_serde_diff!(Unit);
struct CountingSerializer {
num_elements: usize,
}
#[derive(Debug)]
struct CountingSerializerError;
impl std::fmt::Display for CountingSerializerError {
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
unimplemented!()
}
}
impl std::error::Error for CountingSerializerError {
fn description(&self) -> &str {
""
}
fn cause(&self) -> Option<&dyn std::error::Error> {
None
}
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
impl ser::Error for CountingSerializerError {
fn custom<T>(_msg: T) -> Self
where
T: std::fmt::Display,
{
CountingSerializerError
}
}
impl<'a> ser::Serializer for &'a mut CountingSerializer {
type Ok = ();
type Error = CountingSerializerError;
type SerializeSeq = Self;
type SerializeTuple = ser::Impossible<(), Self::Error>;
type SerializeTupleStruct = ser::Impossible<(), Self::Error>;
type SerializeTupleVariant = ser::Impossible<(), Self::Error>;
type SerializeMap = ser::Impossible<(), Self::Error>;
type SerializeStruct = ser::Impossible<(), Self::Error>;
type SerializeStructVariant = ser::Impossible<(), Self::Error>;
fn serialize_bool(self, _v: bool) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_i8(self, _v: i8) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_i16(self, _v: i16) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_i32(self, _v: i32) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_i64(self, _v: i64) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_u8(self, _v: u8) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_u16(self, _v: u16) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_u32(self, _v: u32) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_u64(self, _v: u64) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_f32(self, _v: f32) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_f64(self, _v: f64) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_char(self, _v: char) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_str(self, _v: &str) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_bytes(self, _v: &[u8]) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_none(self) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_some<T>(self, _value: &T) -> Result<(), Self::Error>
where
T: ?Sized + Serialize,
{
unimplemented!()
}
fn serialize_unit(self) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_unit_struct(self, _name: &'static str) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_unit_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
) -> Result<(), Self::Error> {
unimplemented!()
}
fn serialize_newtype_struct<T>(self, _name: &'static str, _value: &T) -> Result<(), Self::Error>
where
T: ?Sized + Serialize,
{
unimplemented!()
}
fn serialize_newtype_variant<T>(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_value: &T,
) -> Result<(), Self::Error>
where
T: ?Sized + Serialize,
{
unimplemented!()
}
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
Ok(self)
}
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
unimplemented!()
}
fn serialize_tuple_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
unimplemented!()
}
fn serialize_tuple_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
unimplemented!()
}
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
unimplemented!()
}
fn serialize_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
unimplemented!()
}
fn serialize_struct_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
unimplemented!()
}
}
impl<'a> ser::SerializeSeq for &'a mut CountingSerializer {
type Ok = ();
type Error = CountingSerializerError;
fn serialize_element<T>(&mut self, _value: &T) -> Result<(), Self::Error>
where
T: ?Sized + Serialize,
{
self.num_elements += 1;
Ok(())
}
fn end(self) -> Result<(), Self::Error> {
Ok(())
}
}