use std::{
any::Any,
marker::PhantomData,
sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
},
};
use bevy::ecs::component::Component;
#[derive(Clone)]
#[doc(hidden)]
pub struct LocalData<T: Send + Sync + 'static> {
changed: Arc<AtomicBool>,
data: Arc<Mutex<dyn Any + Send + Sync + 'static>>,
marker: PhantomData<T>,
}
impl<T: Send + Sync + Clone + PartialEq + 'static> LocalData<T> {
pub fn get(&self) -> T {
let lock = self.data.lock().unwrap();
let r = lock
.downcast_ref::<T>()
.expect("Mismatched type for LocalData");
r.clone()
}
pub fn set(&mut self, value: T) {
let mut lock = self.data.lock().unwrap();
let r = lock
.downcast_mut::<T>()
.expect("Mismatched type for LocalData");
if *r != value {
self.changed.store(true, Ordering::Relaxed);
*r = value.clone();
}
}
pub fn is_changed(&self) -> bool {
self.changed.load(Ordering::Relaxed)
}
}
#[derive(Component, Default)]
pub struct TrackedLocals {
changed: Arc<AtomicBool>,
locals: Vec<Arc<Mutex<dyn Any + Send + Sync>>>,
}
#[doc(hidden)]
impl TrackedLocals {
pub fn get<T: Send + Sync + Clone>(
&mut self,
index: usize,
init: impl FnOnce() -> T,
) -> LocalData<T> {
if index < self.locals.len() {
LocalData::<T> {
data: self.locals[index].clone(),
changed: self.changed.clone(),
marker: PhantomData {},
}
} else {
self.locals.push(Arc::new(Mutex::new(init())));
LocalData::<T> {
data: self.locals.last().unwrap().clone(),
changed: self.changed.clone(),
marker: PhantomData {},
}
}
}
pub(crate) fn cas(&self) -> bool {
self.changed.swap(false, Ordering::Relaxed)
}
pub fn is_changed(&self) -> bool {
self.changed.load(Ordering::Relaxed)
}
pub fn reset_changed(&mut self) {
self.changed.store(false, Ordering::Relaxed);
}
}