Skip to main content

cumulo_dipa/
sequence.rs

1use crate::sequence::sequence_apply_patch::apply_patch;
2use crate::sequence::sequence_delta_patch_towards::delta_towards;
3use crate::{CreatedDelta, Diffable, Patchable};
4use serde::Serialize;
5
6mod longest_common_subsequence;
7mod sequence_apply_patch;
8mod sequence_delta_patch_towards;
9
10impl<'s, 'e, T: 'e + Diffable<'s, 'e, T>> Diffable<'s, 'e, Vec<T>> for Vec<T>
11where
12    T: PartialEq,
13    &'e T: serde::Serialize,
14{
15    type Delta = Vec<SequenceModificationDelta<'e, T>>;
16
17    type DeltaOwned = Vec<SequenceModificationDeltaOwned<T>>;
18
19    fn create_delta_towards(&self, end_state: &'e Self) -> CreatedDelta<Self::Delta> {
20        delta_towards(self, end_state)
21    }
22}
23
24impl<T> Patchable<Vec<SequenceModificationDeltaOwned<T>>> for Vec<T> {
25    fn apply_patch(&mut self, patch: Vec<SequenceModificationDeltaOwned<T>>) {
26        apply_patch(self, patch)
27    }
28}
29
30impl<'s, 'e, T: 'e + Diffable<'s, 'e, T>> Diffable<'s, 'e, [T]> for &[T]
31where
32    T: PartialEq,
33    &'e T: serde::Serialize,
34{
35    type Delta = Vec<SequenceModificationDelta<'e, T>>;
36
37    type DeltaOwned = Vec<SequenceModificationDeltaOwned<T>>;
38
39    fn create_delta_towards(&self, end_state: &'e [T]) -> CreatedDelta<Self::Delta> {
40        delta_towards(self, end_state)
41    }
42}
43
44/// Used to diff/patch sequences such as vectors and slices.
45#[derive(Debug, Clone, Serialize)]
46#[cfg_attr(test, derive(PartialEq))]
47pub enum SequenceModificationDelta<'a, T>
48where
49    &'a T: serde::Serialize,
50{
51    /// Insert into the Vec<T>, starting at some start index.
52    InsertOne { index: usize, value: &'a T },
53    /// Prepend an item to the beginning of the vector.
54    PrependOne { item: &'a T },
55    /// Append item to the end of the new vector
56    AppendOne { item: &'a T },
57    /// Delete one item from the sequence
58    DeleteOne { index: usize },
59    /// Replace one item from the sequence
60    ReplaceOne { index: usize, new: &'a T },
61
62    // TODO: Heavily optimize small sequences. So we want operations like
63    //  DeleteFirst, DeleteSecond ... DeleteFifth ... ReplaceThird ... etc.
64    /// Delete the first item in the sequence
65    DeleteFirst,
66    /// Delete the last item in the sequence
67    DeleteLast,
68    /// Replace the first item in the sequence
69    ReplaceFirst { item: &'a T },
70    /// Replace the last item in the sequence
71    ReplaceLast { item: &'a T },
72
73    /// Prepend many items to the beginning of the vector.
74    PrependMany { items: &'a [T] },
75    /// Insert multiple items into the Vec<T>, starting at some start index.
76    InsertMany { start_idx: usize, items: &'a [T] },
77    /// Delete from the Vec<T> starting from some start index
78    DeleteMany {
79        start_index: usize,
80        items_to_delete: usize,
81    },
82    /// Append item to the end of the new vector
83    AppendMany { items: &'a [T] },
84    /// Replace many items in the sequence.
85    ReplaceMany {
86        start_idx: usize,
87        items_to_replace: usize,
88        new: &'a [T],
89    },
90    /// Replace many items in the sequence when we are adding and removing the same number of
91    /// values.
92    ReplaceManySameAmountAddedAndRemoved { index: usize, new: &'a [T] },
93
94    /// Replace all of the values in the old sequence with the values in the new sequence.
95    /// Useful when there is no overlap between the start and end sequence.
96    ReplaceAll { new: &'a [T] },
97
98    /// Delete all items
99    DeleteAll,
100    /// Remove all items *at* AND *before* the specified index.
101    DeleteAllBeforeIncluding { end_index: usize },
102    /// Remove all items *at* AND *after* the specified index.
103    DeleteAllAfterIncluding { start_index: usize },
104
105    /// Replace all values before the provided index, inclusive.
106    ReplaceAllBeforeIncluding { before: usize, new: &'a [T] },
107    /// Replace all values after the provided index, inclusive.
108    ReplaceAllAfterIncluding { after: usize, new: &'a [T] },
109}
110
111/// Used to patch sequences such as vectors and slices.
112#[derive(Debug, Clone, Serialize, Deserialize)]
113#[cfg_attr(test, derive(PartialEq))]
114pub enum SequenceModificationDeltaOwned<T> {
115    /// Insert into the Vec<T>, starting at some start index.
116    InsertOne { index: usize, value: T },
117    /// Prepend an item to the beginning of the vector.
118    PrependOne { item: T },
119    /// Append item to the end of the new vector
120    AppendOne { item: T },
121    /// Delete one item from the sequence
122    DeleteOne { index: usize },
123    /// Replace one item from the sequence
124    ReplaceOne { index: usize, new: T },
125
126    /// Delete the first item in the sequence
127    DeleteFirst,
128    /// Delete the last item in the sequence
129    DeleteLast,
130    /// Replace the first item in the sequence
131    ReplaceFirst { item: T },
132    /// Replace the last item in the sequence
133    ReplaceLast { item: T },
134
135    /// Prepend many items to the beginning of the vector.
136    PrependMany { items: Vec<T> },
137    /// Insert multiple items into the Vec<T>, starting at some start index.
138    InsertMany { start_idx: usize, items: Vec<T> },
139    /// Delete from the Vec<T> starting from some start index
140    DeleteMany {
141        start_index: usize,
142        items_to_delete: usize,
143    },
144    /// Append item to the end of the new vector
145    AppendMany { items: Vec<T> },
146    /// Replace many items in the sequence.
147    ReplaceMany {
148        start_idx: usize,
149        items_to_replace: usize,
150        new: Vec<T>,
151    },
152    /// Replace many items in the sequence when we are adding and removing the same number of
153    /// values.
154    ReplaceManySameAmountAddedAndRemoved { index: usize, new: Vec<T> },
155
156    /// Replace all of the values in the old sequence with the values in the new sequence.
157    ReplaceAll { new: Vec<T> },
158
159    /// Delete all items
160    DeleteAll,
161    /// Remove all items *at* AND *before* the specified index.
162    DeleteAllBeforeIncluding { end_index: usize },
163    /// Remove all items *at* AND *after* the specified index.
164    DeleteAllAfterIncluding { start_index: usize },
165    /// Replace all values before the provided index, inclusive.
166    ReplaceAllBeforeIncluding { before: usize, new: Vec<T> },
167    /// Replace all values after the provided index, inclusive.
168    ReplaceAllAfterIncluding { after: usize, new: Vec<T> },
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174    use crate::dipa_impl_tester::DipaImplTester;
175
176    /// 1 byte for the u8 length of the Vec that holds all of the patch operations
177    const BASE_PATCH_BYTES: usize = 1;
178
179    /// Verify that there is no diff if the start and end vector are the same.
180    #[test]
181    fn vec_unchanged() {
182        DipaImplTester {
183            label: None,
184            start: &mut vec![1u8, 2, 3],
185            end: &vec![1u8, 2, 3],
186            expected_delta: vec![],
187            // No change, none variant is one byte
188            expected_serialized_patch_size: 1,
189            expected_did_change: false,
190        }
191        .test();
192    }
193
194    /// Verify that we delete one extra item at the end.
195    #[test]
196    fn deletion_one_at_end() {
197        // 1 for the variant
198        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1;
199
200        DipaImplTester {
201            label: None,
202            start: &mut vec![0u8, 1, 2, 3],
203            end: &vec![0u8, 1, 2],
204            expected_delta: vec![SequenceModificationDelta::DeleteLast],
205            expected_serialized_patch_size,
206            expected_did_change: true,
207        }
208        .test();
209    }
210
211    /// Verify that we delete many extra items at the end.
212    #[test]
213    fn deletion_many_at_end() {
214        // 1 for the variant then
215        // 1 bytes for the start index
216        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1;
217
218        DipaImplTester {
219            label: None,
220            start: &mut vec![0u8, 1, 2, 3, 4],
221            end: &vec![0u8, 1, 2],
222            expected_delta: vec![SequenceModificationDelta::DeleteAllAfterIncluding {
223                start_index: 3,
224            }],
225            expected_serialized_patch_size,
226            expected_did_change: true,
227        }
228        .test();
229    }
230
231    /// Verify that we properly delete the first item.
232    #[test]
233    fn delete_one_at_beginning() {
234        // 1 for the variant then
235        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1;
236
237        DipaImplTester {
238            label: None,
239            start: &mut vec![0u8, 1, 2],
240            end: &vec![1u8, 2],
241            expected_delta: vec![SequenceModificationDelta::DeleteFirst],
242            expected_serialized_patch_size,
243            expected_did_change: true,
244        }
245        .test();
246    }
247
248    /// Verify that we properly delete the first `n` items.
249    #[test]
250    fn delete_many_at_beginning() {
251        // 1 for the variant then
252        // 1 the index
253        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1;
254
255        DipaImplTester {
256            label: None,
257            start: &mut vec![0u8, 1, 2, 3],
258            end: &vec![2u8, 3],
259            expected_delta: vec![SequenceModificationDelta::DeleteAllBeforeIncluding {
260                end_index: 1,
261            }],
262            expected_serialized_patch_size,
263            expected_did_change: true,
264        }
265        .test();
266    }
267
268    /// Verify that we delete many extra items at the end.
269    #[test]
270    fn delete_many_beginning_and_many_end() {
271        // 2 for the two variants then
272        // 1 bytes for the end index
273        // 1 bytes for the start index
274        let expected_serialized_patch_size = BASE_PATCH_BYTES + 2 + 1 + 1;
275
276        DipaImplTester {
277            label: None,
278            start: &mut vec![0u8, 1, 2, 3, 4, 5],
279            end: &vec![2],
280            expected_delta: vec![
281                SequenceModificationDelta::DeleteAllAfterIncluding { start_index: 3 },
282                SequenceModificationDelta::DeleteAllBeforeIncluding { end_index: 1 },
283            ],
284            expected_serialized_patch_size,
285            expected_did_change: true,
286        }
287        .test();
288    }
289
290    /// Verify that we delete one item in the middle.
291    #[test]
292    fn delete_one_in_middle() {
293        let expected_patch = vec![SequenceModificationDelta::DeleteOne { index: 1 }];
294
295        // 1 for the one variant in the vec, 1 index
296        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1;
297
298        DipaImplTester {
299            label: None,
300            start: &mut vec![1u8, 2, 3],
301            end: &vec![1u8, 3],
302            expected_delta: expected_patch,
303            expected_serialized_patch_size,
304            expected_did_change: true,
305        }
306        .test();
307    }
308
309    /// Verify that we delete many items in the middle.
310    #[test]
311    fn delete_many_in_middle() {
312        let expected_patch = vec![SequenceModificationDelta::DeleteMany {
313            start_index: 1,
314            items_to_delete: 2,
315        }];
316
317        // 1 for the one variant in the vec
318        // 1 for start idx
319        // 1 for item to delete count
320        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1 + 1;
321
322        DipaImplTester {
323            label: None,
324            start: &mut vec![1u8, 2, 3, 4],
325            end: &vec![1u8, 4],
326            expected_delta: expected_patch,
327            expected_serialized_patch_size,
328            expected_did_change: true,
329        }
330        .test();
331    }
332
333    /// Verify that we properly go from an empty vec to one item in the vec.
334    #[test]
335    fn insert_one_into_empty_vec() {
336        let expected_patch = vec![SequenceModificationDelta::ReplaceAll { new: &[1] }];
337
338        // 1 for the one variant in the vec
339        // 1 for len of items vector
340        // 1 for the two u8's
341        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1 + 1;
342
343        DipaImplTester {
344            label: None,
345            start: &mut vec![],
346            end: &vec![1u8],
347            expected_delta: expected_patch,
348            expected_serialized_patch_size,
349            expected_did_change: true,
350        }
351        .test();
352    }
353
354    /// Verify that we properly go from an empty vec to 2 items in the vec.
355    #[test]
356    fn insert_many_into_empty_vec() {
357        let expected_patch = vec![SequenceModificationDelta::ReplaceAll { new: &[1, 2] }];
358
359        // 1 for the one variant in the vec
360        // 1 for len of items vector
361        // 2 for the two u8's
362        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1 + 2;
363
364        DipaImplTester {
365            label: None,
366            start: &mut vec![],
367            end: &vec![1u8, 2],
368            expected_delta: expected_patch,
369            expected_serialized_patch_size,
370            expected_did_change: true,
371        }
372        .test();
373    }
374
375    /// Verify that we properly insert one item at the beginning of the start sequence.
376    #[test]
377    fn insert_one_at_beginning() {
378        let expected_patch = vec![SequenceModificationDelta::PrependOne { item: &1 }];
379
380        // 1 for the one variant in the vec, 1 for the appended u8
381        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1;
382
383        DipaImplTester {
384            label: None,
385            start: &mut vec![2u8, 3],
386            end: &vec![1u8, 2, 3],
387            expected_delta: expected_patch,
388            expected_serialized_patch_size,
389            expected_did_change: true,
390        }
391        .test();
392    }
393
394    /// Verify that we properly insert many items at the beginning of the start sequence.
395    #[test]
396    fn insert_many_at_beginning() {
397        let expected_patch = vec![SequenceModificationDelta::PrependMany { items: &[1, 2] }];
398
399        // 1 for the one variant in the vec
400        // 1 for the length of the items vector
401        // 2 for the prepended u8's
402        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1 + 2;
403
404        DipaImplTester {
405            label: None,
406            start: &mut vec![3u8, 4],
407            end: &vec![1u8, 2u8, 3, 4],
408            expected_delta: expected_patch,
409            expected_serialized_patch_size,
410            expected_did_change: true,
411        }
412        .test();
413    }
414
415    /// Verify that we properly diff/patch inserting one item in the middle
416    #[test]
417    fn insert_one_in_middle() {
418        let expected_patch = vec![SequenceModificationDelta::InsertOne {
419            index: 1,
420            value: &2,
421        }];
422
423        // 1 for the one variant in the vec, 1 for the index, 1 for the appended u8
424        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1 + 1;
425
426        // If the start idx has advanced by 1 but the end index has advanced by 2 then
427        //  insert one
428        DipaImplTester {
429            label: None,
430            start: &mut vec![1u8, 3],
431            end: &vec![1u8, 2, 3],
432            expected_delta: expected_patch,
433            expected_serialized_patch_size,
434            expected_did_change: true,
435        }
436        .test();
437    }
438
439    /// Insert multiple items into the middle of the array.
440    #[test]
441    fn insert_many_in_middle() {
442        let expected_patch = vec![SequenceModificationDelta::InsertMany {
443            start_idx: 1,
444            items: &[2, 3],
445        }];
446
447        // 1 for the one variant in the vec
448        // 1 for the index
449        // 1 for length of items slice
450        // 2 for the appended u8's
451        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1 + 1 + 2;
452
453        DipaImplTester {
454            label: None,
455            start: &mut vec![1u8, 4],
456            end: &vec![1u8, 2, 3, 4],
457            expected_delta: expected_patch,
458            expected_serialized_patch_size,
459            expected_did_change: true,
460        }
461        .test();
462    }
463
464    /// Verify that we append one item to the end.
465    #[test]
466    fn append_one_at_end() {
467        let expected_patch = vec![SequenceModificationDelta::AppendOne { item: &3 }];
468
469        // 1 for the one variant in the vec, 1 for the appended u8
470        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1;
471
472        DipaImplTester {
473            label: None,
474            start: &mut vec![1u8, 2],
475            end: &vec![1u8, 2, 3],
476            expected_delta: expected_patch,
477            expected_serialized_patch_size,
478            expected_did_change: true,
479        }
480        .test();
481    }
482
483    /// Verify that we create a patch to append many items to the end.
484    #[test]
485    fn append_many_at_end() {
486        let expected_patch = vec![SequenceModificationDelta::AppendMany { items: &[3, 4] }];
487
488        // 1 for the one variant in the modifications
489        // 1 for the length of the items vec
490        // 2 for the appended u8's
491        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1 + 2;
492
493        DipaImplTester {
494            label: None,
495            start: &mut vec![1u8, 2],
496            end: &vec![1u8, 2, 3, 4],
497            expected_delta: expected_patch,
498            expected_serialized_patch_size,
499            expected_did_change: true,
500        }
501        .test();
502    }
503
504    /// Verify that we can replace one item at the beginning of the array.
505    #[test]
506    fn replace_one_at_beginning() {
507        let expected_patch = vec![SequenceModificationDelta::ReplaceFirst { item: &2 }];
508
509        // 1 for the one variant in the modifications
510        // 1 for the item
511        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1;
512
513        DipaImplTester {
514            label: None,
515            start: &mut vec![1u8, 3],
516            end: &vec![2u8, 3],
517            expected_delta: expected_patch,
518            expected_serialized_patch_size,
519            expected_did_change: true,
520        }
521        .test();
522    }
523
524    /// Verify that we can replace many items in the middle of the array.
525    #[test]
526    fn replace_many_at_beginning() {
527        let expected_patch = vec![SequenceModificationDelta::ReplaceAllBeforeIncluding {
528            before: 1,
529            new: &[5, 6],
530        }];
531
532        // 1 for the one variant in the modifications
533        // 1 for the index
534        // 1 for the items length
535        // 2 for the items
536        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1 + 1 + 2;
537
538        DipaImplTester {
539            label: None,
540            start: &mut vec![1u8, 2, 3, 4],
541            end: &vec![5u8, 6, 3, 4],
542            expected_delta: expected_patch,
543            expected_serialized_patch_size,
544            expected_did_change: true,
545        }
546        .test();
547    }
548
549    /// Verify that we can replace one item at the end of the array.
550    #[test]
551    fn replace_one_at_end() {
552        let expected_patch = vec![SequenceModificationDelta::ReplaceLast { item: &3 }];
553
554        // 1 for the one variant in the modifications
555        // 1 for the item
556        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1;
557
558        DipaImplTester {
559            label: None,
560            start: &mut vec![1u8, 2],
561            end: &vec![1u8, 3],
562            expected_delta: expected_patch,
563            expected_serialized_patch_size,
564            expected_did_change: true,
565        }
566        .test();
567    }
568
569    /// Verify that we can replace many items at the end of the array.
570    #[test]
571    fn replace_many_at_end() {
572        let expected_patch = vec![SequenceModificationDelta::ReplaceAllAfterIncluding {
573            after: 2,
574            new: &[5, 6],
575        }];
576
577        // 1 for the one variant in the modifications
578        // 1 for index
579        // 1 for the items length
580        // 2 for the items
581        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1 + 1 + 2;
582
583        DipaImplTester {
584            label: None,
585            start: &mut vec![1u8, 2, 3, 4],
586            end: &vec![1u8, 2, 5, 6],
587            expected_delta: expected_patch,
588            expected_serialized_patch_size,
589            expected_did_change: true,
590        }
591        .test();
592    }
593
594    /// Verify that we can replace one item in the middle of the array.
595    #[test]
596    fn replace_one_in_middle() {
597        let expected_patch = vec![SequenceModificationDelta::ReplaceOne { index: 1, new: &4 }];
598
599        // 1 for the one variant in the modifications
600        // 1 for index
601        // 1 for the item
602        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1 + 1;
603
604        DipaImplTester {
605            label: None,
606            start: &mut vec![1u8, 2, 3],
607            end: &vec![1u8, 4, 3],
608            expected_delta: expected_patch,
609            expected_serialized_patch_size,
610            expected_did_change: true,
611        }
612        .test();
613    }
614
615    /// Verify that we can rename `n` items with `m` new items.
616    #[test]
617    fn replace_many_in_middle() {
618        let expected_patch = vec![SequenceModificationDelta::ReplaceMany {
619            start_idx: 1,
620            items_to_replace: 3,
621            new: &[6, 7],
622        }];
623
624        // 1 for the one variant in the modifications
625        // 1 for index
626        // 1 for items to replace count
627        // 1 for length of items
628        // 2 for the items
629        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1 + 1 + 1 + 2;
630
631        DipaImplTester {
632            label: None,
633            start: &mut vec![1u8, 2, 3, 4, 5],
634            end: &vec![1u8, 6, 7, 5],
635            expected_delta: expected_patch,
636            expected_serialized_patch_size,
637            expected_did_change: true,
638        }
639        .test();
640    }
641
642    /// Verify that we can replace many items in the middle of the array when we are removing just
643    /// as many items as we are adding.
644    #[test]
645    fn replace_many_in_middle_same_amount_added_and_removed() {
646        let expected_patch = vec![
647            SequenceModificationDelta::ReplaceManySameAmountAddedAndRemoved {
648                index: 1,
649                new: &[5, 6],
650            },
651        ];
652
653        // 1 for the one variant in the modifications
654        // 1 for index
655        // 1 for items length
656        // 2 for the items
657        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1 + 1 + 1 + 2;
658
659        DipaImplTester {
660            label: None,
661            start: &mut vec![1u8, 2, 3, 4],
662            end: &vec![1u8, 5, 6, 4],
663            expected_delta: expected_patch,
664            expected_serialized_patch_size,
665            expected_did_change: true,
666        }
667        .test();
668    }
669
670    /// Verify that we create a patch to remove all items.
671    #[test]
672    fn delete_entire_vector() {
673        let expected_patch = vec![SequenceModificationDelta::DeleteAll];
674
675        // 1 for the one variant in the modifications
676        let expected_serialized_patch_size = BASE_PATCH_BYTES + 1;
677
678        DipaImplTester {
679            label: None,
680            start: &mut vec![1u8, 2, 3, 4],
681            end: &vec![],
682            expected_delta: expected_patch,
683            expected_serialized_patch_size,
684            expected_did_change: true,
685        }
686        .test();
687    }
688
689    /// Verify that only one byte is used to serialize a sequence modification variant.
690    ///
691    /// This test guards against us accidentally adding more than 250 variants, at which point
692    /// bincode would begin to use 2 bytes instead of one.
693    #[test]
694    fn sequence_variant_one_byte() {
695        let diff: SequenceModificationDelta<()> = SequenceModificationDelta::DeleteFirst;
696
697        assert_eq!(postcard::to_allocvec(&diff).unwrap().len(), 1);
698    }
699}