use super::{
query::{EntQueryMut, Query, QueryMut, ResQuery, ResQueryMut},
request::{
Request, RequestInfo, RequestKey, Response, StoreRequestInfo, SystemBuffer, RINFO_STOR,
},
};
use crate::{ecs::EcsError, FxBuildHasher};
use my_utils::{
debug_format,
ds::{ATypeId, ListPos, ManagedMutPtr, NonNullExt, SetList, SimpleVecPool},
Or,
};
use std::{
any::{self, Any},
borrow,
collections::{HashMap, HashSet},
fmt, hash,
marker::PhantomData,
mem,
ops::{Deref, DerefMut},
ptr::NonNull,
sync::Arc,
};
use SystemState::*;
pub trait System: Send + 'static {
type Request: Request;
fn run(&mut self, resp: Response<'_, Self::Request>);
#[doc(hidden)]
#[allow(unused_variables)]
fn run_private(&mut self, sid: SystemId, buf: ManagedMutPtr<SystemBuffer>) {}
#[allow(unused_variables)]
fn on_transition(&mut self, from: SystemState, to: SystemState) {}
fn name() -> &'static str {
any::type_name::<Self>()
}
#[doc(hidden)]
fn key() -> SystemKey {
SystemKey::of::<Self>()
}
#[doc(hidden)]
fn into_data(self) -> SystemData
where
Self: Sized + 'static,
{
let boxed = Box::new(self);
let ptr = unsafe { NonNull::new_unchecked(Box::into_raw(boxed)) };
Self::_create_data(ptr, SystemFlags::OWNED_SET)
}
#[doc(hidden)]
unsafe fn create_data(ptr: NonNull<dyn Invoke + Send>) -> SystemData
where
Self: Sized + 'static,
{
Self::_create_data(ptr, SystemFlags::OWNED_RESET)
}
#[doc(hidden)]
fn _create_data(invoker: NonNull<dyn Invoke + Send>, flags: SystemFlags) -> SystemData {
let mut stor = RINFO_STOR.lock().unwrap();
let rinfo = Arc::clone(Self::Request::get_info_from(&mut *stor));
drop(stor);
SystemData {
id: SystemId::dummy(),
flags,
invoker,
info: Arc::new(SystemInfo::new(
Self::name(),
Self::key(),
Self::Request::key(),
rinfo,
)),
}
}
}
#[derive(Debug)]
pub(crate) struct SystemGroup {
cur_id: SystemId,
active: SystemCycle,
inactive: HashSet<SystemData, FxBuildHasher>,
dead: Vec<SystemData>,
poisoned: Vec<PoisonedSystem>,
volatile: HashSet<SystemId, FxBuildHasher>,
lifetime: SystemLifetime,
}
impl SystemGroup {
const INIT_SYSTEM_IDX: u16 = 1;
pub(crate) fn new(gi: u16) -> Self {
Self {
cur_id: SystemId::new(gi, Self::INIT_SYSTEM_IDX),
active: SystemCycle::new(),
inactive: HashSet::with_hasher(FxBuildHasher::default()),
dead: Vec::new(),
poisoned: Vec::new(),
volatile: HashSet::with_hasher(FxBuildHasher::default()),
lifetime: SystemLifetime::new(),
}
}
pub(crate) fn clear(&mut self) {
let mut sids = Vec::with_capacity(self.len_active() + self.len_inactive());
for sdata in self.active.values() {
sids.push(sdata.id());
}
while let Some(sid) = sids.pop() {
self.inactivate(&sid).unwrap();
}
for sdata in self.inactive.iter() {
sids.push(sdata.id());
}
while let Some(sid) = sids.pop() {
self.unregister(&sid).unwrap();
}
self.drain_dead();
self.drain_poisoned();
}
pub(crate) fn len_active(&self) -> usize {
self.active.len()
}
pub(crate) fn len_inactive(&self) -> usize {
self.inactive.len()
}
pub(crate) fn get_active_mut(&mut self) -> &mut SystemCycle {
&mut self.active
}
pub(crate) fn is_active(&self, sid: &SystemId) -> bool {
self.active.contains(sid)
}
pub(crate) fn contains(&self, sid: &SystemId) -> bool {
self.contains_active(sid) || self.contains_inactive(sid)
}
pub(crate) fn contains_active(&self, sid: &SystemId) -> bool {
self.active.contains(sid)
}
pub(crate) fn contains_inactive(&self, sid: &SystemId) -> bool {
self.inactive.contains(sid)
}
pub(crate) fn get_active(&self, sid: &SystemId) -> Option<&SystemData> {
self.active.get(sid)
}
pub(crate) fn next_system_id(&self) -> SystemId {
self.cur_id
}
pub(crate) fn register(
&mut self,
sdata: SystemData,
volatile: bool,
) -> Result<(), EcsError<SystemData>> {
if sdata.id() != self.cur_id {
let reason = debug_format!("invalid system id");
return Err(EcsError::Unknown(reason, sdata));
}
if self.contains(&sdata.id()) {
let reason = debug_format!("duplicated system id");
return Err(EcsError::Unknown(reason, sdata));
}
let sid = sdata.id();
self.cur_id.add_system_index(1);
let is_new = self.inactive.insert(sdata);
debug_assert!(is_new);
if volatile {
let is_new = self.volatile.insert(sid);
debug_assert!(is_new);
}
Ok(())
}
pub(crate) fn activate(
&mut self,
target: &SystemId,
at: InsertPos,
live: Tick,
) -> Result<(), EcsError> {
if let InsertPos::After(after) = at {
if !self.is_active(&after) {
let reason =
debug_format!("cannot activate a system due to invalid insert position");
return Err(EcsError::UnknownSystem(reason, ()));
}
}
if let Some(mut sdata) = self.inactive.take(target) {
debug_assert_eq!(sdata.id(), *target);
sdata.as_invoker_mut().on_transition(Inactive, Active);
let must_true = self.active.insert(sdata, at);
debug_assert!(must_true);
self.lifetime.register(*target, live);
Ok(())
} else {
let reason = debug_format!("system activation is allowed for inactive systems only");
Err(EcsError::UnknownSystem(reason, ()))
}
}
pub(crate) fn unregister(&mut self, sid: &SystemId) -> Result<(), EcsError> {
if let Some(mut sdata) = self.inactive.take(sid) {
sdata.as_invoker_mut().on_transition(Inactive, Dead);
self.dead.push(sdata);
Ok(())
} else {
let reason = debug_format!("tried to unregister a not inactive system");
Err(EcsError::UnknownSystem(reason, ()))
}
}
pub(crate) fn poison(
&mut self,
sid: &SystemId,
payload: Box<dyn Any + Send>,
) -> Result<(), EcsError<Box<dyn Any + Send>>> {
let sdata = if let Some(mut sdata) = self.active.remove(sid) {
sdata.as_invoker_mut().on_transition(Active, Poisoned);
sdata
} else if let Some(mut sdata) = self.inactive.take(sid) {
sdata.as_invoker_mut().on_transition(Inactive, Poisoned);
sdata
} else {
let reason = debug_format!("tried to poison a not (in)active system");
return Err(EcsError::UnknownSystem(reason, payload));
};
let poisoned = PoisonedSystem::from_system_data(sdata, payload);
self.poisoned.push(poisoned);
Ok(())
}
pub(crate) fn inactivate(&mut self, sid: &SystemId) -> Result<(), EcsError> {
let Self {
active,
inactive,
dead,
volatile,
..
} = self;
Self::_inactivate(sid, active, inactive, dead, volatile)
}
fn _inactivate(
sid: &SystemId,
active: &mut SystemCycle,
inactive: &mut HashSet<SystemData, FxBuildHasher>,
dead: &mut Vec<SystemData>,
volatile: &mut HashSet<SystemId, FxBuildHasher>,
) -> Result<(), EcsError> {
if inactive.contains(sid) {
Ok(())
} else if let Some(mut sdata) = active.remove(sid) {
if volatile.contains(sid) {
sdata.as_invoker_mut().on_transition(Active, Dead);
dead.push(sdata);
} else {
sdata.as_invoker_mut().on_transition(Active, Inactive);
inactive.insert(sdata);
}
Ok(())
} else {
let reason = debug_format!("tried to inactivate a not (in)active system");
Err(EcsError::UnknownSystem(reason, ()))
}
}
pub(crate) fn drain_dead(&mut self) -> std::vec::Drain<'_, SystemData> {
for sdata in self.dead.iter() {
self.volatile.remove(&sdata.id());
}
self.dead.drain(..)
}
pub(crate) fn drain_poisoned(&mut self) -> std::vec::Drain<'_, PoisonedSystem> {
for poisoned in self.poisoned.iter() {
self.volatile.remove(&poisoned.id());
}
self.poisoned.drain(..)
}
pub(crate) fn tick(&mut self) {
let Self {
active,
inactive,
dead,
volatile,
lifetime,
..
} = self;
if let Some(expired_sids) = lifetime.tick() {
while let Some(sid) = expired_sids.pop() {
let _ = Self::_inactivate(&sid, active, inactive, dead, volatile);
}
}
}
}
#[derive(Debug)]
pub enum SystemState {
Active,
Inactive,
Dead,
Poisoned,
}
#[derive(Debug)]
#[repr(transparent)]
pub(crate) struct SystemCycle(SetList<SystemId, SystemData, FxBuildHasher>);
impl SystemCycle {
pub(crate) fn new() -> Self {
Self(SetList::new())
}
pub(crate) fn len(&self) -> usize {
self.0.len()
}
pub(crate) fn contains(&self, sid: &SystemId) -> bool {
self.0.contains_key(sid)
}
pub(crate) fn insert(&mut self, sdata: SystemData, at: InsertPos) -> bool {
match at {
InsertPos::After(after) => self.0.insert(sdata.id(), sdata, &after),
InsertPos::Back => self.0.push_back(sdata.id(), sdata),
InsertPos::Front => self.0.push_front(sdata.id(), sdata),
}
}
pub(crate) fn remove(&mut self, sid: &SystemId) -> Option<SystemData> {
self.0.remove(sid)
}
pub(crate) fn iter_begin(&mut self) -> SystemCycleIter<'_> {
SystemCycleIter::new(&mut self.0)
}
}
impl Default for SystemCycle {
fn default() -> Self {
Self::new()
}
}
impl Deref for SystemCycle {
type Target = SetList<SystemId, SystemData, FxBuildHasher>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for SystemCycle {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Debug)]
#[repr(transparent)]
pub(crate) struct SystemCycleIter<'a> {
raw: RawSystemCycleIter,
_marker: PhantomData<&'a mut ()>,
}
impl<'a> SystemCycleIter<'a> {
pub(crate) fn new(systems: &'a mut SetList<SystemId, SystemData, FxBuildHasher>) -> Self {
Self {
raw: RawSystemCycleIter::new(systems),
_marker: PhantomData,
}
}
pub(crate) const fn into_raw(self) -> RawSystemCycleIter {
self.raw
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct RawSystemCycleIter {
systems: NonNull<SetList<SystemId, SystemData, FxBuildHasher>>,
cur_pos: ListPos,
}
impl RawSystemCycleIter {
pub(crate) fn position(&self) -> ListPos {
self.cur_pos
}
pub(crate) fn new(systems: &mut SetList<SystemId, SystemData, FxBuildHasher>) -> Self {
let cur_pos = systems.first_position();
let systems = unsafe { NonNull::new_unchecked(systems as *mut _) };
Self { systems, cur_pos }
}
pub(crate) unsafe fn next(&mut self) {
let systems = unsafe { self.systems.as_ref() };
if let Some((next, _sdata)) = systems.iter_next(self.cur_pos) {
self.cur_pos = next;
}
}
pub(crate) unsafe fn get(&mut self) -> Option<&mut SystemData> {
unsafe { self.get_at(self.cur_pos) }
}
pub(crate) unsafe fn get_at(&mut self, pos: ListPos) -> Option<&mut SystemData> {
let systems = unsafe { self.systems.as_mut() };
systems.iter_next_mut(pos).map(|(_, sdata)| sdata)
}
}
#[derive(Debug, Clone, Copy)]
pub enum InsertPos {
Back,
Front,
After(SystemId),
}
#[derive(Debug)]
struct SystemLifetime {
tick: Tick,
lives: HashMap<Tick, usize, FxBuildHasher>,
pool: SimpleVecPool<SystemId>,
}
impl SystemLifetime {
fn new() -> Self {
Self {
tick: 0,
lives: HashMap::with_hasher(FxBuildHasher::default()),
pool: SimpleVecPool::new(),
}
}
fn register(&mut self, sid: SystemId, live: Tick) {
debug_assert!(live > 0);
let end = self.tick.saturating_add(live);
let index = *self.lives.entry(end).or_insert(self.pool.request());
let vec = self.pool.get(index);
vec.push(sid);
}
fn tick(&mut self) -> Option<&mut Vec<SystemId>> {
self.tick += 1;
self.lives.remove(&self.tick).map(|index| {
self.pool.release(index);
self.pool.get(index)
})
}
}
impl Default for SystemLifetime {
fn default() -> Self {
Self::new()
}
}
impl System for () {
type Request = ();
fn run(&mut self, _resp: Response<Self::Request>) {}
}
pub type SystemKey = ATypeId<SystemKey_>;
pub struct SystemKey_;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
pub struct SystemId {
group_index: u16,
system_index: u16,
}
impl SystemId {
const DUMMY: Self = Self {
group_index: u16::MAX,
system_index: u16::MAX,
};
const MAX: u16 = u16::MAX - 1;
pub(crate) const fn dummy() -> Self {
Self::DUMMY
}
pub(crate) fn is_dummy(&self) -> bool {
self == &Self::dummy()
}
pub(crate) const fn new(group_index: u16, system_index: u16) -> Self {
Self {
group_index,
system_index,
}
}
pub(crate) const fn group_index(&self) -> u16 {
self.group_index
}
pub(crate) const fn max_system_index() -> u16 {
Self::MAX
}
pub(crate) fn add_system_index(&mut self, by: u16) {
assert!(
self.system_index < Self::max_system_index(),
"number of systems exceeded its limit {}",
Self::max_system_index() - 1
);
self.system_index += by;
}
}
impl Default for SystemId {
fn default() -> Self {
Self::dummy()
}
}
impl fmt::Display for SystemId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.group_index, self.system_index)
}
}
pub struct SystemData {
id: SystemId,
flags: SystemFlags,
invoker: NonNull<dyn Invoke + Send>,
info: Arc<SystemInfo>,
}
unsafe impl Send for SystemData {}
unsafe impl Sync for SystemData {}
impl SystemData {
pub(crate) fn try_into_any(mut self) -> Result<Box<dyn Any + Send>, Self> {
if self.flags.is_owned() {
debug_assert!(!mem::needs_drop::<SystemId>());
debug_assert!(!mem::needs_drop::<SystemFlags>());
debug_assert!(mem::needs_drop::<Arc<SystemInfo>>());
let info = &mut self.info as *mut _;
unsafe { std::ptr::drop_in_place(info) };
let boxed = unsafe { Box::from_raw(self.invoker.as_ptr()) };
mem::forget(self);
Ok(boxed.into_any())
} else {
Err(self)
}
}
}
impl Default for SystemData {
fn default() -> Self {
().into_data()
}
}
impl Drop for SystemData {
fn drop(&mut self) {
if self.flags.is_owned() {
unsafe { drop(Box::from_raw(self.invoker.as_ptr())) };
}
}
}
impl fmt::Debug for SystemData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SystemData")
.field("id", &self.id)
.field("flags", &self.flags)
.field("info", &self.info)
.finish_non_exhaustive()
}
}
impl hash::Hash for SystemData {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl PartialEq for SystemData {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for SystemData {}
impl borrow::Borrow<SystemId> for SystemData {
fn borrow(&self) -> &SystemId {
&self.id
}
}
impl SystemData {
pub(crate) const fn id(&self) -> SystemId {
self.id
}
pub(crate) const fn flags(&self) -> SystemFlags {
self.flags
}
pub(crate) fn set_id(&mut self, sid: SystemId) {
self.id = sid;
}
pub(crate) fn union_flags(&mut self, sflags: SystemFlags) {
self.flags |= sflags;
}
pub(crate) fn info(&self) -> Arc<SystemInfo> {
Arc::clone(&self.info)
}
pub(crate) fn get_request_info(&self) -> &Arc<RequestInfo> {
unsafe { self.info.rinfo.as_ref().unwrap_unchecked() }
}
pub(crate) fn as_invoker_mut(&mut self) -> &mut (dyn Invoke + Send) {
unsafe { self.invoker.as_mut() }
}
pub(crate) unsafe fn task_ptr(&mut self) -> ManagedMutPtr<dyn Invoke + Send> {
unsafe {
let ptr = self.invoker.as_ptr();
let ptr = NonNullExt::new_unchecked(ptr);
ManagedMutPtr::new(ptr)
}
}
}
#[derive(Debug)]
pub struct PoisonedSystem {
id: SystemId,
name: &'static str,
data: Option<Box<dyn Any + Send>>,
err_payload: Box<dyn Any + Send>,
}
impl PoisonedSystem {
const fn new(
id: SystemId,
name: &'static str,
data: Option<Box<dyn Any + Send>>,
err_payload: Box<dyn Any + Send>,
) -> Self {
Self {
id,
name,
data,
err_payload,
}
}
fn from_system_data(sdata: SystemData, err_payload: Box<dyn Any + Send>) -> Self {
let id = sdata.id;
let name = sdata.info().name;
let data = sdata.try_into_any().ok();
Self::new(id, name, data, err_payload)
}
pub fn id(&self) -> SystemId {
self.id
}
pub fn name(&self) -> &'static str {
self.name
}
pub fn take_data(&mut self) -> Option<Box<dyn Any + Send>> {
self.data.take()
}
pub fn into_error_payload(self) -> Box<dyn Any + Send> {
self.err_payload
}
}
#[derive(Clone, Copy)]
pub struct SystemFlags(u32);
bitflags::bitflags! {
impl SystemFlags: u32 {
const DEDI_SET = 1;
const DEDI_RESET = 1 << 1;
const PRIVATE_SET = 1 << 2;
const PRIVATE_RESET = 1 << 3;
const OWNED_SET = 1 << 4;
const OWNED_RESET = 1 << 5;
}
}
impl SystemFlags {
pub(crate) const fn is_dedi(&self) -> bool {
debug_assert!(!self.is_dedi_empty());
self.intersects(Self::DEDI_SET)
}
pub(crate) const fn is_dedi_empty(&self) -> bool {
!self.intersects(Self::DEDI_SET.union(Self::DEDI_RESET))
}
pub(crate) const fn is_private(&self) -> bool {
debug_assert!(!self.is_private_empty());
self.intersects(Self::PRIVATE_SET)
}
pub(crate) const fn is_private_empty(&self) -> bool {
!self.intersects(Self::PRIVATE_SET.union(Self::PRIVATE_RESET))
}
pub(crate) const fn is_owned(&self) -> bool {
debug_assert!(!self.is_owned_empty());
self.intersects(Self::OWNED_SET)
}
pub(crate) const fn is_owned_empty(&self) -> bool {
!self.intersects(Self::OWNED_SET.union(Self::OWNED_RESET))
}
}
impl fmt::Debug for SystemFlags {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let dedi = if !self.is_dedi_empty() {
if self.is_dedi() {
"DEDI"
} else {
"NON-DEDI"
}
} else {
"DEDI?"
};
let private = if !self.is_private_empty() {
if self.is_private() {
"PRIVATE"
} else {
"NON-PRIVATE"
}
} else {
"PRIVATE?"
};
let owned = if !self.is_owned_empty() {
if self.is_owned() {
"OWNED"
} else {
"NON-OWNED"
}
} else {
"OWNED?"
};
f.debug_tuple("SystemFlags")
.field(&[dedi, private, owned].join(" | "))
.finish()
}
}
pub(crate) struct SystemInfo {
name: &'static str,
_skey: SystemKey,
rkey: RequestKey,
rinfo: Option<Arc<RequestInfo>>,
}
impl SystemInfo {
const fn new(
name: &'static str,
skey: SystemKey,
rkey: RequestKey,
rinfo: Arc<RequestInfo>,
) -> Self {
Self {
name,
_skey: skey,
rkey,
rinfo: Some(rinfo),
}
}
pub(crate) fn get_request_info(&self) -> &RequestInfo {
unsafe { self.rinfo.as_ref().unwrap_unchecked() }
}
}
impl fmt::Debug for SystemInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SystemInfo")
.field("name", &self.name)
.finish_non_exhaustive()
}
}
impl Drop for SystemInfo {
fn drop(&mut self) {
drop(self.rinfo.take());
let mut stor = RINFO_STOR.lock().unwrap();
stor.remove(&self.rkey);
}
}
pub struct SystemDesc<Sys> {
pub(crate) sys: Or<Sys, SystemData>,
pub(crate) private: bool,
pub group_index: u16,
pub volatile: bool,
pub activation: (Tick, InsertPos),
}
impl<Sys> fmt::Debug for SystemDesc<Sys> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SystemDesc")
.field("private", &self.private)
.field("group_index", &self.group_index)
.field("volatile", &self.volatile)
.field("activation", &self.activation)
.finish_non_exhaustive()
}
}
impl<Sys> SystemDesc<Sys>
where
Sys: System,
{
pub fn with_system<T, OutSys>(self, sys: T) -> SystemDesc<OutSys>
where
T: Into<SystemBond<OutSys>>,
OutSys: System,
{
let sys: SystemBond<OutSys> = sys.into();
SystemDesc::<OutSys> {
sys: Or::A(sys.into_inner()),
private: self.private,
group_index: self.group_index,
volatile: self.volatile,
activation: self.activation,
}
}
pub fn with_once<T, Req, F>(self, sys: T) -> SystemDesc<FnOnceSystem<Req, F>>
where
T: Into<FnOnceSystem<Req, F>>,
FnOnceSystem<Req, F>: System,
{
let activation = if self.activation.0 > 0 {
(1, self.activation.1)
} else {
self.activation
};
SystemDesc::<FnOnceSystem<Req, F>> {
sys: Or::A(sys.into()),
private: self.private,
group_index: self.group_index,
volatile: self.volatile,
activation,
}
}
pub fn with_group_index(self, index: u16) -> Self {
Self {
group_index: index,
..self
}
}
pub fn with_volatile(self, volatile: bool) -> Self {
Self { volatile, ..self }
}
pub fn with_activation(self, live: Tick, insert_at: InsertPos) -> Self {
Self {
activation: (live, insert_at),
..self
}
}
pub fn take_system(self) -> Sys {
match self.sys {
Or::A(sys) => sys,
Or::B(_sdata) => panic!(),
}
}
pub(crate) fn with_data(self, sdata: SystemData) -> SystemDesc<()> {
SystemDesc::<()> {
sys: Or::B(sdata),
private: self.private,
group_index: self.group_index,
volatile: self.volatile,
activation: self.activation,
}
}
pub(crate) fn with_private(self, private: bool) -> Self {
Self { private, ..self }
}
}
impl SystemDesc<()> {
pub const fn new() -> Self {
Self {
sys: Or::A(()),
private: false,
group_index: 0,
volatile: true,
activation: (Tick::MAX, InsertPos::Back),
}
}
}
impl Default for SystemDesc<()> {
fn default() -> Self {
Self::new()
}
}
impl<T: System> From<T> for SystemDesc<T> {
fn from(value: T) -> Self {
SystemDesc::new().with_system(value)
}
}
pub trait Invoke {
fn invoke(&mut self, buf: &mut SystemBuffer);
fn invoke_private(&mut self, sid: SystemId, buf: ManagedMutPtr<SystemBuffer>);
fn on_transition(&mut self, from: SystemState, to: SystemState);
fn into_any(self: Box<Self>) -> Box<dyn Any + Send>;
}
impl<S: System> Invoke for S {
fn invoke(&mut self, buf: &mut SystemBuffer) {
self.run(Response::new(buf));
}
fn invoke_private(&mut self, sid: SystemId, buf: ManagedMutPtr<SystemBuffer>) {
self.run_private(sid, buf);
}
fn on_transition(&mut self, from: SystemState, to: SystemState) {
self.on_transition(from, to);
}
fn into_any(self: Box<Self>) -> Box<dyn Any + Send> {
self
}
}
#[repr(transparent)]
pub struct FnSystem<Req, F> {
run: F,
_marker: PhantomData<Req>,
}
unsafe impl<Req, F: Send> Send for FnSystem<Req, F> {}
impl<Req, F> fmt::Debug for FnSystem<Req, F>
where
Self: System,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", Self::name())
}
}
#[repr(transparent)]
pub struct FnOnceSystem<Req, F> {
run: Option<F>,
_marker: PhantomData<Req>,
}
unsafe impl<Req, F: Send> Send for FnOnceSystem<Req, F> {}
impl<Req, F> fmt::Debug for FnOnceSystem<Req, F>
where
Self: System,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", Self::name())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Ph;
#[rustfmt::skip]
mod impl_for_fn_system {
use super::*;
use crate::ecs::sys::{
query::{Read, Write, ResRead, ResWrite, EntWrite},
request::ResponseAll,
};
macro_rules! _impl {
(
$req_with_placeholder:ty,
$req_with_tuple:ty
$(,r=$r:ident)?
$(,w=$w:ident)?
$(,rr=$rr:ident)?
$(,rw=$rw:ident)?
$(,ew=$ew:ident)?
) => {
impl<F $(,$r)? $(,$w)? $(,$rr)? $(,$rw)? $(,$ew)?>
From<F> for
FnSystem<$req_with_placeholder, F>
where
F: FnMut(
$(Read<$r>,)?
$(Write<$w>,)?
$(ResRead<$rr>,)?
$(ResWrite<$rw>,)?
$(EntWrite<$ew>,)?
),
$($r: Query,)?
$($w: QueryMut,)?
$($rr: ResQuery,)?
$($rw: ResQueryMut,)?
$($ew: EntQueryMut,)?
{
fn from(value: F) -> Self {
Self {
run: value,
_marker: PhantomData,
}
}
}
impl<F $(,$r)? $(,$w)? $(,$rr)? $(,$rw)? $(,$ew)?>
From<F> for
FnOnceSystem<$req_with_placeholder, F>
where
F: FnOnce(
$(Read<$r>,)?
$(Write<$w>,)?
$(ResRead<$rr>,)?
$(ResWrite<$rw>,)?
$(EntWrite<$ew>,)?
),
$($r: Query,)?
$($w: QueryMut,)?
$($rr: ResQuery,)?
$($rw: ResQueryMut,)?
$($ew: EntQueryMut,)?
{
fn from(value: F) -> Self {
Self {
run: Some(value),
_marker: PhantomData,
}
}
}
impl<F $(,$r)? $(,$w)? $(,$rr)? $(,$rw)? $(,$ew)?>
System for
FnSystem<$req_with_placeholder, F>
where
F: FnMut(
$(Read<$r>,)?
$(Write<$w>,)?
$(ResRead<$rr>,)?
$(ResWrite<$rw>,)?
$(EntWrite<$ew>,)?
) + Send + 'static,
$($r: Query,)?
$($w: QueryMut,)?
$($rr: ResQuery,)?
$($rw: ResQueryMut,)?
$($ew: EntQueryMut,)?
{
type Request = $req_with_tuple;
fn run(&mut self, mut resp: Response<Self::Request>) {
let ResponseAll {
read: _read,
write: _write,
res_read: _res_read,
res_write: _res_write,
ent_write: _ent_write
} = resp.all();
(self.run)(
$(Read::<'_, $r>(_read),)?
$(Write::<'_, $w>(_write),)?
$(ResRead::<'_, $rr>(_res_read),)?
$(ResWrite::<'_, $rw>(_res_write),)?
$(EntWrite::<$ew>(_ent_write),)?
)
}
fn name() -> &'static str {
std::any::type_name::<F>()
}
}
impl<F $(,$r)? $(,$w)? $(,$rr)? $(,$rw)? $(,$ew)?>
System for
FnOnceSystem<$req_with_placeholder, F>
where
F: FnOnce(
$(Read<$r>,)?
$(Write<$w>,)?
$(ResRead<$rr>,)?
$(ResWrite<$rw>,)?
$(EntWrite<$ew>,)?
) + Send + 'static,
$($r: Query,)?
$($w: QueryMut,)?
$($rr: ResQuery,)?
$($rw: ResQueryMut,)?
$($ew: EntQueryMut,)?
{
type Request = $req_with_tuple;
fn run(&mut self, mut resp: Response<Self::Request>) {
let ResponseAll {
read: _read,
write: _write,
res_read: _res_read,
res_write: _res_write,
ent_write: _ent_write
} = resp.all();
if let Some(run) = self.run.take() {
(run)(
$(Read::<'_, $r>(_read),)?
$(Write::<'_, $w>(_write),)?
$(ResRead::<'_, $rr>(_res_read),)?
$(ResWrite::<'_, $rw>(_res_write),)?
$(EntWrite::<$ew>(_ent_write),)?
)
} else {
panic!(
"unable to call `{}` twice, which implements FnOnce",
std::any::type_name::<F>()
);
}
}
fn name() -> &'static str {
std::any::type_name::<F>()
}
}
impl<F $(,$r)? $(,$w)? $(,$rr)? $(,$rw)? $(,$ew)?>
From<F> for
SystemBond<FnSystem<$req_with_placeholder, F>>
where
F: FnMut(
$(Read<$r>,)?
$(Write<$w>,)?
$(ResRead<$rr>,)?
$(ResWrite<$rw>,)?
$(EntWrite<$ew>,)?
),
$($r: Query,)?
$($w: QueryMut,)?
$($rr: ResQuery,)?
$($rw: ResQueryMut,)?
$($ew: EntQueryMut,)?
{
fn from(value: F) -> Self {
Self(value.into())
}
}
impl<F $(,$r)? $(,$w)? $(,$rr)? $(,$rw)? $(,$ew)?>
From<F> for
SystemDesc<FnSystem<$req_with_placeholder, F>>
where
F: FnMut(
$(Read<$r>,)?
$(Write<$w>,)?
$(ResRead<$rr>,)?
$(ResWrite<$rw>,)?
$(EntWrite<$ew>,)?
) + Send + 'static,
$($r: Query,)?
$($w: QueryMut,)?
$($rr: ResQuery,)?
$($rw: ResQueryMut,)?
$($ew: EntQueryMut,)?
{
fn from(value: F) -> Self {
SystemDesc::new().with_system(value)
}
}
};
}
#[allow(non_camel_case_types)]
type o = Ph;
_impl!((o , o , o , o , o ), ((), (), (), (), ()));
_impl!((R, o , o , o , o ), (R, (), (), (), ()), r=R);
_impl!((o , W, o , o , o ), ((), W, (), (), ()), w=W);
_impl!((R, W, o , o , o ), (R, W, (), (), ()), r=R, w=W);
_impl!((o , o , RR, o , o ), ((), (), RR, (), ()), rr=RR);
_impl!((R, o , RR, o , o ), (R, (), RR, (), ()), r=R, rr=RR);
_impl!((o , W, RR, o , o ), ((), W, RR, (), ()), w=W, rr=RR);
_impl!((R, W, RR, o , o ), (R, W, RR, (), ()), r=R, w=W, rr=RR);
_impl!((o , o , o , RW, o ), ((), (), (), RW, ()), rw=RW);
_impl!((R, o , o , RW, o ), (R, (), (), RW, ()), r=R, rw=RW);
_impl!((o , W, o , RW, o ), ((), W, (), RW, ()), w=W, rw=RW);
_impl!((R, W, o , RW, o ), (R, W, (), RW, ()), r=R, w=W, rw=RW);
_impl!((o , o , RR, RW, o ), ((), (), RR, RW, ()), rr=RR, rw=RW);
_impl!((R, o , RR, RW, o ), (R, (), RR, RW, ()), r=R, rr=RR, rw=RW);
_impl!((o , W, RR, RW, o ), ((), W, RR, RW, ()), w=W, rr=RR, rw=RW);
_impl!((R, W, RR, RW, o ), (R, W, RR, RW, ()), r=R, w=W, rr=RR, rw=RW);
_impl!((o , o , o , o , EW), ((), (), (), (), EW), ew=EW);
_impl!((R, o , o , o , EW), (R, (), (), (), EW), r=R, ew=EW);
_impl!((o , W, o , o , EW), ((), W, (), (), EW), w=W, ew=EW);
_impl!((R, W, o , o , EW), (R, W, (), (), EW), r=R, w=W, ew=EW);
_impl!((o , o , RR, o , EW), ((), (), RR, (), EW), rr=RR, ew=EW);
_impl!((R, o , RR, o , EW), (R, (), RR, (), EW), r=R, rr=RR, ew=EW);
_impl!((o , W, RR, o , EW), ((), W, RR, (), EW), w=W, rr=RR, ew=EW);
_impl!((R, W, RR, o , EW), (R, W, RR, (), EW), r=R, w=W, rr=RR, ew=EW);
_impl!((o , o , o , RW, EW), ((), (), (), RW, EW), rw=RW, ew=EW);
_impl!((R, o , o , RW, EW), (R, (), (), RW, EW), r=R, rw=RW, ew=EW);
_impl!((o , W, o , RW, EW), ((), W, (), RW, EW), w=W, rw=RW, ew=EW);
_impl!((R, W, o , RW, EW), (R, W, (), RW, EW), r=R, w=W, rw=RW, ew=EW);
_impl!((o , o , RR, RW, EW), ((), (), RR, RW, EW), rr=RR, rw=RW, ew=EW);
_impl!((R, o , RR, RW, EW), (R, (), RR, RW, EW), r=R, rr=RR, rw=RW, ew=EW);
_impl!((o , W, RR, RW, EW), ((), W, RR, RW, EW), w=W, rr=RR, rw=RW, ew=EW);
_impl!((R, W, RR, RW, EW), (R, W, RR, RW, EW), r=R, w=W, rr=RR, rw=RW, ew=EW);
}
#[derive(Debug)]
#[repr(transparent)]
pub struct SystemBond<S>(S);
impl<S> SystemBond<S> {
pub(crate) fn into_inner(self) -> S {
self.0
}
}
impl<S: System> From<S> for SystemBond<S> {
fn from(value: S) -> Self {
Self(value)
}
}
pub type Tick = u64;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_systemgroup_unregister_volatile() {
let mut sgroup = SystemGroup::new(0);
let mut sdata: SystemData = ().into_data();
let sid = sgroup.next_system_id();
sdata.id = sid;
sgroup.register(sdata, true).unwrap();
validate_len(&sgroup, 0, 1, 1);
sgroup.unregister(&sid).unwrap();
sgroup.drain_dead();
validate_len(&sgroup, 0, 0, 0);
}
#[test]
fn test_systemgroup_mixed_operations() {
let mut sgroup = SystemGroup::new(0);
let mut sdata: SystemData = ().into_data();
let sid_a = sgroup.next_system_id();
sdata.id = sid_a;
sgroup.register(sdata, false).unwrap();
validate_len(&sgroup, 0, 1, 0);
sgroup.activate(&sid_a, InsertPos::Back, 1).unwrap();
validate_len(&sgroup, 1, 0, 0);
let mut sdata: SystemData = ().into_data();
let sid_b = sgroup.next_system_id();
sdata.id = sid_b;
sgroup.register(sdata, true).unwrap();
validate_len(&sgroup, 1, 1, 1);
sgroup.activate(&sid_b, InsertPos::Back, 2).unwrap();
validate_len(&sgroup, 2, 0, 1);
sgroup.tick();
sgroup.drain_dead();
validate_len(&sgroup, 1, 1, 1);
sgroup.tick();
sgroup.drain_dead();
validate_len(&sgroup, 0, 1, 0);
sgroup.unregister(&sid_a).unwrap();
sgroup.drain_dead();
validate_len(&sgroup, 0, 0, 0);
}
fn validate_len(sgroup: &SystemGroup, act: usize, inact: usize, vol: usize) {
assert_eq!(sgroup.active.len(), act);
assert_eq!(sgroup.inactive.len(), inact);
assert_eq!(sgroup.volatile.len(), vol);
}
}