Skip to main content

firewheel_core/diff/
leaf.rs

1//! A set of diff and patch implementations for common leaf types.
2
3use super::{Diff, EventQueue, Patch, PatchError, PathBuilder};
4use crate::{
5    clock::{DurationSamples, DurationSeconds, InstantSamples, InstantSeconds},
6    collector::ArcGc,
7    diff::{Notify, RealtimeClone, notify::NotifyID},
8    dsp::volume::Volume,
9    event::{NodeEventType, ParamData},
10    vector::{Vec2, Vec3},
11};
12
13#[cfg(feature = "musical_transport")]
14use crate::clock::{DurationMusical, InstantMusical};
15
16impl Diff for () {
17    fn diff<E: EventQueue>(&self, _baseline: &Self, _path: PathBuilder, _event_queue: &mut E) {}
18}
19
20impl Patch for () {
21    type Patch = ();
22
23    fn patch(data: &ParamData, _path: &[u32]) -> Result<Self::Patch, PatchError> {
24        match data {
25            ParamData::None => Ok(()),
26            _ => Err(PatchError::InvalidData),
27        }
28    }
29
30    fn apply(&mut self, _patch: Self::Patch) {}
31}
32
33macro_rules! primitive_diff {
34    ($ty:ty, $variant:ident) => {
35        impl Diff for $ty {
36            fn diff<E: EventQueue>(&self, baseline: &Self, path: PathBuilder, event_queue: &mut E) {
37                if self != baseline {
38                    event_queue.push_param(*self, path);
39                }
40            }
41        }
42
43        impl Patch for $ty {
44            type Patch = Self;
45
46            fn patch(data: &ParamData, _: &[u32]) -> Result<Self::Patch, PatchError> {
47                match data {
48                    ParamData::$variant(value) => Ok((*value).into()),
49                    _ => Err(PatchError::InvalidData),
50                }
51            }
52
53            fn apply(&mut self, value: Self::Patch) {
54                *self = value;
55            }
56        }
57
58        impl Diff for Option<$ty> {
59            fn diff<E: EventQueue>(&self, baseline: &Self, path: PathBuilder, event_queue: &mut E) {
60                if self != baseline {
61                    event_queue.push_param(*self, path);
62                }
63            }
64        }
65
66        impl Patch for Option<$ty> {
67            type Patch = Self;
68
69            fn patch(data: &ParamData, _: &[u32]) -> Result<Self::Patch, PatchError> {
70                match data {
71                    ParamData::$variant(value) => Ok(Some((*value).into())),
72                    ParamData::None => Ok(None),
73                    _ => Err(PatchError::InvalidData),
74                }
75            }
76
77            fn apply(&mut self, value: Self::Patch) {
78                *self = value;
79            }
80        }
81    };
82
83    ($ty:ty, $cast:ty, $variant:ident) => {
84        impl Diff for $ty {
85            fn diff<E: EventQueue>(&self, baseline: &Self, path: PathBuilder, event_queue: &mut E) {
86                if self != baseline {
87                    event_queue.push_param(*self as $cast, path);
88                }
89            }
90        }
91
92        impl Patch for $ty {
93            type Patch = Self;
94
95            fn patch(data: &ParamData, _: &[u32]) -> Result<Self::Patch, PatchError> {
96                match data {
97                    ParamData::$variant(value) => Ok(value.clone() as $ty),
98                    _ => Err(PatchError::InvalidData),
99                }
100            }
101
102            fn apply(&mut self, value: Self::Patch) {
103                *self = value;
104            }
105        }
106
107        impl Diff for Option<$ty> {
108            fn diff<E: EventQueue>(&self, baseline: &Self, path: PathBuilder, event_queue: &mut E) {
109                if self != baseline {
110                    event_queue.push_param(self.map(|v| v as $cast), path);
111                }
112            }
113        }
114
115        impl Patch for Option<$ty> {
116            type Patch = Self;
117
118            fn patch(data: &ParamData, _: &[u32]) -> Result<Self::Patch, PatchError> {
119                match data {
120                    ParamData::$variant(value) => Ok(Some(value.clone() as $ty)),
121                    ParamData::None => Ok(None),
122                    _ => Err(PatchError::InvalidData),
123                }
124            }
125
126            fn apply(&mut self, value: Self::Patch) {
127                *self = value;
128            }
129        }
130    };
131}
132
133primitive_diff!(bool, Bool);
134primitive_diff!(u8, u32, U32);
135primitive_diff!(u16, u32, U32);
136primitive_diff!(u32, U32);
137primitive_diff!(u64, U64);
138primitive_diff!(i8, i32, I32);
139primitive_diff!(i16, i32, I32);
140primitive_diff!(i32, I32);
141primitive_diff!(i64, I64);
142primitive_diff!(usize, u64, U64);
143primitive_diff!(isize, i64, I64);
144primitive_diff!(f32, F32);
145primitive_diff!(f64, F64);
146primitive_diff!(Volume, Volume);
147primitive_diff!(InstantSamples, InstantSamples);
148primitive_diff!(DurationSamples, DurationSamples);
149primitive_diff!(InstantSeconds, InstantSeconds);
150primitive_diff!(DurationSeconds, DurationSeconds);
151
152#[cfg(feature = "musical_transport")]
153primitive_diff!(InstantMusical, InstantMusical);
154#[cfg(feature = "musical_transport")]
155primitive_diff!(DurationMusical, DurationMusical);
156
157primitive_diff!(Vec2, Vector2D);
158primitive_diff!(Vec3, Vector3D);
159
160#[cfg(feature = "glam-29")]
161primitive_diff!(glam_29::Vec2, Vector2D);
162#[cfg(feature = "glam-29")]
163primitive_diff!(glam_29::Vec3, Vector3D);
164
165#[cfg(feature = "glam-30")]
166primitive_diff!(glam_30::Vec2, Vector2D);
167#[cfg(feature = "glam-30")]
168primitive_diff!(glam_30::Vec3, Vector3D);
169
170#[cfg(feature = "glam-31")]
171primitive_diff!(glam_31::Vec2, Vector2D);
172#[cfg(feature = "glam-31")]
173primitive_diff!(glam_31::Vec3, Vector3D);
174
175#[cfg(feature = "glam-32")]
176primitive_diff!(glam_32::Vec2, Vector2D);
177#[cfg(feature = "glam-32")]
178primitive_diff!(glam_32::Vec3, Vector3D);
179
180impl<A: ?Sized + Send + Sync + 'static> Diff for ArcGc<A> {
181    fn diff<E: EventQueue>(&self, baseline: &Self, path: PathBuilder, event_queue: &mut E) {
182        if !ArcGc::ptr_eq(self, baseline) {
183            event_queue.push(NodeEventType::Param {
184                data: ParamData::any(self.clone()),
185                path: path.build(),
186            });
187        }
188    }
189}
190
191impl<A: ?Sized + Send + Sync + 'static> Patch for ArcGc<A> {
192    type Patch = Self;
193
194    fn patch(data: &ParamData, _: &[u32]) -> Result<Self::Patch, PatchError> {
195        if let ParamData::Any(any) = data
196            && let Some(data) = any.downcast_ref::<Self>()
197        {
198            return Ok(data.clone());
199        }
200
201        Err(PatchError::InvalidData)
202    }
203
204    fn apply(&mut self, patch: Self::Patch) {
205        *self = patch;
206    }
207}
208
209impl<T: Send + Sync + RealtimeClone + PartialEq + 'static> Diff for Option<T> {
210    fn diff<E: EventQueue>(&self, baseline: &Self, path: PathBuilder, event_queue: &mut E) {
211        if self != baseline {
212            event_queue.push_param(ParamData::opt_any(self.clone()), path);
213        }
214    }
215}
216
217impl<T: Send + Sync + RealtimeClone + PartialEq + 'static> Patch for Option<T> {
218    type Patch = Self;
219
220    fn patch(data: &ParamData, _: &[u32]) -> Result<Self::Patch, PatchError> {
221        Ok(data.downcast_ref::<T>().cloned())
222    }
223
224    fn apply(&mut self, patch: Self::Patch) {
225        *self = patch;
226    }
227}
228
229// Here we specialize the `Notify` implementations since most
230// primitives can have some number of optimizations applied.
231impl Diff for Notify<()> {
232    fn diff<E: EventQueue>(&self, baseline: &Self, path: PathBuilder, event_queue: &mut E) {
233        if self != baseline {
234            event_queue.push_param(ParamData::U64(self.id().0), path);
235        }
236    }
237}
238
239impl Patch for Notify<()> {
240    type Patch = Self;
241
242    fn patch(data: &ParamData, _: &[u32]) -> Result<Self::Patch, PatchError> {
243        match data {
244            ParamData::U64(id) => Ok(Notify::from_raw((), NotifyID(*id))),
245            _ => Err(PatchError::InvalidData),
246        }
247    }
248
249    fn apply(&mut self, value: Self::Patch) {
250        *self = value;
251    }
252}
253
254impl Diff for Notify<bool> {
255    fn diff<E: EventQueue>(&self, baseline: &Self, path: PathBuilder, event_queue: &mut E) {
256        if self != baseline {
257            let mut bytes: [u8; 20] = [0; 20];
258            bytes[0..size_of::<u64>()].copy_from_slice(&self.id().0.to_ne_bytes());
259            bytes[size_of::<u64>()] = if **self { 1 } else { 0 };
260
261            event_queue.push_param(ParamData::CustomBytes(bytes), path);
262        }
263    }
264}
265
266impl Patch for Notify<bool> {
267    type Patch = Self;
268
269    fn patch(data: &ParamData, _path: &[u32]) -> Result<Self::Patch, PatchError> {
270        match data {
271            ParamData::CustomBytes(bytes) => {
272                let (id_bytes, rest_bytes) = bytes.split_at(size_of::<u64>());
273                let id = u64::from_ne_bytes(id_bytes.try_into().unwrap());
274
275                let value = rest_bytes[0] != 0;
276
277                Ok(Notify::from_raw(value, NotifyID(id)))
278            }
279            _ => Err(PatchError::InvalidData),
280        }
281    }
282
283    fn apply(&mut self, value: Self::Patch) {
284        *self = value;
285    }
286}
287
288macro_rules! trivial_notify {
289    ($ty:path) => {
290        impl Diff for Notify<$ty> {
291            fn diff<E: EventQueue>(&self, baseline: &Self, path: PathBuilder, event_queue: &mut E) {
292                if self != baseline {
293                    let mut bytes: [u8; 20] = [0; 20];
294                    bytes[0..8].copy_from_slice(&self.id().0.to_ne_bytes());
295                    let value_bytes = self.to_ne_bytes();
296                    bytes[8..8 + value_bytes.len()].copy_from_slice(&value_bytes);
297
298                    event_queue.push_param(ParamData::CustomBytes(bytes), path);
299                }
300            }
301        }
302
303        impl Patch for Notify<$ty> {
304            type Patch = Self;
305
306            fn patch(data: &ParamData, _path: &[u32]) -> Result<Self::Patch, PatchError> {
307                match data {
308                    ParamData::CustomBytes(bytes) => {
309                        let (id_bytes, rest_bytes) = bytes.split_at(size_of::<u64>());
310                        let id = u64::from_ne_bytes(id_bytes.try_into().unwrap());
311
312                        let (value_bytes, _) = rest_bytes.split_at(size_of::<$ty>());
313                        let value = <$ty>::from_ne_bytes(value_bytes.try_into().unwrap());
314
315                        Ok(Notify::from_raw(value, NotifyID(id)))
316                    }
317                    _ => Err(PatchError::InvalidData),
318                }
319            }
320
321            fn apply(&mut self, value: Self::Patch) {
322                *self = value;
323            }
324        }
325    };
326}
327
328macro_rules! non_trivial_notify {
329    ($ty:path) => {
330        impl Diff for Notify<$ty> {
331            fn diff<E: EventQueue>(&self, baseline: &Self, path: PathBuilder, event_queue: &mut E) {
332                if self != baseline {
333                    event_queue.push_param(ParamData::any(self.clone()), path);
334                }
335            }
336        }
337
338        impl Patch for Notify<$ty> {
339            type Patch = Self;
340
341            fn patch(data: &ParamData, _: &[u32]) -> Result<Self::Patch, PatchError> {
342                data.downcast_ref()
343                    .ok_or(super::PatchError::InvalidData)
344                    .cloned()
345            }
346
347            fn apply(&mut self, value: Self::Patch) {
348                *self = value;
349            }
350        }
351    };
352}
353
354trivial_notify!(i8);
355trivial_notify!(u8);
356trivial_notify!(i16);
357trivial_notify!(u16);
358trivial_notify!(i32);
359trivial_notify!(u32);
360trivial_notify!(i64);
361trivial_notify!(u64);
362trivial_notify!(f32);
363trivial_notify!(f64);
364
365// No good optimizations possible for these large values.
366non_trivial_notify!(Volume);
367non_trivial_notify!(InstantSamples);
368non_trivial_notify!(DurationSamples);
369non_trivial_notify!(InstantSeconds);
370non_trivial_notify!(DurationSeconds);
371
372#[cfg(feature = "musical_transport")]
373non_trivial_notify!(InstantMusical);
374#[cfg(feature = "musical_transport")]
375non_trivial_notify!(DurationMusical);
376
377non_trivial_notify!(Vec2);
378non_trivial_notify!(Vec3);
379
380#[cfg(feature = "glam-29")]
381non_trivial_notify!(glam_29::Vec2);
382#[cfg(feature = "glam-29")]
383non_trivial_notify!(glam_29::Vec3);
384
385#[cfg(feature = "glam-30")]
386non_trivial_notify!(glam_30::Vec2);
387#[cfg(feature = "glam-30")]
388non_trivial_notify!(glam_30::Vec3);
389
390#[cfg(feature = "glam-31")]
391non_trivial_notify!(glam_31::Vec2);
392#[cfg(feature = "glam-31")]
393non_trivial_notify!(glam_31::Vec3);
394
395#[cfg(feature = "glam-32")]
396non_trivial_notify!(glam_32::Vec2);
397#[cfg(feature = "glam-32")]
398non_trivial_notify!(glam_32::Vec3);