firewheel_core/diff/
collections.rs

1//! A set of diff and patch implementations for common collections.
2
3use super::{Diff, EventQueue, Patch, PatchError, PathBuilder};
4use crate::event::ParamData;
5
6macro_rules! sequence_diff {
7    ($gen:ident, $ty:ty) => {
8        impl<$gen: Diff> Diff for $ty {
9            fn diff<E: EventQueue>(&self, baseline: &Self, path: PathBuilder, event_queue: &mut E) {
10                for (i, item) in self.iter().enumerate() {
11                    item.diff(&baseline[i], path.with(i as u32), event_queue);
12                }
13            }
14        }
15
16        impl<$gen: Patch> Patch for $ty {
17            type Patch = (usize, $gen::Patch);
18
19            fn patch(data: &ParamData, path: &[u32]) -> Result<Self::Patch, PatchError> {
20                let first = *path.first().ok_or(PatchError::InvalidPath)?;
21                let inner = $gen::patch(data, &path[1..])?;
22
23                Ok((first as usize, inner))
24            }
25
26            fn apply(&mut self, patch: Self::Patch) {
27                self[patch.0].apply(patch.1);
28            }
29        }
30    };
31}
32
33sequence_diff!(T, Vec<T>);
34sequence_diff!(T, Box<[T]>);
35sequence_diff!(T, [T]);
36
37impl<T: Diff, const LEN: usize> Diff for [T; LEN] {
38    fn diff<E: EventQueue>(&self, baseline: &Self, path: PathBuilder, event_queue: &mut E) {
39        for (i, item) in self.iter().enumerate() {
40            item.diff(&baseline[i], path.with(i as u32), event_queue);
41        }
42    }
43}
44
45impl<T: Patch, const LEN: usize> Patch for [T; LEN] {
46    type Patch = (usize, T::Patch);
47
48    fn patch(data: &ParamData, path: &[u32]) -> Result<Self::Patch, PatchError> {
49        let first = *path.first().ok_or(PatchError::InvalidPath)? as usize;
50        if first >= LEN {
51            return Err(PatchError::InvalidPath);
52        }
53        let inner = T::patch(data, &path[1..])?;
54
55        Ok((first, inner))
56    }
57
58    fn apply(&mut self, patch: Self::Patch) {
59        self[patch.0].apply(patch.1);
60    }
61}
62
63macro_rules! tuple_diff {
64    ($tup:ident, $($gen:ident, $base:ident, $index:literal),*) => {
65        pub enum $tup<$($gen: Patch),*> {
66            $($gen($gen::Patch)),*
67        }
68
69        #[allow(non_snake_case, unused_variables)]
70        impl<$($gen: Diff),*> Diff for ($($gen,)*) {
71            fn diff<EQ: EventQueue>(&self, baseline: &Self, path: PathBuilder, event_queue: &mut EQ) {
72                let ($($gen,)*) = self;
73                let ($($base,)*) = baseline;
74
75                $(
76                    $gen.diff($base, path.with($index), event_queue);
77                )*
78            }
79        }
80
81        #[allow(non_snake_case, unused_variables)]
82        impl<$($gen: Patch),*> Patch for ($($gen,)*) {
83            type Patch = $tup<$($gen),*>;
84
85            fn patch(data: &ParamData, path: &[u32]) -> Result<Self::Patch, PatchError> {
86                match path {
87                    $(
88                        [$index, tail @ ..] => Ok($tup::$gen($gen::patch(data, tail)?)),
89                    )*
90                    _ => Err(PatchError::InvalidPath),
91                }
92            }
93
94            fn apply(&mut self, patch: Self::Patch) {
95                let ($($gen,)*) = self;
96
97                match patch {
98                    $(
99                        $tup::$gen(p) => $gen.apply(p)
100                    ),*
101                }
102            }
103        }
104    };
105}
106
107tuple_diff!(Tuple1, A, A1, 0);
108tuple_diff!(Tuple2, A, A1, 0, B, B1, 1);
109tuple_diff!(Tuple3, A, A1, 0, B, B1, 1, C, C1, 2);
110tuple_diff!(Tuple4, A, A1, 0, B, B1, 1, C, C1, 2, D, D1, 3);
111tuple_diff!(Tuple5, A, A1, 0, B, B1, 1, C, C1, 2, D, D1, 3, E, E1, 4);
112tuple_diff!(Tuple6, A, A1, 0, B, B1, 1, C, C1, 2, D, D1, 3, E, E1, 4, F, F1, 5);
113tuple_diff!(Tuple7, A, A1, 0, B, B1, 1, C, C1, 2, D, D1, 3, E, E1, 4, F, F1, 5, G, G1, 6);
114tuple_diff!(Tuple8, A, A1, 0, B, B1, 1, C, C1, 2, D, D1, 3, E, E1, 4, F, F1, 5, G, G1, 6, H, H1, 7);