serde_diff/
difference.rs

1use crate::{
2    apply::ApplyContext, counting_serializer::CountingSerializer, Config, ElementStackEntry,
3    FieldPathMode, SerdeDiff,
4};
5use serde::{de, ser::SerializeSeq, Deserialize, Serialize, Serializer};
6use std::{borrow::Cow, cell::Cell};
7
8/// Used during a diff operation for transient data used during the diff
9#[doc(hidden)]
10pub struct DiffContext<'a, S: SerializeSeq> {
11    /// As we descend into fields recursively, the field names (or other "placement" indicators like
12    /// array indexes) are pushed and popped to/from this stack
13    element_stack: Option<Vec<ElementStackEntry<'a, S>>>,
14    /// Reference to the serializer used to save the data
15    serializer: &'a mut S,
16    /// some commands are implicit Exit to save space, so we set a flag to avoid writing the next Exit
17    implicit_exit_written: bool,
18    /// When pushing field path elements, sometimes we need to narrow the lifetime.
19    /// parent_element_stack contains a reference to the parent DiffContext's element_stack.
20    parent_element_stack: Option<&'a mut Option<Vec<ElementStackEntry<'a, S>>>>,
21    /// Contains the minimum index in the element stack at which this context has pushed elements.
22    /// When the context is dropped, we have to make sure we have dropped all elements
23    /// >= index before we can pass the element stack back to the parent.
24    /// This is to ensure the safety invariant that a sub-context's (a `reborrow`ed context)
25    /// pushed elements cannot live longer than the sub-context itself.
26    element_stack_start: usize,
27    /// Mode for serializing field paths
28    field_path_mode: FieldPathMode,
29    /// Set to true if any change is detected
30    has_changes: bool,
31}
32
33impl<'a, S: SerializeSeq> Drop for DiffContext<'a, S> {
34    fn drop(&mut self) {
35        if let Some(parent) = self.parent_element_stack.take() {
36            if let Some(mut stack) = self.element_stack.take() {
37                if self.element_stack_start < stack.len() {
38                    stack.drain(self.element_stack_start..);
39                }
40                parent.replace(stack);
41            }
42        }
43    }
44}
45
46#[doc(hidden)]
47impl<'a, S: SerializeSeq> DiffContext<'a, S> {
48    /// Mode for serializing field paths
49    pub fn field_path_mode(&self) -> FieldPathMode {
50        self.field_path_mode
51    }
52
53    /// True if a change operation has been written
54    pub fn has_changes(&self) -> bool {
55        self.has_changes
56    }
57
58    /// Called when we visit a field. If the structure is recursive (i.e. struct within struct,
59    /// elements within an array) this may be called more than once before a corresponding pop_path_element
60    /// is called. See `pop_path_element`
61    pub fn push_field(&mut self, field_name: &'static str) {
62        self.element_stack
63            .as_mut()
64            .unwrap()
65            .push(ElementStackEntry::PathElement(DiffPathElementValue::Field(
66                Cow::Borrowed(field_name),
67            )));
68    }
69
70    pub fn push_variant(&mut self, variant_name: &'static str) {
71        self.element_stack
72            .as_mut()
73            .unwrap()
74            .push(ElementStackEntry::PathElement(
75                DiffPathElementValue::EnumVariant(Cow::Borrowed(variant_name)),
76            ));
77    }
78
79    pub fn push_full_variant(&mut self) {
80        self.element_stack
81            .as_mut()
82            .unwrap()
83            .push(ElementStackEntry::PathElement(
84                DiffPathElementValue::FullEnumVariant,
85            ));
86    }
87
88    /// Called when we visit a field. If the structure is recursive (i.e. struct within struct,
89    /// elements within an array) this may be called more than once before a corresponding pop_path_element
90    /// is called. See `pop_path_element`
91    pub fn push_field_index(&mut self, field_idx: u16) {
92        self.element_stack
93            .as_mut()
94            .unwrap()
95            .push(ElementStackEntry::PathElement(
96                DiffPathElementValue::FieldIndex(field_idx),
97            ));
98    }
99
100    /// Called when we visit an element within an indexed collection
101    pub fn push_collection_index(&mut self, idx: usize) {
102        self.element_stack
103            .as_mut()
104            .unwrap()
105            .push(ElementStackEntry::PathElement(
106                DiffPathElementValue::CollectionIndex(idx),
107            ));
108    }
109    /// Called when we visit an element within a collection that is new
110    pub fn push_collection_add(&mut self) {
111        self.element_stack
112            .as_mut()
113            .unwrap()
114            .push(ElementStackEntry::PathElement(
115                DiffPathElementValue::AddToCollection,
116            ));
117    }
118
119    pub fn push_field_element(&mut self, f: &'a dyn Fn(&mut S) -> Result<(), S::Error>) {
120        self.element_stack
121            .as_mut()
122            .unwrap()
123            .push(ElementStackEntry::Closure(f));
124    }
125
126    /// Called when we finish visiting an element. See `push_field` for details
127    pub fn pop_path_element(&mut self) -> Result<(), S::Error> {
128        let element_stack = self.element_stack.as_mut().unwrap();
129        if element_stack.is_empty() {
130            // if we don't have any buffered elements, we just write Exit command directly to the serializer
131            // if we've just written a field, skip the Exit
132            if !self.implicit_exit_written {
133                let cmd = DiffCommandRef::<()>::Exit;
134                self.serializer.serialize_element(&cmd)
135            } else {
136                self.implicit_exit_written = false;
137                Ok(())
138            }
139        } else {
140            element_stack.pop();
141            self.element_stack_start = std::cmp::min(element_stack.len(), self.element_stack_start);
142            Ok(())
143        }
144    }
145
146    /// Stores a value for an element that has previously been pushed using push_field or similar.
147    pub fn save_value<T: Serialize>(&mut self, value: &T) -> Result<(), S::Error> {
148        self.save_command(&DiffCommandRef::Value(value), true, true)
149    }
150
151    /// Stores an arbitrary DiffCommand to be handled by the type.
152    /// Any custom sequence of DiffCommands must be followed by Exit.
153    pub fn save_command<'b, T: Serialize>(
154        &mut self,
155        value: &DiffCommandRef<'b, T>,
156        implicit_exit: bool,
157        is_change: bool,
158    ) -> Result<(), S::Error> {
159        let element_stack = self.element_stack.as_mut().unwrap();
160        if !element_stack.is_empty() {
161            // flush buffered elements as Enter* commands
162            for element in element_stack.drain(0..element_stack.len()) {
163                match element {
164                    ElementStackEntry::PathElement(element) => self
165                        .serializer
166                        .serialize_element(&DiffCommandRef::<()>::Enter(element))?,
167                    ElementStackEntry::Closure(closure) => (closure)(&mut self.serializer)?,
168                };
169            }
170            self.element_stack_start = 0;
171        }
172        self.has_changes |= is_change;
173        self.implicit_exit_written = implicit_exit;
174        self.serializer.serialize_element(value)
175    }
176
177    pub fn reborrow<'c, 'd: 'c>(&'d mut self) -> DiffContext<'c, S>
178    where
179        'a: 'c,
180        'a: 'd,
181    {
182        let element_stack = self.element_stack.take();
183        // Some background on this then..
184        // HashMaps need to be able to serialize any T as keys for EnterKey(T).
185        // The usual approach to Enter* commands is to push element paths to the element stack,
186        // then flush the stack into the serialized stream when we encounter a value that has changed.
187        // For any T, we need to push a type-erased closure that contains a reference to something that
188        // might life on the stack. This is why reborrow() exists - to create a smaller scoped lifetime
189        // that can be used to push such closures that live on the stack.
190        // The following transmute changes the lifetime constraints on the elements in the Vec to be
191        // limited to the lifetime of the newly created context. The ownership of the Vec is then moved
192        // to the parent context.
193        // Safety invariant:
194        // In Drop, we have to make sure that any elements that could have been created by this sub-context
195        // are removed from the Vec before passing the ownership back to the parent.
196
197        let element_stack_ref = unsafe {
198            std::mem::transmute::<
199                &'d mut Option<Vec<ElementStackEntry<'a, S>>>,
200                &'c mut Option<Vec<ElementStackEntry<'c, S>>>,
201            >(&mut self.element_stack)
202        };
203
204        DiffContext {
205            element_stack_start: element_stack.as_ref().unwrap().len(),
206            element_stack,
207            parent_element_stack: Some(element_stack_ref),
208            serializer: &mut *self.serializer,
209            implicit_exit_written: self.implicit_exit_written,
210            field_path_mode: self.field_path_mode,
211            has_changes: false,
212        }
213    }
214}
215
216/// A serializable structure that will produce a sequence of diff commands when serialized.
217/// You can pass this to a serializer, or use the convenience method `diff`
218/// to pass your serializer along with old/new values to use when serializing the diff.
219///
220/// # Examples
221///
222/// ```rust
223/// use serde_diff::{SerdeDiff, Diff};
224/// use serde::{Serialize, Deserialize};
225/// #[derive(SerdeDiff, Serialize, Deserialize, PartialEq)]
226/// struct Test {
227///     a: i32,
228/// }
229/// let diff = Diff::serializable(&Test { a: 3 }, &Test { a: 5 });
230/// ```
231pub struct Diff<'a, 'b, T> {
232    pub(crate) old: &'a T,
233    pub(crate) new: &'b T,
234    pub(crate) field_path_mode: FieldPathMode,
235
236    // This is a cell to provide interior mutability
237    pub(crate) has_changes: Cell<bool>,
238}
239
240impl<'a, 'b, T: SerdeDiff + 'a + 'b> Diff<'a, 'b, T> {
241    /// Create a serializable Diff, which when serialized will write the differences between the old
242    /// and new value into the serializer in the form of a sequence of diff commands
243    pub fn serializable(old: &'a T, new: &'b T) -> Self {
244        Config::default().serializable_diff(old, new)
245    }
246
247    /// Writes the differences between the old and new value into the given serializer in the form
248    /// of a sequence of diff commands
249    pub fn diff<S: Serializer>(serializer: S, old: &'a T, new: &'b T) -> Result<S::Ok, S::Error> {
250        Config::default().diff(serializer, old, new)
251    }
252
253    /// True if a change was detected during the diff
254    pub fn has_changes(&self) -> bool {
255        self.has_changes.get()
256    }
257}
258
259impl<'a, 'b, T: SerdeDiff> Serialize for Diff<'a, 'b, T> {
260    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
261    where
262        S: Serializer,
263    {
264        self.has_changes.set(false);
265
266        // Count the number of elements
267        // This may only be needed for certain serializers like bincode,
268        // so we assume that it's only required if the serializer format is not human readable.
269        let num_elements = if !serializer.is_human_readable() {
270            let mut serializer = CountingSerializer { num_elements: 0 };
271            let mut seq = serializer.serialize_seq(None).unwrap();
272            {
273                let mut ctx = DiffContext {
274                    element_stack_start: 0,
275                    element_stack: Some(Vec::new()),
276                    serializer: &mut seq,
277                    implicit_exit_written: false,
278                    parent_element_stack: None,
279                    field_path_mode: self.field_path_mode,
280                    has_changes: false,
281                };
282                self.old.diff(&mut ctx, &self.new).unwrap();
283            }
284            seq.end().unwrap();
285            Some(serializer.num_elements)
286        } else {
287            None
288        };
289
290        // Setup the context, starting a sequence on the serializer
291        let mut seq = serializer.serialize_seq(num_elements)?;
292        {
293            let mut ctx = DiffContext {
294                element_stack_start: 0,
295                element_stack: Some(Vec::new()),
296                serializer: &mut seq,
297                implicit_exit_written: false,
298                parent_element_stack: None,
299                field_path_mode: self.field_path_mode,
300                has_changes: false,
301            };
302
303            // Do the actual comparison, writing diff commands (see DiffCommandRef, DiffCommandValue)
304            // into the sequence
305            self.old.diff(&mut ctx, &self.new)?;
306            self.has_changes.set(ctx.has_changes);
307        }
308
309        // End the sequence on the serializer
310        Ok(seq.end()?)
311    }
312}
313
314pub(crate) struct DeserWrapper<'a, T> {
315    pub(crate) val: &'a mut T,
316}
317
318pub(crate) struct DiffCommandDeserWrapper<'a, T> {
319    pub(crate) val_wrapper: DeserWrapper<'a, T>,
320}
321
322// This monstrosity is based off the output of the derive macro for DiffCommand.
323// The justification for this is that we want to use Deserialize::deserialize_in_place
324// for DiffCommand::Value in order to support zero-copy deserialization of T.
325// This is achieved by passing &mut T through the DiffCommandDeserWrapper, which parses the enum
326// to the DeserWrapper which calls Deserialize::deserialize_in_place.
327pub(crate) enum DiffCommandField {
328    Enter,
329    Value,
330    Remove,
331    AddKey,
332    EnterKey,
333    RemoveKey,
334    Exit,
335}
336
337pub(crate) struct DiffCommandFieldVisitor;
338
339const VARIANTS: &'static [&'static str] = &[
340    "Enter",
341    "Value",
342    "Remove",
343    "AddKey",
344    "EnterKey",
345    "RemoveKey",
346    "Exit",
347];
348
349impl<'de> de::Visitor<'de> for DiffCommandFieldVisitor {
350    type Value = DiffCommandField;
351    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
352        std::fmt::Formatter::write_str(formatter, "variant identifier")
353    }
354    fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
355    where
356        E: de::Error,
357    {
358        match value {
359            0u64 => Ok(DiffCommandField::Enter),
360            1u64 => Ok(DiffCommandField::Value),
361            2u64 => Ok(DiffCommandField::Remove),
362            3u64 => Ok(DiffCommandField::AddKey),
363            4u64 => Ok(DiffCommandField::EnterKey),
364            5u64 => Ok(DiffCommandField::RemoveKey),
365            6u64 => Ok(DiffCommandField::Exit),
366            _ => Err(de::Error::invalid_value(
367                de::Unexpected::Unsigned(value),
368                &"variant index 0 <= i < 7",
369            )),
370        }
371    }
372    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
373    where
374        E: de::Error,
375    {
376        match value {
377            "Enter" => Ok(DiffCommandField::Enter),
378            "Value" => Ok(DiffCommandField::Value),
379            "Remove" => Ok(DiffCommandField::Remove),
380            "AddKey" => Ok(DiffCommandField::AddKey),
381            "EnterKey" => Ok(DiffCommandField::EnterKey),
382            "RemoveKey" => Ok(DiffCommandField::RemoveKey),
383            "Exit" => Ok(DiffCommandField::Exit),
384            _ => Err(de::Error::unknown_variant(value, VARIANTS)),
385        }
386    }
387    fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
388    where
389        E: de::Error,
390    {
391        match value {
392            b"Enter" => Ok(DiffCommandField::Enter),
393            b"Value" => Ok(DiffCommandField::Value),
394            b"Remove" => Ok(DiffCommandField::Remove),
395            b"AddKey" => Ok(DiffCommandField::AddKey),
396            b"EnterKey" => Ok(DiffCommandField::EnterKey),
397            b"RemoveKey" => Ok(DiffCommandField::RemoveKey),
398            b"Exit" => Ok(DiffCommandField::Exit),
399            _ => {
400                let value = &String::from_utf8_lossy(value);
401                Err(de::Error::unknown_variant(value, VARIANTS))
402            }
403        }
404    }
405}
406
407impl<'de> Deserialize<'de> for DiffCommandField {
408    #[inline]
409    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
410    where
411        D: de::Deserializer<'de>,
412    {
413        de::Deserializer::deserialize_identifier(deserializer, DiffCommandFieldVisitor)
414    }
415}
416
417impl<'a, 'de, T> de::DeserializeSeed<'de> for DiffCommandDeserWrapper<'a, T>
418where
419    T: de::Deserialize<'de>,
420{
421    type Value = DiffCommandValue<'de, T>;
422    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
423    where
424        D: de::Deserializer<'de>,
425    {
426        struct Visitor<'de, 'a, T>
427        where
428            T: de::Deserialize<'de>,
429        {
430            seed: DeserWrapper<'a, T>,
431            lifetime: std::marker::PhantomData<&'de ()>,
432        }
433        impl<'de, 'a, T> de::Visitor<'de> for Visitor<'de, 'a, T>
434        where
435            T: de::Deserialize<'de>,
436        {
437            type Value = DiffCommandValue<'de, T>;
438            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
439                std::fmt::Formatter::write_str(formatter, "enum DiffCommandValueTest")
440            }
441            fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
442            where
443                A: de::EnumAccess<'de>,
444            {
445                match de::EnumAccess::variant(data)? {
446                    (DiffCommandField::Enter, variant) => {
447                        let enter =
448                            de::VariantAccess::newtype_variant::<DiffPathElementValue>(variant)?;
449                        Ok(DiffCommandValue::Enter(enter))
450                    }
451                    (DiffCommandField::Value, variant)
452                    | (DiffCommandField::AddKey, variant)
453                    | (DiffCommandField::EnterKey, variant)
454                    | (DiffCommandField::RemoveKey, variant) => {
455                        de::VariantAccess::newtype_variant_seed::<DeserWrapper<T>>(
456                            variant, self.seed,
457                        )?;
458                        Ok(DiffCommandValue::DeserializedValue)
459                    }
460                    (DiffCommandField::Remove, variant) => {
461                        let num_elements = de::VariantAccess::newtype_variant::<usize>(variant)?;
462                        Ok(DiffCommandValue::Remove(num_elements))
463                    }
464                    (DiffCommandField::Exit, variant) => {
465                        de::VariantAccess::unit_variant(variant)?;
466                        Ok(DiffCommandValue::Exit)
467                    }
468                }
469            }
470        }
471        de::Deserializer::deserialize_enum(
472            deserializer,
473            "DiffCommandValueTest",
474            VARIANTS,
475            Visitor {
476                seed: self.val_wrapper,
477                lifetime: std::marker::PhantomData,
478            },
479        )
480    }
481}
482
483impl<'a, 'de, T: Deserialize<'de>> de::DeserializeSeed<'de> for DeserWrapper<'a, T> {
484    type Value = Self;
485    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
486    where
487        D: de::Deserializer<'de>,
488    {
489        Deserialize::deserialize_in_place(deserializer, self.val)?;
490        Ok(self)
491    }
492}
493
494// Deserializes a DiffCommand but ignores values
495pub(crate) struct DiffCommandIgnoreValue;
496
497impl<'de> de::DeserializeSeed<'de> for DiffCommandIgnoreValue {
498    type Value = DiffCommandValue<'de, ()>;
499    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
500    where
501        D: de::Deserializer<'de>,
502    {
503        struct Visitor<'de> {
504            lifetime: std::marker::PhantomData<&'de ()>,
505        }
506        impl<'de> de::Visitor<'de> for Visitor<'de> {
507            type Value = DiffCommandValue<'de, ()>;
508            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
509                std::fmt::Formatter::write_str(formatter, "enum DiffCommandValueTest")
510            }
511            fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
512            where
513                A: de::EnumAccess<'de>,
514            {
515                match de::EnumAccess::variant(data)? {
516                    (DiffCommandField::Enter, variant) => {
517                        let enter =
518                            de::VariantAccess::newtype_variant::<DiffPathElementValue>(variant)?;
519                        Ok(DiffCommandValue::Enter(enter))
520                    }
521                    (DiffCommandField::Value, variant)
522                    | (DiffCommandField::AddKey, variant)
523                    | (DiffCommandField::EnterKey, variant)
524                    | (DiffCommandField::RemoveKey, variant) => {
525                        de::VariantAccess::newtype_variant::<de::IgnoredAny>(variant)?;
526                        Ok(DiffCommandValue::Value(()))
527                    }
528                    (DiffCommandField::Remove, variant) => {
529                        let num_elements = de::VariantAccess::newtype_variant::<usize>(variant)?;
530                        Ok(DiffCommandValue::Remove(num_elements))
531                    }
532                    (DiffCommandField::Exit, variant) => {
533                        de::VariantAccess::unit_variant(variant)?;
534                        Ok(DiffCommandValue::Exit)
535                    }
536                }
537            }
538        }
539        de::Deserializer::deserialize_enum(
540            deserializer,
541            "DiffCommandValueTest",
542            VARIANTS,
543            Visitor {
544                lifetime: std::marker::PhantomData,
545            },
546        )
547    }
548}
549
550#[doc(hidden)]
551#[derive(Serialize, Debug)]
552pub enum DiffCommandRef<'a, T: Serialize> {
553    /// Enter a path element
554    Enter(DiffPathElementValue<'a>),
555    /// A value to be deserialized.
556    /// For collections, this implies "add to end" if not preceded by UpdateIndex.
557    Value(&'a T),
558    /// Remove N items from end of collection
559    Remove(usize),
560    /// Add a key to a map
561    AddKey(&'a T),
562    /// Enter a key in a map.
563    /// This isn't part of Enter because then DiffPathElementValue would have to be generic over T
564    // Fortunately, keys on HashMaps are terminal as far as we're concerned.
565    EnterKey(&'a T),
566    /// Remove a key from a map
567    RemoveKey(&'a T),
568    /// Exit a path element
569    Exit,
570}
571
572#[doc(hidden)]
573#[derive(Deserialize, Debug)]
574pub enum DiffCommandValue<'a, T> {
575    // Enter a path element
576    #[serde(borrow)]
577    Enter(DiffPathElementValue<'a>),
578    /// A value to be deserialized.
579    Value(T),
580    /// Remove N items from end of collection
581    Remove(usize),
582    /// Add a key to a map
583    AddKey(T),
584    // Enter a key in a map
585    EnterKey(T),
586    /// Remove a key from a map
587    RemoveKey(T),
588    // Exit a path element
589    Exit,
590    // Never serialized
591    Nothing,
592    // Never serialized, used to indicate that deserializer wrote a value into supplied reference
593    DeserializedValue,
594}
595
596#[doc(hidden)]
597#[derive(Serialize, Deserialize, Debug)]
598pub enum DiffPathElementValue<'a> {
599    /// A struct field
600    #[serde(borrow)]
601    Field(Cow<'a, str>),
602    FieldIndex(u16),
603    EnumVariant(Cow<'a, str>),
604    FullEnumVariant,
605    CollectionIndex(usize),
606    AddToCollection,
607}
608
609impl<T: SerdeDiff + Serialize + for<'a> Deserialize<'a>> SerdeDiff for Vec<T> {
610    fn diff<'a, S: SerializeSeq>(
611        &self,
612        ctx: &mut DiffContext<'a, S>,
613        other: &Self,
614    ) -> Result<bool, S::Error> {
615        let mut self_iter = self.iter();
616        let mut other_iter = other.iter();
617        let mut idx = 0;
618        let mut need_exit = false;
619        let mut changed = false;
620        loop {
621            let self_item = self_iter.next();
622            let other_item = other_iter.next();
623            match (self_item, other_item) {
624                (None, None) => break,
625                (Some(_), None) => {
626                    let mut num_to_remove = 1;
627                    while self_iter.next().is_some() {
628                        num_to_remove += 1;
629                    }
630                    ctx.save_command::<()>(&DiffCommandRef::Remove(num_to_remove), true, true)?;
631                    changed = true;
632                    need_exit = false;
633                }
634                (None, Some(other_item)) => {
635                    ctx.save_command::<()>(
636                        &DiffCommandRef::Enter(DiffPathElementValue::AddToCollection),
637                        false,
638                        true,
639                    )?;
640                    ctx.save_command(&DiffCommandRef::Value(other_item), true, true)?;
641                    need_exit = true;
642                    changed = true;
643                }
644                (Some(self_item), Some(other_item)) => {
645                    ctx.push_collection_index(idx);
646                    if <T as SerdeDiff>::diff(self_item, ctx, other_item)? {
647                        need_exit = true;
648                        changed = true;
649                    }
650                    ctx.pop_path_element()?;
651                }
652            }
653            idx += 1;
654        }
655        if need_exit {
656            ctx.save_command::<()>(&DiffCommandRef::Exit, true, false)?;
657        }
658        Ok(changed)
659    }
660
661    fn apply<'de, A>(
662        &mut self,
663        seq: &mut A,
664        ctx: &mut ApplyContext,
665    ) -> Result<bool, <A as de::SeqAccess<'de>>::Error>
666    where
667        A: de::SeqAccess<'de>,
668    {
669        let mut changed = false;
670        while let Some(cmd) = ctx.read_next_command::<A, T>(seq)? {
671            use DiffCommandValue::*;
672            use DiffPathElementValue::*;
673            match cmd {
674                // we should not be getting fields when reading collection commands
675                Enter(Field(_)) => {
676                    ctx.skip_value(seq)?;
677                    break;
678                }
679                Enter(CollectionIndex(idx)) => {
680                    if let Some(value_ref) = self.get_mut(idx) {
681                        changed |= <T as SerdeDiff>::apply(value_ref, seq, ctx)?;
682                    } else {
683                        ctx.skip_value(seq)?;
684                    }
685                }
686                Enter(AddToCollection) => {
687                    if let Value(v) = ctx
688                        .read_next_command(seq)?
689                        .expect("Expected value after AddToCollection")
690                    {
691                        changed = true;
692                        self.push(v);
693                    } else {
694                        panic!("Expected value after AddToCollection");
695                    }
696                }
697                Remove(num_elements) => {
698                    let new_length = self.len().saturating_sub(num_elements);
699                    self.truncate(new_length);
700                    changed = true;
701                    break;
702                }
703                _ => break,
704            }
705        }
706        Ok(changed)
707    }
708}