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;
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>;
}
#[doc(hidden)]
pub struct DiffContext<'a, S: SerializeSeq> {
field_stack: Vec<DiffPathElementValue<'a>>,
serializer: &'a mut S,
implicit_exit_written: bool,
}
impl<'a, S: SerializeSeq> DiffContext<'a, S> {
pub fn push_field(&mut self, field_name: &'static str) {
self.field_stack
.push(DiffPathElementValue::Field(Cow::Borrowed(field_name)));
}
pub fn push_collection_index(&mut self, idx: usize) {
self.field_stack
.push(DiffPathElementValue::CollectionIndex(idx));
}
pub fn push_collection_add(&mut self) {
self.field_stack.push(DiffPathElementValue::AddToCollection);
}
pub fn pop_path_element(&mut self) -> Result<(), S::Error> {
if self.field_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 {
self.field_stack.pop();
Ok(())
}
}
pub fn save_value<T: Serialize>(&mut self, value: &T) -> Result<(), S::Error> {
self.save_command(&DiffCommandRef::Value(value), true)
}
pub fn save_command<'b, T: Serialize>(
&mut self,
value: &DiffCommandRef<'b, T>,
implicit_exit: bool,
) -> Result<(), S::Error> {
if !self.field_stack.is_empty() {
for field in self.field_stack.drain(0..self.field_stack.len()) {
self.serializer
.serialize_element(&DiffCommandRef::<()>::Enter(field))?;
}
}
self.implicit_exit_written = implicit_exit;
self.serializer.serialize_element(value)
}
}
pub struct Diff<'a, 'b, T> {
old: &'a T,
new: &'b T,
}
impl<'a, 'b, T: SerdeDiff + 'a + 'b> Diff<'a, 'b, T> {
pub fn serializable(old: &'a T, new: &'b T) -> Self {
Self { old, new }
}
pub fn diff<S: Serializer>(serializer: S, old: &'a T, new: &'b T) -> Result<S::Ok, S::Error> {
Self::serializable(old, new).serialize(serializer)
}
}
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,
{
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 {
field_stack: Vec::new(),
serializer: &mut seq,
implicit_exit_written: 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 {
field_stack: Vec::new(),
serializer: &mut seq,
implicit_exit_written: false,
};
self.old.diff(&mut ctx, &self.new)?;
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 {
Self { target }
}
pub fn apply<D>(
deserializer: D,
target: &mut T,
) -> Result<(), <D as de::Deserializer<'de>>::Error>
where
D: de::Deserializer<'de>,
{
deserializer.deserialize_seq(Apply { 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(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(_) => depth += 1,
DiffCommandValue::Exit => depth -= 1,
DiffCommandValue::Value(_) | DiffCommandValue::Remove(_) => depth -= 1,
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::Exit) => cmd,
_ => None,
})
}
}
struct DeserWrapper<'a, T> {
val: &'a mut T,
}
struct DiffCommandDeserWrapper<'a, T> {
val_wrapper: DeserWrapper<'a, T>,
}
#[allow(non_camel_case_types)]
enum DiffCommandField {
Enter,
Value,
Remove,
Exit,
}
struct DiffCommandFieldVisitor;
const VARIANTS: &'static [&'static str] = &["Enter", "Value", "Remove", "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::Exit),
_ => Err(de::Error::invalid_value(
de::Unexpected::Unsigned(value),
&"variant index 0 <= i < 4",
)),
}
}
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),
"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"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) => {
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) => {
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),
Exit,
}
#[doc(hidden)]
#[derive(Deserialize, Debug)]
pub enum DiffCommandValue<'a, T> {
#[serde(borrow)]
Enter(DiffPathElementValue<'a>),
Value(T),
Remove(usize),
Exit,
Nothing,
DeserializedValue,
}
#[doc(hidden)]
#[derive(Serialize, Deserialize, Debug)]
pub enum DiffPathElementValue<'a> {
#[serde(borrow)]
Field(Cow<'a, str>),
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)?;
changed = true;
}
(None, Some(other_item)) => {
ctx.save_command::<()>(
&DiffCommandRef::Enter(DiffPathElementValue::AddToCollection),
false,
)?;
ctx.save_command(&DiffCommandRef::Value(other_item), 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)?;
}
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_export]
macro_rules! simple_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)
}
}
};
}
simple_serde_diff!(bool);
simple_serde_diff!(isize);
simple_serde_diff!(i8);
simple_serde_diff!(i16);
simple_serde_diff!(i32);
simple_serde_diff!(i64);
simple_serde_diff!(usize);
simple_serde_diff!(u8);
simple_serde_diff!(u16);
simple_serde_diff!(u32);
simple_serde_diff!(u64);
simple_serde_diff!(i128);
simple_serde_diff!(u128);
simple_serde_diff!(f32);
simple_serde_diff!(f64);
simple_serde_diff!(char);
simple_serde_diff!(String);
simple_serde_diff!(std::ffi::CString);
simple_serde_diff!(std::ffi::OsString);
simple_serde_diff!(std::num::NonZeroU8);
simple_serde_diff!(std::num::NonZeroU16);
simple_serde_diff!(std::num::NonZeroU32);
simple_serde_diff!(std::num::NonZeroU64);
simple_serde_diff!(std::time::Duration);
simple_serde_diff!(std::time::SystemTime);
simple_serde_diff!(std::net::IpAddr);
simple_serde_diff!(std::net::Ipv4Addr);
simple_serde_diff!(std::net::Ipv6Addr);
simple_serde_diff!(std::net::SocketAddr);
simple_serde_diff!(std::net::SocketAddrV4);
simple_serde_diff!(std::net::SocketAddrV6);
simple_serde_diff!(std::path::PathBuf);
#[allow(dead_code)]
type Unit = ();
simple_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(())
}
}