1use crate::{
2 difference::{
3 DeserWrapper, DiffCommandDeserWrapper, DiffCommandIgnoreValue, DiffCommandValue,
4 DiffPathElementValue,
5 },
6 Config, SerdeDiff,
7};
8use serde::{de, Deserialize};
9
10pub struct Apply<'a, T: SerdeDiff> {
28 pub(crate) target: &'a mut T,
29}
30
31impl<'a, 'de, T: SerdeDiff> Apply<'a, T> {
32 pub fn deserializable(target: &'a mut T) -> Self {
35 Config::default().deserializable_apply(target)
36 }
37
38 pub fn apply<D>(
40 deserializer: D,
41 target: &mut T,
42 ) -> Result<(), <D as de::Deserializer<'de>>::Error>
43 where
44 D: de::Deserializer<'de>,
45 {
46 Config::default().apply(deserializer, target)
47 }
48}
49
50impl<'a, 'de, T: SerdeDiff> de::DeserializeSeed<'de> for Apply<'a, T> {
51 type Value = ();
52 fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
53 where
54 D: de::Deserializer<'de>,
55 {
56 deserializer.deserialize_seq(self)
57 }
58}
59
60impl<'a, 'de, T: SerdeDiff> de::Visitor<'de> for Apply<'a, T> {
61 type Value = ();
62 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
63 write!(formatter, "a sequence containing DiffCommands")
64 }
65
66 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, <A as de::SeqAccess<'de>>::Error>
67 where
68 A: de::SeqAccess<'de>,
69 {
70 let mut ctx = ApplyContext {};
71 self.target.apply(&mut seq, &mut ctx)?;
72 Ok(())
73 }
74}
75
76#[doc(hidden)]
78pub struct ApplyContext {}
79
80impl ApplyContext {
81 pub fn next_path_element<'de, A>(
83 &mut self,
84 seq: &mut A,
85 ) -> Result<Option<DiffPathElementValue<'de>>, <A as de::SeqAccess<'de>>::Error>
86 where
87 A: de::SeqAccess<'de>,
88 {
89 use DiffCommandValue::*;
90 let element = match seq.next_element_seed(DiffCommandIgnoreValue {})? {
91 Some(Enter(element)) => Ok(Some(element)),
92 Some(AddKey(_)) | Some(EnterKey(_)) | Some(RemoveKey(_)) => {
93 Ok(None)
95 }
96 Some(Value(_)) | Some(Remove(_)) => panic!("unexpected DiffCommand Value or Remove"),
97 Some(Exit) | Some(Nothing) | Some(DeserializedValue) | None => Ok(None),
98 };
99 element
100 }
101 pub fn skip_value<'de, A>(
103 &mut self,
104 seq: &mut A,
105 ) -> Result<(), <A as de::SeqAccess<'de>>::Error>
106 where
107 A: de::SeqAccess<'de>,
108 {
109 self.skip_value_internal(seq, 1)
110 }
111 fn skip_value_internal<'de, A>(
112 &mut self,
113 seq: &mut A,
114 mut depth: i32,
115 ) -> Result<(), <A as de::SeqAccess<'de>>::Error>
116 where
117 A: de::SeqAccess<'de>,
118 {
119 while let Some(cmd) = seq.next_element_seed(DiffCommandIgnoreValue {})? {
121 match cmd {
122 DiffCommandValue::Enter(_)
123 | DiffCommandValue::AddKey(_)
124 | DiffCommandValue::EnterKey(_) => depth += 1,
125 DiffCommandValue::Exit => depth -= 1,
126 DiffCommandValue::Value(_) | DiffCommandValue::Remove(_) => depth -= 1, DiffCommandValue::RemoveKey(_) => {}
128 DiffCommandValue::Nothing | DiffCommandValue::DeserializedValue => {
129 panic!("should never serialize cmd Nothing or DeserializedValue")
130 }
131 }
132 if depth == 0 {
133 break;
134 }
135 }
136 if depth != 0 {
137 panic!("mismatched DiffCommand::Enter/Exit ")
138 }
139 Ok(())
140 }
141 pub fn read_value<'de, A, T: for<'c> Deserialize<'c>>(
143 &mut self,
144 seq: &mut A,
145 val: &mut T,
146 ) -> Result<bool, <A as de::SeqAccess<'de>>::Error>
147 where
148 A: de::SeqAccess<'de>,
149 {
150 let cmd = seq.next_element_seed::<DiffCommandDeserWrapper<T>>(DiffCommandDeserWrapper {
153 val_wrapper: DeserWrapper { val },
154 })?;
155 match cmd {
156 Some(DiffCommandValue::DeserializedValue) => return Ok(true),
157 Some(DiffCommandValue::Enter(_)) => {
158 self.skip_value_internal(seq, 1)?;
159 }
160 Some(DiffCommandValue::Exit) => panic!("unexpected Exit command"),
161 _ => {}
162 }
163
164 Ok(false)
165 }
166 pub fn read_next_command<'de, A, T: for<'c> Deserialize<'c>>(
168 &mut self,
169 seq: &mut A,
170 ) -> Result<Option<DiffCommandValue<'de, T>>, <A as de::SeqAccess<'de>>::Error>
171 where
172 A: de::SeqAccess<'de>,
173 {
174 let cmd = seq.next_element::<DiffCommandValue<'de, T>>()?;
177 Ok(match cmd {
178 cmd @ Some(DiffCommandValue::Remove(_))
179 | cmd @ Some(DiffCommandValue::Value(_))
180 | cmd @ Some(DiffCommandValue::Enter(_))
181 | cmd @ Some(DiffCommandValue::AddKey(_))
182 | cmd @ Some(DiffCommandValue::EnterKey(_))
183 | cmd @ Some(DiffCommandValue::RemoveKey(_))
184 | cmd @ Some(DiffCommandValue::Exit) => cmd,
185 _ => None,
186 })
187 }
188}