bevy_cobweb/react/
react_resource.rsuse crate::prelude::*;
use bevy::prelude::*;
use bevy::ecs::component::Tick;
use bevy::ecs::system::SystemParam;
use core::ops::Deref;
fn trigger_resource_mutation<R: ReactResource>(mut c: Commands)
{
c.react().trigger_resource_mutation::<R>();
}
#[derive(Resource)]
struct ReactResInner<R: ReactResource>
{
resource: R,
}
impl<R: ReactResource> ReactResInner<R>
{
fn new(resource: R) -> Self
{
Self{ resource }
}
fn get_mut<'a>(&'a mut self, c: &mut Commands) -> &'a mut R
{
c.react().trigger_resource_mutation::<R>();
&mut self.resource
}
fn get_noreact(&mut self) -> &mut R
{
&mut self.resource
}
fn set_if_neq(&mut self, c: &mut Commands, new: R) -> Option<R>
where
R: PartialEq
{
if new == self.resource { return None; }
c.react().trigger_resource_mutation::<R>();
let old = std::mem::replace(&mut self.resource, new);
Some(old)
}
fn take(self) -> R
{
self.resource
}
}
impl<R: ReactResource> Deref for ReactResInner<R>
{
type Target = R;
fn deref(&self) -> &R
{
&self.resource
}
}
pub trait ReactResource: Send + Sync + 'static {}
#[derive(SystemParam)]
pub struct ReactRes<'w, R: ReactResource>
{
inner: Res<'w, ReactResInner<R>>,
}
impl<'w, R: ReactResource> DetectChanges for ReactRes<'w, R>
{
#[inline] fn is_added(&self) -> bool { self.inner.is_added() }
#[inline] fn is_changed(&self) -> bool { self.inner.is_changed() }
#[inline] fn last_changed(&self) -> Tick { self.inner.last_changed() }
}
impl<'w, R: ReactResource> Deref for ReactRes<'w, R>
{
type Target = R;
fn deref(&self) -> &R
{
&self.inner
}
}
#[derive(SystemParam)]
pub struct ReactResMut<'w, R: ReactResource>
{
inner: ResMut<'w, ReactResInner<R>>,
}
impl<'w, R: ReactResource> ReactResMut<'w, R>
{
pub fn get_mut<'a>(&'a mut self, c: &mut Commands) -> &'a mut R
{
self.inner.get_mut(c)
}
pub fn get_noreact(&mut self) -> &mut R
{
self.inner.get_noreact()
}
pub fn set_if_neq(&mut self, c: &mut Commands, new: R) -> Option<R>
where
R: PartialEq
{
(*self.inner).set_if_neq(c, new)
}
}
impl<'w, R: ReactResource> DetectChanges for ReactResMut<'w, R>
{
#[inline] fn is_added(&self) -> bool { self.inner.is_added() }
#[inline] fn is_changed(&self) -> bool { self.inner.is_changed() }
#[inline] fn last_changed(&self) -> Tick { self.inner.last_changed() }
}
impl<'w, R: ReactResource> Deref for ReactResMut<'w, R>
{
type Target = R;
fn deref(&self) -> &R
{
&self.inner
}
}
pub trait ReactResWorldExt
{
fn init_react_resource<R: ReactResource + FromWorld>(&mut self);
fn insert_react_resource<R: ReactResource>(&mut self, value: R);
fn remove_react_resource<R: ReactResource>(&mut self) -> Option<R>;
fn contains_react_resource<R: ReactResource>(&self) -> bool;
fn is_react_resource_added<R: ReactResource>(&self) -> bool;
fn is_react_resource_changed<R: ReactResource>(&self) -> bool;
fn react_resource<R: ReactResource>(&self) -> &R;
fn react_resource_mut_noreact<R: ReactResource>(&mut self) -> &mut R;
fn get_react_resource<R: ReactResource>(&self) -> Option<&R>;
fn get_react_resource_noreact<R: ReactResource>(&mut self) -> Option<&mut R>;
fn get_react_resource_or_insert_with<R: ReactResource>(
&mut self,
func: impl FnOnce() -> R,
) -> &R;
fn trigger_resource_mutation<R: ReactResource>(&mut self);
}
impl ReactResWorldExt for World
{
fn init_react_resource<R: ReactResource + FromWorld>(&mut self)
{
if self.contains_react_resource::<R>() { return; }
let value = R::from_world(self);
self.insert_react_resource(value);
}
fn insert_react_resource<R: ReactResource>(&mut self, value: R)
{
self.insert_resource(ReactResInner::new(value));
}
fn remove_react_resource<R: ReactResource>(&mut self) -> Option<R>
{
self.remove_resource::<ReactResInner<R>>().map_or(None, |r| Some(r.take()))
}
fn contains_react_resource<R: ReactResource>(&self) -> bool
{
self.contains_resource::<ReactResInner<R>>()
}
fn is_react_resource_added<R: ReactResource>(&self) -> bool
{
self.is_resource_added::<ReactResInner<R>>()
}
fn is_react_resource_changed<R: ReactResource>(&self) -> bool
{
self.is_resource_changed::<ReactResInner<R>>()
}
fn react_resource<R: ReactResource>(&self) -> &R
{
&self.resource::<ReactResInner<R>>()
}
fn react_resource_mut_noreact<R: ReactResource>(&mut self) -> &mut R
{
self.get_react_resource_noreact().expect("react resource missing!")
}
fn get_react_resource<R: ReactResource>(&self) -> Option<&R>
{
self.get_resource::<ReactResInner<R>>().map_or(None, |r| Some(&r))
}
fn get_react_resource_noreact<R: ReactResource>(&mut self) -> Option<&mut R>
{
self.get_resource_mut::<ReactResInner<R>>().map_or(None, |r| Some(r.into_inner().get_noreact()))
}
fn get_react_resource_or_insert_with<R: ReactResource>(
&mut self,
func: impl FnOnce() -> R,
) -> &R
{
self.get_resource_or_insert_with(move || ReactResInner::new((func)())).into_inner()
}
fn trigger_resource_mutation<R: ReactResource>(&mut self)
{
self.syscall((), trigger_resource_mutation::<R>);
}
}
pub trait ReactResAppExt
{
fn init_react_resource<R: ReactResource + FromWorld>(&mut self) -> &mut Self;
fn insert_react_resource<R: ReactResource>(&mut self, value: R) -> &mut Self;
}
impl ReactResAppExt for App
{
fn init_react_resource<R: ReactResource + FromWorld>(&mut self) -> &mut Self
{
self.world_mut().init_react_resource::<R>();
self
}
fn insert_react_resource<R: ReactResource>(&mut self, value: R) -> &mut Self
{
self.world_mut().insert_react_resource(value);
self
}
}
pub trait ReactResCommandsExt
{
fn init_react_resource<R: ReactResource + FromWorld>(&mut self);
fn insert_react_resource<R: ReactResource>(&mut self, value: R);
fn remove_react_resource<R: ReactResource>(&mut self);
}
impl<'w, 's> ReactResCommandsExt for Commands<'w, 's>
{
fn init_react_resource<R: ReactResource + FromWorld>(&mut self)
{
self.queue(|world: &mut World| world.init_react_resource::<R>());
}
fn insert_react_resource<R: ReactResource>(&mut self, value: R)
{
self.insert_resource(ReactResInner::new(value));
}
fn remove_react_resource<R: ReactResource>(&mut self)
{
self.remove_resource::<ReactResInner<R>>();
}
}