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