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