use crate::{
difference::{
DeserWrapper, DiffCommandDeserWrapper, DiffCommandIgnoreValue, DiffCommandValue,
DiffPathElementValue,
},
Config, SerdeDiff,
};
use serde::{de, Deserialize};
pub struct Apply<'a, T: SerdeDiff> {
pub(crate) 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,
})
}
}