1use bevy_platform::sync::atomic::Ordering;
2
3use crate::{
4 diff::{Diff, Patch, RealtimeClone},
5 event::ParamData,
6};
7
8fn increment_counter() -> NotifyID {
12 portable_atomic::cfg_has_atomic_64! {
13 use portable_atomic::AtomicU64;
14
15 static NOTIFY_COUNTER: AtomicU64 = AtomicU64::new(1);
16
17 portable_atomic::cfg_has_atomic_cas! {
18 NotifyID(NOTIFY_COUNTER.fetch_add(1, Ordering::Relaxed))
19 }
20
21 portable_atomic::cfg_no_atomic_cas! {
22 let val = NOTIFY_COUNTER.load(Ordering::Relaxed) + 1;
23 NOTIFY_COUNTER.store(val, Ordering::Relaxed);
24 NotifyID(val)
25 }
26 }
27
28 portable_atomic::cfg_no_atomic_64! {
29 portable_atomic::cfg_has_atomic_32! {
30 use portable_atomic::AtomicU32;
31
32 static NOTIFY_COUNTER_0: AtomicU32 = AtomicU32::new(1);
37 static NOTIFY_COUNTER_1: AtomicU32 = AtomicU32::new(0);
38
39 let val_0 = NOTIFY_COUNTER_0.load(Ordering::Relaxed);
40 let val_1 = NOTIFY_COUNTER_1.load(Ordering::Relaxed);
41
42 let val = val_0 as u64 + ((val_1 as u64) << 32) + 1u64;
43
44 NOTIFY_COUNTER_0.store((val & (u32::MAX as u64)) as u32, Ordering::Relaxed);
45 NOTIFY_COUNTER_1.store((val >> 32) as u32, Ordering::Relaxed);
46
47 NotifyID(val)
48 }
49
50 portable_atomic::cfg_no_atomic_32! {
51 use portable_atomic::AtomicU64;
52
53 static NOTIFY_COUNTER: AtomicU64 = AtomicU64::new(1);
55 NotifyID(NOTIFY_COUNTER.fetch_add(1, Ordering::Relaxed))
56 }
57 }
58}
59
60#[repr(transparent)]
69#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
70#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
71#[cfg_attr(feature = "bevy_reflect", reflect(opaque))]
72pub struct NotifyID(pub u64);
73
74impl NotifyID {
75 pub const DANGLING: Self = Self(0);
76}
77
78#[derive(Debug, Clone)]
89pub struct Notify<T> {
90 value: T,
91 id: NotifyID,
92}
93
94impl<T> Notify<T> {
95 pub fn new(value: T) -> Self {
111 Self {
112 value,
113 id: increment_counter(),
114 }
115 }
116
117 pub(crate) fn from_raw(value: T, id: NotifyID) -> Self {
118 Self { value, id }
119 }
120
121 #[inline(always)]
130 pub fn id(&self) -> NotifyID {
131 self.id
132 }
133
134 pub fn as_mut_unsync(&mut self) -> &mut T {
136 &mut self.value
137 }
138
139 pub fn notify(&mut self) {
141 self.id = increment_counter();
142 }
143}
144
145impl<T> AsRef<T> for Notify<T> {
146 fn as_ref(&self) -> &T {
147 &self.value
148 }
149}
150
151impl<T> AsMut<T> for Notify<T> {
152 fn as_mut(&mut self) -> &mut T {
153 self.id = increment_counter();
154
155 &mut self.value
156 }
157}
158
159impl<T: Default> Default for Notify<T> {
160 fn default() -> Self {
161 Self::new(T::default())
162 }
163}
164
165impl<T> core::ops::Deref for Notify<T> {
166 type Target = T;
167
168 fn deref(&self) -> &Self::Target {
169 &self.value
170 }
171}
172
173impl<T> core::ops::DerefMut for Notify<T> {
174 fn deref_mut(&mut self) -> &mut Self::Target {
175 self.id = increment_counter();
176
177 &mut self.value
178 }
179}
180
181impl<T: Copy> Copy for Notify<T> {}
182
183impl<T> PartialEq for Notify<T> {
184 fn eq(&self, other: &Self) -> bool {
185 self.id == other.id
188 }
189}
190
191impl<T: RealtimeClone + Send + Sync + 'static> Diff for Notify<T> {
192 fn diff<E: super::EventQueue>(
193 &self,
194 baseline: &Self,
195 path: super::PathBuilder,
196 event_queue: &mut E,
197 ) {
198 if self.id != baseline.id {
199 event_queue.push_param(ParamData::any(self.clone()), path);
200 }
201 }
202}
203
204impl<T: RealtimeClone + Send + Sync + 'static> Patch for Notify<T> {
205 type Patch = Self;
206
207 fn patch(data: &ParamData, _: &[u32]) -> Result<Self::Patch, super::PatchError> {
208 data.downcast_ref()
209 .ok_or(super::PatchError::InvalidData)
210 .cloned()
211 }
212
213 fn apply(&mut self, patch: Self::Patch) {
214 *self = patch;
215 }
216}
217
218#[cfg(test)]
219mod test {
220 use crate::diff::PathBuilder;
221
222 use super::*;
223
224 #[test]
225 fn test_identical_write() {
226 #[cfg(not(feature = "std"))]
227 use bevy_platform::prelude::Vec;
228
229 let baseline = Notify::new(0.5f32);
230 let mut value = baseline;
231
232 let mut events = Vec::new();
233 value.diff(&baseline, PathBuilder::default(), &mut events);
234 assert_eq!(events.len(), 0);
235
236 *value = 0.5f32;
237
238 value.diff(&baseline, PathBuilder::default(), &mut events);
239 assert_eq!(events.len(), 1);
240 }
241}
242
243#[cfg(feature = "bevy_reflect")]
244mod reflect {
245 use super::Notify;
246
247 #[cfg(not(feature = "std"))]
248 use bevy_platform::prelude::{Box, ToString};
249
250 impl<T> bevy_reflect::GetTypeRegistration for Notify<T>
251 where
252 Notify<T>: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
253 T: Clone
254 + Default
255 + bevy_reflect::FromReflect
256 + bevy_reflect::TypePath
257 + bevy_reflect::MaybeTyped
258 + bevy_reflect::__macro_exports::RegisterForReflection,
259 {
260 fn get_type_registration() -> bevy_reflect::TypeRegistration {
261 let mut registration = bevy_reflect::TypeRegistration::of::<Self>();
262 registration.insert:: <bevy_reflect::ReflectFromPtr>(bevy_reflect::FromType:: <Self> ::from_type());
263 registration.insert::<bevy_reflect::ReflectFromReflect>(
264 bevy_reflect::FromType::<Self>::from_type(),
265 );
266 registration
267 .insert::<bevy_reflect::prelude::ReflectDefault>(
268 bevy_reflect::FromType::<Self>::from_type(),
269 );
270 registration
271 }
272
273 #[inline(never)]
274 fn register_type_dependencies(registry: &mut bevy_reflect::TypeRegistry) {
275 <T as bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
276 <u64 as bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
277 }
278 }
279
280 impl<T> bevy_reflect::Typed for Notify<T>
281 where
282 Notify<T>: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
283 T: Clone
284 + bevy_reflect::FromReflect
285 + bevy_reflect::TypePath
286 + bevy_reflect::MaybeTyped
287 + bevy_reflect::__macro_exports::RegisterForReflection,
288 {
289 #[inline]
290 fn type_info() -> &'static bevy_reflect::TypeInfo {
291 static CELL: bevy_reflect::utility::GenericTypeInfoCell =
292 bevy_reflect::utility::GenericTypeInfoCell::new();
293 CELL.get_or_insert::<Self, _>(|| {
294 bevy_reflect::TypeInfo::Struct(
295 bevy_reflect::structs::StructInfo::new::<Self>(&[
296 bevy_reflect::NamedField::new::<T>("value").with_custom_attributes(
297 bevy_reflect::attributes::CustomAttributes::default(),
298 ),
299 ])
300 .with_custom_attributes(bevy_reflect::attributes::CustomAttributes::default())
301 .with_generics(bevy_reflect::Generics::from_iter([
302 bevy_reflect::GenericInfo::Type(bevy_reflect::TypeParamInfo::new::<T>(
303 bevy_reflect::__macro_exports::alloc_utils::Cow::Borrowed("T"),
305 )),
306 ])),
307 )
308 })
309 }
310 }
311
312 extern crate alloc;
313 impl<T> bevy_reflect::TypePath for Notify<T>
314 where
315 Notify<T>: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
316 T: bevy_reflect::TypePath,
317 {
318 fn type_path() -> &'static str {
319 static CELL: bevy_reflect::utility::GenericTypePathCell =
320 bevy_reflect::utility::GenericTypePathCell::new();
321 CELL.get_or_insert::<Self, _>(|| {
322 ::core::ops::Add::<&str>::add(
323 ::core::ops::Add::<&str>::add(
324 ToString::to_string(::core::concat!(
325 ::core::concat!(
326 ::core::concat!(::core::module_path!(), "::"),
327 "Notify"
328 ),
329 "<"
330 )),
331 <T as bevy_reflect::TypePath>::type_path(),
332 ),
333 ">",
334 )
335 })
336 }
337 fn short_type_path() -> &'static str {
338 static CELL: bevy_reflect::utility::GenericTypePathCell =
339 bevy_reflect::utility::GenericTypePathCell::new();
340 CELL.get_or_insert::<Self, _>(|| {
341 ::core::ops::Add::<&str>::add(
342 ::core::ops::Add::<&str>::add(
343 ToString::to_string(::core::concat!("Notify", "<")),
344 <T as bevy_reflect::TypePath>::short_type_path(),
345 ),
346 ">",
347 )
348 })
349 }
350 fn type_ident() -> Option<&'static str> {
351 Some("Notify")
352 }
353 fn crate_name() -> Option<&'static str> {
354 Some(::core::module_path!().split(':').next().unwrap())
355 }
356 fn module_path() -> Option<&'static str> {
357 Some(::core::module_path!())
358 }
359 }
360
361 impl<T> bevy_reflect::Reflect for Notify<T>
362 where
363 Notify<T>: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
364 T: Clone
365 + bevy_reflect::FromReflect
366 + bevy_reflect::TypePath
367 + bevy_reflect::MaybeTyped
368 + bevy_reflect::__macro_exports::RegisterForReflection,
369 {
370 #[inline]
371 fn into_any(self: Box<Self>) -> Box<dyn ::core::any::Any> {
372 self
373 }
374 #[inline]
375 fn as_any(&self) -> &dyn ::core::any::Any {
376 self
377 }
378 #[inline]
379 fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any {
380 self
381 }
382 #[inline]
383 fn into_reflect(self: Box<Self>) -> Box<dyn bevy_reflect::Reflect> {
384 self
385 }
386 #[inline]
387 fn as_reflect(&self) -> &dyn bevy_reflect::Reflect {
388 self
389 }
390 #[inline]
391 fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
392 self
393 }
394 #[inline]
395 fn set(
396 &mut self,
397 value: Box<dyn bevy_reflect::Reflect>,
398 ) -> Result<(), Box<dyn bevy_reflect::Reflect>> {
399 *self = <dyn bevy_reflect::Reflect>::take(value)?;
400 Ok(())
401 }
402 }
403
404 impl<T> bevy_reflect::prelude::Struct for Notify<T>
405 where
406 Notify<T>: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
407 T: Clone
408 + bevy_reflect::FromReflect
409 + bevy_reflect::TypePath
410 + bevy_reflect::MaybeTyped
411 + bevy_reflect::__macro_exports::RegisterForReflection,
412 {
413 fn field(&self, name: &str) -> Option<&dyn bevy_reflect::PartialReflect> {
414 match name {
415 "value" => Some(&self.value),
416 _ => None,
417 }
418 }
419
420 fn field_mut(&mut self, name: &str) -> Option<&mut dyn bevy_reflect::PartialReflect> {
421 match name {
422 "value" => Some(self.as_mut()),
423 _ => None,
424 }
425 }
426
427 fn field_at(&self, index: usize) -> Option<&dyn bevy_reflect::PartialReflect> {
428 match index {
429 0usize => Some(&self.value),
430 _ => None,
431 }
432 }
433
434 fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn bevy_reflect::PartialReflect> {
435 match index {
436 0usize => Some(self.as_mut()),
437 _ => None,
438 }
439 }
440
441 fn name_at(&self, index: usize) -> Option<&str> {
442 match index {
443 0usize => Some("value"),
444 _ => None,
445 }
446 }
447
448 fn field_len(&self) -> usize {
449 1usize
450 }
451
452 fn iter_fields<'a>(&'a self) -> bevy_reflect::structs::FieldIter<'a> {
453 bevy_reflect::structs::FieldIter::new(self)
454 }
455
456 fn to_dynamic_struct(&self) -> bevy_reflect::structs::DynamicStruct {
457 let mut dynamic: bevy_reflect::structs::DynamicStruct = Default::default();
458 dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(
459 self,
460 ));
461 dynamic.insert_boxed(
462 "value",
463 bevy_reflect::PartialReflect::to_dynamic(&self.value),
464 );
465 dynamic
466 }
467
468 fn index_of_name(&self, name: &str) -> Option<usize> {
469 (name == "value").then_some(0)
470 }
471 }
472
473 impl<T> bevy_reflect::PartialReflect for Notify<T>
474 where
475 Notify<T>: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
476 T: Clone
477 + bevy_reflect::FromReflect
478 + bevy_reflect::TypePath
479 + bevy_reflect::MaybeTyped
480 + bevy_reflect::__macro_exports::RegisterForReflection,
481 {
482 #[inline]
483 fn get_represented_type_info(&self) -> Option<&'static bevy_reflect::TypeInfo> {
484 Some(<Self as bevy_reflect::Typed>::type_info())
485 }
486
487 #[inline]
488 fn try_apply(
489 &mut self,
490 value: &dyn bevy_reflect::PartialReflect,
491 ) -> Result<(), bevy_reflect::ApplyError> {
492 if let bevy_reflect::ReflectRef::Struct(struct_value) =
493 bevy_reflect::PartialReflect::reflect_ref(value)
494 {
495 for (name, value) in struct_value {
496 if let Some(v) = bevy_reflect::prelude::Struct::field_mut(self, name) {
497 bevy_reflect::PartialReflect::try_apply(v, value)?;
498 }
499 }
500 } else {
501 return Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
502 from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
503 to_kind: bevy_reflect::ReflectKind::Struct,
504 });
505 }
506 Ok(())
507 }
508
509 #[inline]
510 fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
511 bevy_reflect::ReflectKind::Struct
512 }
513
514 #[inline]
515 fn reflect_ref<'a>(&'a self) -> bevy_reflect::ReflectRef<'a> {
516 bevy_reflect::ReflectRef::Struct(self)
517 }
518
519 #[inline]
520 fn reflect_mut<'a>(&'a mut self) -> bevy_reflect::ReflectMut<'a> {
521 bevy_reflect::ReflectMut::Struct(self)
522 }
523
524 #[inline]
525 fn reflect_owned(self: Box<Self>) -> bevy_reflect::ReflectOwned {
526 bevy_reflect::ReflectOwned::Struct(self)
527 }
528
529 #[inline]
530 fn try_into_reflect(
531 self: Box<Self>,
532 ) -> Result<Box<dyn bevy_reflect::Reflect>, Box<dyn bevy_reflect::PartialReflect>> {
533 Ok(self)
534 }
535
536 #[inline]
537 fn try_as_reflect(&self) -> Option<&dyn bevy_reflect::Reflect> {
538 Some(self)
539 }
540
541 #[inline]
542 fn try_as_reflect_mut(&mut self) -> Option<&mut dyn bevy_reflect::Reflect> {
543 Some(self)
544 }
545
546 #[inline]
547 fn into_partial_reflect(self: Box<Self>) -> Box<dyn bevy_reflect::PartialReflect> {
548 self
549 }
550
551 #[inline]
552 fn as_partial_reflect(&self) -> &dyn bevy_reflect::PartialReflect {
553 self
554 }
555
556 #[inline]
557 fn as_partial_reflect_mut(&mut self) -> &mut dyn bevy_reflect::PartialReflect {
558 self
559 }
560
561 fn reflect_partial_eq(&self, value: &dyn bevy_reflect::PartialReflect) -> Option<bool> {
562 (bevy_reflect::structs::struct_partial_eq)(self, value)
563 }
564
565 #[inline]
566 fn reflect_clone(
567 &self,
568 ) -> Result<Box<dyn bevy_reflect::Reflect>, bevy_reflect::ReflectCloneError> {
569 Ok(Box::new(Clone::clone(self)))
570 }
571 }
572
573 impl<T> bevy_reflect::FromReflect for Notify<T>
574 where
575 Notify<T>: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
576 T: Default
577 + Clone
578 + bevy_reflect::FromReflect
579 + bevy_reflect::TypePath
580 + bevy_reflect::MaybeTyped
581 + bevy_reflect::__macro_exports::RegisterForReflection,
582 {
583 fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect) -> Option<Self> {
584 if let bevy_reflect::ReflectRef::Struct(ref_struct) =
585 bevy_reflect::PartialReflect::reflect_ref(reflect)
586 {
587 let mut this = <Self as ::core::default::Default>::default();
588 if let Some(field) = (|| {
589 <T as bevy_reflect::FromReflect>::from_reflect(
590 bevy_reflect::prelude::Struct::field(ref_struct, "value")?,
591 )
592 })() {
593 this.value = field;
594 }
595 Some(this)
596 } else {
597 None
598 }
599 }
600 }
601}