use std::any::TypeId;
use std::mem::{replace, transmute};
use std::ops::{Deref, DerefMut};
use std::sync::atomic::Ordering;
use pi_share::{Share, ShareUsize};
use crate::single_res::{SingleRes, SingleResMut, TickRes};
use crate::system::{Relation, SystemMeta};
use crate::system_params::SystemParam;
use crate::world::*;
#[derive(Debug)]
pub struct ResVec<T: 'static> {
vec: Vec<TickRes<T>>,
}
impl<T: 'static> ResVec<T> {
pub fn new() -> Self {
Self { vec: Vec::new() }
}
pub fn insert(&mut self, value: T) -> usize {
let index = self.vec.len();
self.vec.push(TickRes::new(value));
index
}
pub fn len(&self) -> usize {
self.vec.len()
}
#[inline(always)]
pub fn get(&self, index: usize) -> Option<&TickRes<T>> {
self.vec.get(index)
}
#[inline(always)]
pub unsafe fn get_unchecked(&self, index: usize) -> &TickRes<T> {
self.vec.get_unchecked(index)
}
pub fn iter(&self) -> impl Iterator<Item = &TickRes<T>> {
self.vec.iter()
}
}
unsafe impl<T: 'static> Send for ResVec<T> {}
unsafe impl<T: 'static> Sync for ResVec<T> {}
pub struct MultiRes<'w, T: 'static> {
pub(crate) vec: &'w ResVec<T>,
changed_tick: Tick,
last_run: Tick,
tick: Tick,
}
unsafe impl<T: 'static> Send for MultiRes<'_, T> {}
unsafe impl<T: 'static> Sync for MultiRes<'_, T> {}
impl<'w, T: 'static> MultiRes<'w, T> {
#[inline]
pub(crate) fn new(vec: &'w ResVec<T>, changed_tick: Tick, last_run: Tick, tick: Tick) -> Self {
MultiRes {
vec,
changed_tick,
last_run,
tick,
}
}
pub fn len(&self) -> usize {
self.vec.len()
}
#[inline(always)]
pub fn tick(&self) -> Tick {
self.tick
}
#[inline(always)]
pub fn changed_tick(&self) -> Tick {
self.changed_tick
}
#[inline(always)]
pub fn is_changed(&self) -> bool {
self.changed_tick > self.last_run
}
pub fn get(&self, index: usize) -> Option<SingleRes<T>> {
self.vec
.get(index)
.map(|r| SingleRes::new(r, self.last_run))
}
pub unsafe fn get_unchecked(&self, index: usize) -> SingleRes<T> {
SingleRes::new(unsafe { self.vec.get_unchecked(index) }, self.last_run)
}
pub fn iter(&self) -> impl Iterator<Item = SingleRes<T>> {
self.vec.iter().map(|r| SingleRes::new(r, self.last_run))
}
}
impl<T: 'static> SystemParam for MultiRes<'_, T> {
type State = (Share<ResVec<T>>, Share<ShareUsize>, Tick);
type Item<'w> = MultiRes<'w, T>;
fn init_state(world: &mut World, meta: &mut SystemMeta) -> Self::State {
let id: TypeId = TypeId::of::<T>();
meta.add_res(Relation::Read(id));
let (r, changed_tick) = world.init_multi_res(id, Share::new(ResVec::<T>::new()));
(Share::downcast(r).unwrap(), changed_tick, Tick::default())
}
#[inline]
fn get_param<'world>(
_world: &'world World,
_system_meta: &'world SystemMeta,
state: &'world mut Self::State,
tick: Tick,
) -> Self::Item<'world> {
let last_run = replace(&mut state.2, tick);
MultiRes::new(
&state.0,
state.1.load(Ordering::Relaxed).into(),
last_run,
tick,
)
}
#[inline]
fn get_self<'world>(
world: &'world World,
system_meta: &'world SystemMeta,
state: &'world mut Self::State,
tick: Tick,
) -> Self {
unsafe { transmute(Self::get_param(world, system_meta, state, tick)) }
}
}
pub struct MultiResMut<'w, T: FromWorld + 'static> {
pub(crate) value: SingleResMut<'w, T>,
changed_tick: &'w Share<ShareUsize>,
}
unsafe impl<T: FromWorld> Send for MultiResMut<'_, T> {}
unsafe impl<T: FromWorld> Sync for MultiResMut<'_, T> {}
impl<'w, T: FromWorld + 'static> MultiResMut<'w, T> {
#[inline]
fn new(value: SingleResMut<'w, T>, changed_tick: &'w Share<ShareUsize>) -> Self {
MultiResMut {
value,
changed_tick,
}
}
#[inline(always)]
pub fn changed_tick(&self) -> Tick {
Tick::from(self.changed_tick.load(Ordering::Relaxed))
}
}
impl<T: FromWorld + 'static> SystemParam for MultiResMut<'_, T> {
type State = (Share<ResVec<T>>, Share<ShareUsize>, usize);
type Item<'w> = MultiResMut<'w, T>;
fn init_state(world: &mut World, meta: &mut SystemMeta) -> Self::State {
let id: TypeId = TypeId::of::<T>();
meta.add_res(Relation::ShareWrite(id));
let (r, changed_tick) = world.init_multi_res(id, Share::new(ResVec::<T>::new()));
let mut res_vec: Share<ResVec<T>> = Share::downcast(r).unwrap();
let vec = unsafe { Share::get_mut_unchecked(&mut res_vec) };
let index = vec.insert(T::from_world(world));
(res_vec, changed_tick, index)
}
#[inline]
fn get_param<'world>(
_world: &'world World,
_system_meta: &'world SystemMeta,
state: &'world mut Self::State,
tick: Tick,
) -> Self::Item<'world> {
let vec = unsafe { Share::get_mut_unchecked(&mut state.0) };
let res = unsafe { vec.vec.get_unchecked_mut(state.2) };
let value = SingleResMut::new(res, tick);
MultiResMut::new(value, &state.1)
}
#[inline]
fn get_self<'world>(
world: &'world World,
system_meta: &'world SystemMeta,
state: &'world mut Self::State,
tick: Tick,
) -> Self {
unsafe { transmute(Self::get_param(world, system_meta, state, tick)) }
}
}
impl<'w, T: FromWorld + Sync + Send + 'static> Deref for MultiResMut<'w, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<'w, T: FromWorld + Sync + Send + 'static> DerefMut for MultiResMut<'w, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.changed_tick
.store(self.value.tick().index(), Ordering::Relaxed);
&mut self.value
}
}