firewheel_core/diff/
notify.rs

1use crate::{
2    diff::{Diff, Patch, RealtimeClone},
3    event::ParamData,
4};
5use bevy_platform::sync::atomic::{AtomicU64, Ordering};
6
7// Increment an atomic counter.
8//
9// This is guaranteed to never return zero.
10#[inline(always)]
11fn increment_counter() -> u64 {
12    static NOTIFY_COUNTER: AtomicU64 = AtomicU64::new(1);
13
14    NOTIFY_COUNTER.fetch_add(1, Ordering::Relaxed)
15}
16
17/// A lightweight wrapper that guarantees an event
18/// will be generated every time the inner value is accessed mutably,
19/// even if the value doesn't change.
20///
21/// This is useful for types like a play head
22/// where periodically writing the same value
23/// carries useful information.
24///
25/// [`Notify`] implements [`core::ops::Deref`] and [`core::ops::DerefMut`]
26/// for the inner `T`.
27#[derive(Debug, Clone)]
28pub struct Notify<T> {
29    value: T,
30    counter: u64,
31}
32
33impl<T> Notify<T> {
34    /// Construct a new [`Notify`].
35    ///
36    /// If two instances of [`Notify`] are constructed separately,
37    /// a call to [`Diff::diff`] will produce an event, even if the
38    /// value is the same.
39    ///
40    /// ```
41    /// # use firewheel_core::diff::Notify;
42    /// // Diffing `a` and `b` will produce an event
43    /// let a = Notify::new(1);
44    /// let b = Notify::new(1);
45    ///
46    /// // whereas `b` and `c` will not.
47    /// let c = b.clone();
48    /// ```
49    pub fn new(value: T) -> Self {
50        Self {
51            value,
52            counter: increment_counter(),
53        }
54    }
55
56    pub(crate) fn from_raw(value: T, counter: u64) -> Self {
57        Self { value, counter }
58    }
59
60    /// Get this instance's unique ID.
61    ///
62    /// After each mutable dereference, this ID will be replaced
63    /// with a new, unique value. For all practical purposes,
64    /// the ID can be considered unique among all [`Notify`] instances.
65    ///
66    /// [`Notify`] IDs are guaranteed to never be 0, so it can be
67    /// used as a sentinel value.
68    #[inline(always)]
69    pub fn id(&self) -> u64 {
70        self.counter
71    }
72
73    /// Get mutable access to the inner value without updating the ID.
74    pub fn as_mut_unsync(&mut self) -> &mut T {
75        &mut self.value
76    }
77
78    /// Manually update the internal ID without modifying the internals.
79    pub fn notify(&mut self) {
80        self.counter = increment_counter();
81    }
82}
83
84impl<T> AsRef<T> for Notify<T> {
85    fn as_ref(&self) -> &T {
86        &self.value
87    }
88}
89
90impl<T> AsMut<T> for Notify<T> {
91    fn as_mut(&mut self) -> &mut T {
92        self.counter = increment_counter();
93
94        &mut self.value
95    }
96}
97
98impl<T: Default> Default for Notify<T> {
99    fn default() -> Self {
100        Self::new(T::default())
101    }
102}
103
104impl<T> core::ops::Deref for Notify<T> {
105    type Target = T;
106
107    fn deref(&self) -> &Self::Target {
108        &self.value
109    }
110}
111
112impl<T> core::ops::DerefMut for Notify<T> {
113    fn deref_mut(&mut self) -> &mut Self::Target {
114        self.counter = increment_counter();
115
116        &mut self.value
117    }
118}
119
120impl<T: Copy> Copy for Notify<T> {}
121
122impl<T: RealtimeClone + Send + Sync + 'static> Diff for Notify<T> {
123    fn diff<E: super::EventQueue>(
124        &self,
125        baseline: &Self,
126        path: super::PathBuilder,
127        event_queue: &mut E,
128    ) {
129        if self.counter != baseline.counter {
130            event_queue.push_param(ParamData::any(self.clone()), path);
131        }
132    }
133}
134
135impl<T: RealtimeClone + Send + Sync + 'static> Patch for Notify<T> {
136    type Patch = Self;
137
138    fn patch(data: &ParamData, _: &[u32]) -> Result<Self::Patch, super::PatchError> {
139        data.downcast_ref()
140            .ok_or(super::PatchError::InvalidData)
141            .cloned()
142    }
143
144    fn apply(&mut self, patch: Self::Patch) {
145        *self = patch;
146    }
147}
148
149impl<T> PartialEq for Notify<T> {
150    fn eq(&self, other: &Self) -> bool {
151        // under normal usage, it is not possible that the inner value
152        // can change without incrementing the counter
153        self.counter == other.counter
154    }
155}
156
157#[cfg(test)]
158mod test {
159    use crate::diff::PathBuilder;
160
161    use super::*;
162
163    #[test]
164    fn test_identical_write() {
165        #[cfg(not(feature = "std"))]
166        use bevy_platform::prelude::Vec;
167
168        let baseline = Notify::new(0.5f32);
169        let mut value = baseline;
170
171        let mut events = Vec::new();
172        value.diff(&baseline, PathBuilder::default(), &mut events);
173        assert_eq!(events.len(), 0);
174
175        *value = 0.5f32;
176
177        value.diff(&baseline, PathBuilder::default(), &mut events);
178        assert_eq!(events.len(), 1);
179    }
180}
181
182#[cfg(feature = "bevy_reflect")]
183mod reflect {
184    use super::Notify;
185
186    #[cfg(not(feature = "std"))]
187    use bevy_platform::prelude::{Box, ToString};
188
189    impl<T> bevy_reflect::GetTypeRegistration for Notify<T>
190    where
191        Notify<T>: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
192        T: Clone
193            + Default
194            + bevy_reflect::FromReflect
195            + bevy_reflect::TypePath
196            + bevy_reflect::MaybeTyped
197            + bevy_reflect::__macro_exports::RegisterForReflection,
198    {
199        fn get_type_registration() -> bevy_reflect::TypeRegistration {
200            let mut registration = bevy_reflect::TypeRegistration::of::<Self>();
201            registration.insert:: <bevy_reflect::ReflectFromPtr>(bevy_reflect::FromType:: <Self> ::from_type());
202            registration.insert::<bevy_reflect::ReflectFromReflect>(
203                bevy_reflect::FromType::<Self>::from_type(),
204            );
205            registration
206                .insert::<bevy_reflect::prelude::ReflectDefault>(
207                    bevy_reflect::FromType::<Self>::from_type(),
208                );
209            registration
210        }
211
212        #[inline(never)]
213        fn register_type_dependencies(registry: &mut bevy_reflect::TypeRegistry) {
214            <T as bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
215            <u64 as bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
216        }
217    }
218
219    impl<T> bevy_reflect::Typed for Notify<T>
220    where
221        Notify<T>: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
222        T: Clone
223            + bevy_reflect::FromReflect
224            + bevy_reflect::TypePath
225            + bevy_reflect::MaybeTyped
226            + bevy_reflect::__macro_exports::RegisterForReflection,
227    {
228        #[inline]
229        fn type_info() -> &'static bevy_reflect::TypeInfo {
230            static CELL: bevy_reflect::utility::GenericTypeInfoCell =
231                bevy_reflect::utility::GenericTypeInfoCell::new();
232            CELL.get_or_insert::<Self, _>(|| {
233                bevy_reflect::TypeInfo::Struct(
234                    bevy_reflect::StructInfo::new::<Self>(&[
235                        bevy_reflect::NamedField::new::<T>("value").with_custom_attributes(
236                            bevy_reflect::attributes::CustomAttributes::default(),
237                        ),
238                    ])
239                    .with_custom_attributes(bevy_reflect::attributes::CustomAttributes::default())
240                    .with_generics(bevy_reflect::Generics::from_iter([
241                        bevy_reflect::GenericInfo::Type(bevy_reflect::TypeParamInfo::new::<T>(
242                            // TODO: Use nicer path once bevy_reflect exposes it.
243                            bevy_reflect::__macro_exports::alloc_utils::Cow::Borrowed("T"),
244                        )),
245                    ])),
246                )
247            })
248        }
249    }
250
251    extern crate alloc;
252    impl<T> bevy_reflect::TypePath for Notify<T>
253    where
254        Notify<T>: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
255        T: bevy_reflect::TypePath,
256    {
257        fn type_path() -> &'static str {
258            static CELL: bevy_reflect::utility::GenericTypePathCell =
259                bevy_reflect::utility::GenericTypePathCell::new();
260            CELL.get_or_insert::<Self, _>(|| {
261                ::core::ops::Add::<&str>::add(
262                    ::core::ops::Add::<&str>::add(
263                        ToString::to_string(::core::concat!(
264                            ::core::concat!(
265                                ::core::concat!(::core::module_path!(), "::"),
266                                "Notify"
267                            ),
268                            "<"
269                        )),
270                        <T as bevy_reflect::TypePath>::type_path(),
271                    ),
272                    ">",
273                )
274            })
275        }
276        fn short_type_path() -> &'static str {
277            static CELL: bevy_reflect::utility::GenericTypePathCell =
278                bevy_reflect::utility::GenericTypePathCell::new();
279            CELL.get_or_insert::<Self, _>(|| {
280                ::core::ops::Add::<&str>::add(
281                    ::core::ops::Add::<&str>::add(
282                        ToString::to_string(::core::concat!("Notify", "<")),
283                        <T as bevy_reflect::TypePath>::short_type_path(),
284                    ),
285                    ">",
286                )
287            })
288        }
289        fn type_ident() -> Option<&'static str> {
290            Some("Notify")
291        }
292        fn crate_name() -> Option<&'static str> {
293            Some(::core::module_path!().split(':').next().unwrap())
294        }
295        fn module_path() -> Option<&'static str> {
296            Some(::core::module_path!())
297        }
298    }
299
300    impl<T> bevy_reflect::Reflect for Notify<T>
301    where
302        Notify<T>: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
303        T: Clone
304            + bevy_reflect::FromReflect
305            + bevy_reflect::TypePath
306            + bevy_reflect::MaybeTyped
307            + bevy_reflect::__macro_exports::RegisterForReflection,
308    {
309        #[inline]
310        fn into_any(self: Box<Self>) -> Box<dyn ::core::any::Any> {
311            self
312        }
313        #[inline]
314        fn as_any(&self) -> &dyn ::core::any::Any {
315            self
316        }
317        #[inline]
318        fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any {
319            self
320        }
321        #[inline]
322        fn into_reflect(self: Box<Self>) -> Box<dyn bevy_reflect::Reflect> {
323            self
324        }
325        #[inline]
326        fn as_reflect(&self) -> &dyn bevy_reflect::Reflect {
327            self
328        }
329        #[inline]
330        fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
331            self
332        }
333        #[inline]
334        fn set(
335            &mut self,
336            value: Box<dyn bevy_reflect::Reflect>,
337        ) -> Result<(), Box<dyn bevy_reflect::Reflect>> {
338            *self = <dyn bevy_reflect::Reflect>::take(value)?;
339            Ok(())
340        }
341    }
342
343    impl<T> bevy_reflect::Struct for Notify<T>
344    where
345        Notify<T>: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
346        T: Clone
347            + bevy_reflect::FromReflect
348            + bevy_reflect::TypePath
349            + bevy_reflect::MaybeTyped
350            + bevy_reflect::__macro_exports::RegisterForReflection,
351    {
352        fn field(&self, name: &str) -> Option<&dyn bevy_reflect::PartialReflect> {
353            match name {
354                "value" => Some(&self.value),
355                _ => None,
356            }
357        }
358
359        fn field_mut(&mut self, name: &str) -> Option<&mut dyn bevy_reflect::PartialReflect> {
360            match name {
361                "value" => Some(self.as_mut()),
362                _ => None,
363            }
364        }
365
366        fn field_at(&self, index: usize) -> Option<&dyn bevy_reflect::PartialReflect> {
367            match index {
368                0usize => Some(&self.value),
369                _ => None,
370            }
371        }
372
373        fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn bevy_reflect::PartialReflect> {
374            match index {
375                0usize => Some(self.as_mut()),
376                _ => None,
377            }
378        }
379
380        fn name_at(&self, index: usize) -> Option<&str> {
381            match index {
382                0usize => Some("value"),
383                _ => None,
384            }
385        }
386
387        fn field_len(&self) -> usize {
388            1usize
389        }
390
391        fn iter_fields<'a>(&'a self) -> bevy_reflect::FieldIter<'a> {
392            bevy_reflect::FieldIter::new(self)
393        }
394
395        fn to_dynamic_struct(&self) -> bevy_reflect::DynamicStruct {
396            let mut dynamic: bevy_reflect::DynamicStruct = Default::default();
397            dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(
398                self,
399            ));
400            dynamic.insert_boxed(
401                "value",
402                bevy_reflect::PartialReflect::to_dynamic(&self.value),
403            );
404            dynamic
405        }
406    }
407
408    impl<T> bevy_reflect::PartialReflect for Notify<T>
409    where
410        Notify<T>: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
411        T: Clone
412            + bevy_reflect::FromReflect
413            + bevy_reflect::TypePath
414            + bevy_reflect::MaybeTyped
415            + bevy_reflect::__macro_exports::RegisterForReflection,
416    {
417        #[inline]
418        fn get_represented_type_info(&self) -> Option<&'static bevy_reflect::TypeInfo> {
419            Some(<Self as bevy_reflect::Typed>::type_info())
420        }
421
422        #[inline]
423        fn try_apply(
424            &mut self,
425            value: &dyn bevy_reflect::PartialReflect,
426        ) -> Result<(), bevy_reflect::ApplyError> {
427            if let bevy_reflect::ReflectRef::Struct(struct_value) =
428                bevy_reflect::PartialReflect::reflect_ref(value)
429            {
430                for (i, value) in ::core::iter::Iterator::enumerate(
431                    bevy_reflect::Struct::iter_fields(struct_value),
432                ) {
433                    let name = bevy_reflect::Struct::name_at(struct_value, i).unwrap();
434                    if let Some(v) = bevy_reflect::Struct::field_mut(self, name) {
435                        bevy_reflect::PartialReflect::try_apply(v, value)?;
436                    }
437                }
438            } else {
439                return Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
440                    from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
441                    to_kind: bevy_reflect::ReflectKind::Struct,
442                });
443            }
444            Ok(())
445        }
446
447        #[inline]
448        fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
449            bevy_reflect::ReflectKind::Struct
450        }
451
452        #[inline]
453        fn reflect_ref<'a>(&'a self) -> bevy_reflect::ReflectRef<'a> {
454            bevy_reflect::ReflectRef::Struct(self)
455        }
456
457        #[inline]
458        fn reflect_mut<'a>(&'a mut self) -> bevy_reflect::ReflectMut<'a> {
459            bevy_reflect::ReflectMut::Struct(self)
460        }
461
462        #[inline]
463        fn reflect_owned(self: Box<Self>) -> bevy_reflect::ReflectOwned {
464            bevy_reflect::ReflectOwned::Struct(self)
465        }
466
467        #[inline]
468        fn try_into_reflect(
469            self: Box<Self>,
470        ) -> Result<Box<dyn bevy_reflect::Reflect>, Box<dyn bevy_reflect::PartialReflect>> {
471            Ok(self)
472        }
473
474        #[inline]
475        fn try_as_reflect(&self) -> Option<&dyn bevy_reflect::Reflect> {
476            Some(self)
477        }
478
479        #[inline]
480        fn try_as_reflect_mut(&mut self) -> Option<&mut dyn bevy_reflect::Reflect> {
481            Some(self)
482        }
483
484        #[inline]
485        fn into_partial_reflect(self: Box<Self>) -> Box<dyn bevy_reflect::PartialReflect> {
486            self
487        }
488
489        #[inline]
490        fn as_partial_reflect(&self) -> &dyn bevy_reflect::PartialReflect {
491            self
492        }
493
494        #[inline]
495        fn as_partial_reflect_mut(&mut self) -> &mut dyn bevy_reflect::PartialReflect {
496            self
497        }
498
499        fn reflect_partial_eq(&self, value: &dyn bevy_reflect::PartialReflect) -> Option<bool> {
500            (bevy_reflect::struct_partial_eq)(self, value)
501        }
502
503        #[inline]
504        fn reflect_clone(
505            &self,
506        ) -> Result<Box<dyn bevy_reflect::Reflect>, bevy_reflect::ReflectCloneError> {
507            Ok(Box::new(Clone::clone(self)))
508        }
509    }
510
511    impl<T> bevy_reflect::FromReflect for Notify<T>
512    where
513        Notify<T>: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
514        T: Default
515            + Clone
516            + bevy_reflect::FromReflect
517            + bevy_reflect::TypePath
518            + bevy_reflect::MaybeTyped
519            + bevy_reflect::__macro_exports::RegisterForReflection,
520    {
521        fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect) -> Option<Self> {
522            if let bevy_reflect::ReflectRef::Struct(ref_struct) =
523                bevy_reflect::PartialReflect::reflect_ref(reflect)
524            {
525                let mut this = <Self as ::core::default::Default>::default();
526                if let Some(field) = (|| {
527                    <T as bevy_reflect::FromReflect>::from_reflect(bevy_reflect::Struct::field(
528                        ref_struct, "value",
529                    )?)
530                })() {
531                    this.value = field;
532                }
533                Some(this)
534            } else {
535                None
536            }
537        }
538    }
539}