1use crate::{
2 diff::{Diff, Patch, RealtimeClone},
3 event::ParamData,
4};
5use bevy_platform::sync::atomic::{AtomicU64, Ordering};
6
7#[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#[derive(Debug, Clone)]
28pub struct Notify<T> {
29 value: T,
30 counter: u64,
31}
32
33impl<T> Notify<T> {
34 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 #[inline(always)]
69 pub fn id(&self) -> u64 {
70 self.counter
71 }
72
73 pub fn as_mut_unsync(&mut self) -> &mut T {
75 &mut self.value
76 }
77
78 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 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 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}