#![cfg_attr(unstable, feature(const_heap))]
#![cfg_attr(unstable, feature(const_type_name))]
#![cfg_attr(unstable, feature(core_intrinsics))]
#![cfg_attr(unstable, feature(const_cmp))]
#![cfg_attr(unstable, feature(const_trait_impl))]
#![allow(internal_features)]
#![deny(warnings)]
#![warn(missing_docs)]
#![warn(clippy::missing_docs_in_private_items)]
#[cfg_attr(unstable, path = "const_type_id/compiled.rs")]
#[cfg_attr(not(unstable), path = "const_type_id/runtime.rs")]
mod const_type_id;
mod event_manager;
mod rw_cell;
mod static_eval;
mod store;
mod thread_pool;
mod traits;
use crate::event_manager::*;
use crate::rw_cell::*;
use crate::static_eval::*;
pub use crate::store::*;
pub use crate::thread_pool::*;
pub use crate::traits::*;
use bitvec::access::*;
use bitvec::prelude::*;
use const_list::*;
use smallvec::*;
use std::any::*;
use std::cell::*;
use std::collections::hash_map::*;
use std::hash::*;
use std::hint::*;
use std::marker::*;
use std::mem::*;
use std::ops::*;
use std::pin::*;
use std::sync::atomic::*;
use std::sync::*;
use topological_sort::*;
type TypeMap<V> = HashMap<TypeId, V, TypeIdBuilderHasher>;
#[allow(unused_variables)]
pub struct GeeseContextHandle<S: GeeseSystem> {
inner: Arc<ContextHandleInner>,
data: PhantomData<fn(S)>,
}
impl<S: GeeseSystem> GeeseContextHandle<S> {
#[inline(always)]
fn new(inner: Arc<ContextHandleInner>) -> Self {
Self {
inner,
data: PhantomData,
}
}
#[inline(always)]
pub fn raise_event_boxed(&self, event: Box<dyn Any + Send + Sync>) {
unsafe {
drop(
self.inner
.event_sender
.lock()
.unwrap_unchecked()
.send(Event::new(event)),
);
}
}
#[inline(always)]
pub fn raise_event<T: 'static + Send + Sync>(&self, event: T) {
self.raise_event_boxed(Box::new(event));
}
#[inline(always)]
pub fn get<T: GeeseSystem>(&self) -> SystemRef<'_,T> {
unsafe {
let index = static_eval!(
if let Some(index) = S::DEPENDENCIES.index_of::<T>() {
index
} else {
GeeseContextHandle::<S>::panic_on_invalid_dependency::<T>()
},
usize,
S,
T
);
let ctx = (*self.inner.context).borrow();
let global_index = self.inner.dependency_id(index as u16) as usize;
assert!(
*ctx.sync_systems.get_unchecked(global_index)
|| ctx.owning_thread == std::thread::current().id(),
"Attempted a cross-thread borrow of a system that did not implement Sync."
);
let guard = ctx
.systems
.get_unchecked(global_index)
.value
.borrow()
.detach();
SystemRef::new(RwCellGuard::map(guard, |system| {
transmute::<_, &(&T, *const ())>(system).0
}))
}
}
#[inline(always)]
pub fn get_mut<T: GeeseSystem>(&mut self) -> SystemRefMut<'_,T> {
unsafe {
let index = static_eval!(
{
if let Some(index) = S::DEPENDENCIES.index_of::<T>() {
assert!(
const_unwrap(S::DEPENDENCIES.as_inner().get(index)).mutable(),
"Attempted to mutably access an immutable dependency."
);
index
} else {
GeeseContextHandle::<S>::panic_on_invalid_dependency::<T>()
}
},
usize,
S,
T
);
let ctx = (*self.inner.context).borrow();
let global_index = self.inner.dependency_id(index as u16) as usize;
assert!(
*ctx.sync_systems.get_unchecked(global_index)
|| ctx.owning_thread == std::thread::current().id(),
"Attempted a cross-thread borrow of a system that did not implement Sync."
);
let guard = ctx
.systems
.get_unchecked(global_index)
.value
.borrow_mut()
.detach();
SystemRefMut::new(RwCellGuardMut::map(guard, |system| {
transmute::<_, &mut (&mut T, *const ())>(system).0
}))
}
}
#[cfg(unstable)]
#[inline(always)]
const fn panic_on_invalid_dependency<T: GeeseSystem>() -> ! {
unsafe {
const FIRST_SEGMENT: &str = "System ";
const SECOND_SEGMENT: &str = " was not a dependency of ";
let total_name = std::intrinsics::const_allocate(
FIRST_SEGMENT.len() + type_name::<T>().len() + SECOND_SEGMENT.len() + type_name::<S>().len(), 1);
let segments = [FIRST_SEGMENT, type_name::<T>(), SECOND_SEGMENT, type_name::<S>()];
let mut i = 0;
let mut position = 0;
while i < segments.len() {
let value = segments[i];
std::ptr::copy_nonoverlapping(value.as_ptr(), total_name.add(position), value.len());
position += value.len();
i += 1;
}
panic!("{}", std::str::from_utf8_unchecked(std::slice::from_raw_parts(total_name.cast_const(), position)));
}
}
#[cfg(not(unstable))]
#[inline(always)]
fn panic_on_invalid_dependency<T: GeeseSystem>() -> ! {
panic!("System {} was not a dependency of {}", type_name::<T>(), type_name::<S>());
}
}
impl<S: GeeseSystem> std::fmt::Debug for GeeseContextHandle<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("GeeseContextHandle")
.field("type", &type_name::<S>())
.finish()
}
}
unsafe impl<S: GeeseSystem> Send for GeeseContextHandle<S> {}
unsafe impl<S: GeeseSystem> Sync for GeeseContextHandle<S> {}
struct ContextHandleInner {
context: *const RwCell<ContextInner>,
dependency_ids: SmallVec<[Cell<u16>; Self::DEFAULT_DEPENDENCY_BUFFER_SIZE]>,
event_sender: wasm_sync::Mutex<std::sync::mpsc::Sender<Event>>,
id: Cell<u16>,
}
impl ContextHandleInner {
const DEFAULT_DEPENDENCY_BUFFER_SIZE: usize = 4;
#[inline(always)]
unsafe fn id(&self) -> u16 {
self.id.get()
}
#[inline(always)]
unsafe fn set_id(&self, value: u16) {
self.id.set(value);
}
#[inline(always)]
unsafe fn dependency_len(&self) -> u16 {
self.dependency_ids.len() as u16
}
#[inline(always)]
unsafe fn dependency_id(&self, index: u16) -> u16 {
self.dependency_ids.get_unchecked(index as usize).get()
}
#[inline(always)]
unsafe fn set_dependency_id(&self, index: u16, value: u16) {
*self.dependency_ids.get_unchecked(index as usize).as_ptr() = value;
}
}
pub struct GeeseContext(Pin<Box<RwCell<ContextInner>>>);
impl GeeseContext {
#[inline(always)]
pub fn with_threadpool(pool: impl GeeseThreadPool) -> Self {
Self(Box::pin(RwCell::new(ContextInner::with_threadpool(pool))))
}
#[inline(always)]
pub fn set_threadpool(&mut self, pool: impl GeeseThreadPool) {
self.0.borrow_mut().thread_pool = Arc::new(pool);
}
#[inline(always)]
pub fn flush(&mut self) -> impl '_ + EventQueue {
ContextEventQueue {
ctx: self,
queue: EventBuffer::default(),
}
}
#[inline(always)]
pub fn get<S: GeeseSystem>(&self) -> SystemRef<'_,S> {
unsafe {
let inner = self.0.borrow();
let index = inner
.system_initializers
.get(&TypeId::of::<S>())
.expect("System not found.")
.id();
let guard = inner
.systems
.get_unchecked(index as usize)
.value
.borrow()
.detach();
SystemRef::new(RwCellGuard::map(guard, |system| {
transmute::<_, &(&S, *const ())>(system).0
}))
}
}
#[inline(always)]
pub fn get_mut<S: GeeseSystem>(&mut self) -> SystemRefMut<'_,S> {
unsafe {
let inner = self.0.borrow();
let index = inner
.system_initializers
.get(&TypeId::of::<S>())
.expect("System not found.")
.id();
let guard = inner
.systems
.get_unchecked(index as usize)
.value
.borrow_mut()
.detach();
SystemRefMut::new(RwCellGuardMut::map(guard, |system| {
transmute::<_, &mut (&mut S, *const ())>(system).0
}))
}
}
#[inline(always)]
fn flush_buffer(&mut self, buffer: EventBuffer) {
unsafe {
let inner = self.0.borrow();
for event in buffer.events {
drop(inner.event_sender.send(Event::new(event)));
}
let pool = inner.thread_pool.clone();
let inner_mgr = inner.event_manager.get();
(*inner_mgr).push_external_event_cycle();
(*inner_mgr).gather_external_events();
drop(inner);
let ctx_ptr = &*self.0 as *const RwCell<ContextInner> as usize;
let mgr = Arc::new(EventManagerWrapper(
wasm_sync::Mutex::new(inner_mgr),
wasm_sync::Condvar::new(),
));
let mgr_clone = mgr.clone();
let callback = Arc::new_cyclic(move |weak| {
let weak_clone = weak.clone() as Weak<dyn Fn() + Send + Sync>;
move || {
Self::process_events(
ctx_ptr as *const _,
&mgr_clone.1,
&mgr_clone.0,
&weak_clone,
)
}
});
let mut lock_guard = MaybeUninit::new(mgr.0.lock().unwrap_unchecked());
loop {
let mut notify_new_work = false;
pool.set_callback(Some(callback.clone()));
while let Some(event_mgr) = lock_guard.assume_init_mut().as_mut() {
let guard = (*(ctx_ptr as *const RwCell<ContextInner>)).borrow();
match event_mgr.next_job(&guard) {
Ok(to_run) => {
lock_guard.assume_init_drop();
if take(&mut notify_new_work) {
guard.thread_pool.set_callback(Some(callback.clone()));
}
to_run.execute(&guard);
(***lock_guard.write(mgr.0.lock().unwrap_unchecked()))
.complete_job(&to_run);
notify_new_work = true;
}
Err(EventJobError::Complete) => {
**lock_guard.assume_init_mut() = std::ptr::null_mut();
guard.thread_pool.set_callback(None);
break;
}
_ => {
notify_new_work = false;
guard.thread_pool.set_callback(None);
lock_guard.write(
mgr.1.wait(lock_guard.assume_init_read()).unwrap_unchecked(),
);
}
}
}
let state = (*inner_mgr).update_state();
match state {
EventManagerState::Complete() => break,
EventManagerState::CycleClogged(event) => {
self.run_clogged_event(event, inner_mgr);
(*inner_mgr).gather_external_events();
}
};
**lock_guard.assume_init_mut() = inner_mgr;
}
lock_guard.assume_init_drop();
}
}
fn add_system<S: GeeseSystem>(&mut self) {
unsafe {
static_eval!(
assert!(
!has_duplicate_dependencies(&S::DEPENDENCIES),
"System had duplicate dependencies."
),
(),
S
);
let mut inner = self.0.borrow_mut();
if let Some(value) = inner.system_initializers.get(&TypeId::of::<S>()) {
assert!(!value.top_level(), "Cannot add duplicate dependencies.");
value.set_top_level(true);
} else {
inner.add_new_system::<S>();
let initializers = take(&mut inner.system_initializers);
let to_initialize = inner.instantiate_added_systems(&initializers, self.as_ptr());
drop(inner);
self.initialize_systems(to_initialize.into_iter());
self.0.borrow_mut().system_initializers = initializers;
}
}
}
fn remove_system<S: GeeseSystem>(&mut self) {
unsafe {
let mut inner = self.0.borrow_mut();
inner.remove_top_level_system::<S>();
let connected = inner.determine_connected_systems();
if connected.first_zero().is_some() {
let mut initializers = take(&mut inner.system_initializers);
drop(inner);
self.drop_systems(&connected, &mut initializers);
let mut inner = self.0.borrow_mut();
inner.system_initializers = initializers;
inner.compact_remaining_systems(&connected);
}
}
}
fn reset_system<S: GeeseSystem>(&mut self) {
self.0.borrow().reset_system::<S>();
}
#[inline(always)]
unsafe fn initialize_systems<'a>(&self, systems: impl Iterator<Item = &'a SystemInitializer>) {
let inner = self.0.borrow();
for system in systems {
let holder = inner.system_holder(system.id() as usize);
holder
.value
.borrow_mut()
.write(system.descriptor.create(holder.handle.clone()));
}
}
#[inline(always)]
unsafe fn drop_systems(
&self,
systems: &BitVec,
initializers: &mut TypeMap<SystemInitializer>,
) {
let inner = self.0.borrow();
for system in systems.iter_zeros().rev() {
let holder = inner.system_holder(system);
holder.drop();
initializers.remove(&holder.system_id);
}
}
#[inline(always)]
fn as_ptr(&self) -> *const RwCell<ContextInner> {
&*self.0
}
#[inline(always)]
unsafe fn run_clogged_event(
&mut self,
event: Box<dyn Any + Send + Sync>,
inner_mgr: *mut EventManager,
) {
if let Some(ev) = event.downcast_ref::<notify::AddSystem>() {
(ev.executor)(self);
}
if let Some(ev) = event.downcast_ref::<notify::RemoveSystem>() {
(ev.executor)(self);
}
if let Some(ev) = event.downcast_ref::<notify::ResetSystem>() {
(ev.executor)(self);
}
if let Ok(ev) = event.downcast::<notify::Flush>() {
(*inner_mgr).push_event_cycle(ev.0.events.into_iter())
}
}
#[inline(always)]
unsafe fn process_events(
ctx: *const RwCell<ContextInner>,
on_new_work: &wasm_sync::Condvar,
state: &wasm_sync::Mutex<*mut EventManager>,
callback: &Weak<dyn Fn() + Send + Sync>,
) {
let mut lock_guard = MaybeUninit::new(state.lock().unwrap_unchecked());
let mut notify_new_work = false;
while let Some(mgr) = lock_guard.assume_init_mut().as_mut() {
let guard = (*ctx).borrow();
match mgr.next_job(&guard) {
Ok(to_run) => {
lock_guard.assume_init_drop();
if take(&mut notify_new_work) {
guard
.thread_pool
.set_callback(Some(callback.upgrade().unwrap_unchecked()));
on_new_work.notify_all();
}
to_run.execute(&guard);
(***lock_guard.write(state.lock().unwrap_unchecked())).complete_job(&to_run);
notify_new_work = true;
}
Err(EventJobError::Complete) => {
**lock_guard.assume_init_mut() = std::ptr::null_mut();
guard.thread_pool.set_callback(None);
on_new_work.notify_all();
break;
}
Err(EventJobError::MainThreadRequired) => {
guard.thread_pool.set_callback(None);
on_new_work.notify_all();
break;
}
_ => {
guard.thread_pool.set_callback(None);
break;
}
}
}
lock_guard.assume_init_drop();
}
}
impl std::fmt::Debug for GeeseContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("GeeseContext")
.field(&(&*self.0 as *const RwCell<ContextInner> as *const ()))
.finish()
}
}
impl Default for GeeseContext {
#[inline(always)]
fn default() -> Self {
Self(Box::pin(RwCell::default()))
}
}
impl Drop for GeeseContext {
#[inline(always)]
fn drop(&mut self) {
unsafe {
self.0.borrow().clear_all_systems();
}
}
}
struct ContextInner {
event_handlers: EventMap,
event_manager: UnsafeCell<EventManager>,
event_sender: std::sync::mpsc::Sender<Event>,
owning_thread: std::thread::ThreadId,
sync_systems: BitVec,
system_initializers: TypeMap<SystemInitializer>,
systems: Vec<SystemHolder>,
thread_pool: Arc<dyn GeeseThreadPool>,
transitive_dependencies: SystemFlagsList,
transitive_dependencies_bi: SystemFlagsList,
transitive_dependencies_mut: SystemFlagsList,
}
impl ContextInner {
const DEFAULT_SYSTEM_PROCESSING_SIZE: usize = 8;
#[inline(always)]
pub fn with_threadpool(pool: impl GeeseThreadPool) -> Self {
let (mgr, event_sender) = EventManager::new();
Self {
event_handlers: EventMap::default(),
event_manager: UnsafeCell::new(mgr),
event_sender,
owning_thread: std::thread::current().id(),
sync_systems: BitVec::default(),
system_initializers: TypeMap::default(),
systems: Vec::default(),
thread_pool: Arc::new(pool),
transitive_dependencies: SystemFlagsList::default(),
transitive_dependencies_bi: SystemFlagsList::default(),
transitive_dependencies_mut: SystemFlagsList::default(),
}
}
#[inline(always)]
pub unsafe fn clear_all_systems(&self) {
for holder in self.systems.iter().rev() {
holder.drop();
}
}
#[inline(always)]
pub unsafe fn system_holder(&self, index: usize) -> &SystemHolder {
self.systems.get_unchecked(index)
}
#[inline(always)]
pub fn add_new_system<S: GeeseSystem>(&mut self) {
let mut to_process = SmallVec::new();
self.add_system_and_load_dependencies::<true>(
Box::<TypedSystemDescriptor<S>>::default(),
&mut to_process,
);
while let Some(system) = to_process.pop() {
self.add_system_and_load_dependencies::<false>(system, &mut to_process);
}
}
#[inline(always)]
fn add_system_and_load_dependencies<const TOP_LEVEL: bool>(
&mut self,
system: Box<dyn SystemDescriptor>,
to_process: &mut SmallVec<
[Box<dyn SystemDescriptor>; Self::DEFAULT_SYSTEM_PROCESSING_SIZE],
>,
) {
if TOP_LEVEL {
for dependency in system.dependencies().as_inner() {
to_process.push(dependency.descriptor());
}
self.system_initializers
.insert(system.system_id(), SystemInitializer::new(system, true));
} else if let Entry::Vacant(entry) = self.system_initializers.entry(system.system_id()) {
for dependency in system.dependencies().as_inner() {
to_process.push(dependency.descriptor());
}
entry.insert(SystemInitializer::new(system, false));
}
}
#[inline(always)]
pub fn instantiate_added_systems<'a>(
&mut self,
initializers: &'a TypeMap<SystemInitializer>,
ctx: *const RwCell<ContextInner>,
) -> SmallVec<[&'a SystemInitializer; Self::DEFAULT_SYSTEM_PROCESSING_SIZE]> {
unsafe {
assert!(
initializers.len() < u16::MAX as usize,
"Maximum number of supported systems exceeded."
);
let mut old_systems = take(&mut self.systems);
old_systems.set_len(0);
let old_system_view = old_systems.spare_capacity_mut();
let mut to_initialize = SmallVec::new();
self.systems.reserve(initializers.len());
self.event_handlers.clear();
self.sync_systems = BitVec::repeat(false, initializers.len());
self.transitive_dependencies = SystemFlagsList::new(false, initializers.len());
self.transitive_dependencies_mut = SystemFlagsList::new(false, initializers.len());
let mut default_holder;
for system in Self::topological_sort_systems(initializers) {
let old_id = system.id();
system.set_id(self.systems.len() as u16);
let holder = if old_id < u16::MAX {
let res = old_system_view.get_unchecked_mut(old_id as usize);
assert!(
res.assume_init_mut().value.free(),
"Attempted to borrow system while the context was moving it."
);
res
} else {
default_holder = MaybeUninit::new(SystemHolder::new(
system.descriptor().system_id(),
system.descriptor().dependency_len(),
self.event_sender.clone(),
ctx,
));
to_initialize.push(system.into_inner());
&mut default_holder
};
Self::update_holder_data(holder.assume_init_mut(), initializers, &system);
self.load_transitive_dependencies(holder.assume_init_mut(), &system);
self.systems.push(holder.assume_init_read());
self.event_handlers
.add_handlers(system.id(), system.descriptor().event_handlers());
self.sync_systems
.set_unchecked(system.id() as usize, system.descriptor().is_sync());
}
self.compute_sync_transitive_dependencies();
self.compute_transitive_dependencies_bi();
(*self.event_manager.get()).configure(self);
to_initialize
}
}
#[inline(always)]
fn remove_top_level_system<S: GeeseSystem>(&mut self) {
let system = self
.system_initializers
.get(&TypeId::of::<S>())
.expect("System was not loaded.");
assert!(
system.top_level(),
"System {:?} was not previously added.",
type_name::<S>()
);
system.set_top_level(false);
}
#[inline(always)]
fn determine_connected_systems(&self) -> BitVec {
unsafe {
let mut connected_systems = BitVec::repeat(false, self.systems.len());
for system in self.system_initializers.values() {
if system.top_level() {
connected_systems[..] |= self
.transitive_dependencies
.get_unchecked(system.id() as usize);
}
}
connected_systems
}
}
#[inline(always)]
unsafe fn load_transitive_dependencies(
&mut self,
holder: &SystemHolder,
initializer: &SystemInitializer,
) {
let mut edit = self
.transitive_dependencies
.edit_unchecked(holder.handle.id() as usize);
let mut edit_mut = self
.transitive_dependencies_mut
.edit_unchecked(holder.handle.id() as usize);
edit.set_unchecked(holder.handle.id() as usize, true);
edit_mut.set_unchecked(holder.handle.id() as usize, true);
for i in 0..holder.handle.dependency_len() {
let global_index = holder.handle.dependency_id(i);
edit.or_with_unchecked(global_index as usize);
if initializer
.descriptor()
.dependencies()
.as_inner()
.get(i as usize)
.unwrap_unchecked()
.mutable()
{
edit_mut.or_with_unchecked(global_index as usize);
}
}
}
#[inline(always)]
pub unsafe fn compact_remaining_systems(&mut self, connected: &BitVec) {
self.event_handlers.clear();
self.systems.set_len(0);
let old_systems = self.systems.spare_capacity_mut();
let mut new_systems = Vec::with_capacity(self.system_initializers.len());
let system_view = new_systems.spare_capacity_mut();
self.sync_systems = BitVec::repeat(false, self.system_initializers.len());
let mut new_transitive_dependencies =
SystemFlagsList::new(false, self.system_initializers.len());
let mut new_transitive_dependencies_mut =
SystemFlagsList::new(false, self.system_initializers.len());
for old_id in connected.iter_ones() {
let system_holder = old_systems.get_unchecked_mut(old_id);
let initializer = self
.system_initializers
.get(&system_holder.assume_init_ref().system_id)
.unwrap_unchecked();
initializer.set_id(Self::compact_system_id(old_id as u16, connected));
let new_system = system_view
.get_unchecked_mut(initializer.id() as usize)
.write(system_holder.assume_init_read());
new_system.handle.set_id(initializer.id());
Self::compact_transitive_dependencies(
new_system,
connected,
self.transitive_dependencies_mut.get_unchecked(old_id),
&mut new_transitive_dependencies,
&mut new_transitive_dependencies_mut,
);
self.event_handlers
.add_handlers(initializer.id(), initializer.descriptor().event_handlers());
self.sync_systems.set_unchecked(
initializer.id() as usize,
initializer.descriptor().is_sync(),
);
}
Self::drop_dead_holders(connected, old_systems);
new_systems.set_len(self.system_initializers.len());
self.systems = new_systems;
self.transitive_dependencies = new_transitive_dependencies;
self.transitive_dependencies_mut = new_transitive_dependencies_mut;
self.compute_sync_transitive_dependencies();
self.compute_transitive_dependencies_bi();
(*self.event_manager.get()).configure(self);
}
#[inline(always)]
pub fn reset_system<S: GeeseSystem>(&self) {
unsafe {
let id = self
.system_initializers
.get(&TypeId::of::<S>())
.expect("Attempted to reset nonexistant system.")
.id();
let to_load = self.unload_dependents(id);
self.load_dependents(to_load);
}
}
#[inline(always)]
unsafe fn load_dependents(
&self,
to_load: SmallVec<[u16; Self::DEFAULT_SYSTEM_PROCESSING_SIZE]>,
) {
for i in to_load.into_iter().rev() {
let holder = self.systems.get_unchecked(i as usize);
let descriptor = self
.system_initializers
.get(&holder.system_id)
.unwrap_unchecked()
.descriptor();
holder
.value
.borrow_mut()
.write(descriptor.create(holder.handle.clone()));
}
}
#[inline(always)]
unsafe fn unload_dependents(
&self,
id: u16,
) -> SmallVec<[u16; Self::DEFAULT_SYSTEM_PROCESSING_SIZE]> {
let mut dropped = SmallVec::new();
for i in ((id as usize + 1)..self.systems.len()).rev() {
if *self
.transitive_dependencies
.get_unchecked(i)
.get_unchecked(id as usize)
{
self.systems.get_unchecked(i).drop();
dropped.push(i as u16);
}
}
self.systems.get_unchecked(id as usize).drop();
dropped.push(id);
dropped
}
#[inline(always)]
unsafe fn compute_sync_transitive_dependencies(&mut self) {
let mut syncs = BitVec::repeat(false, self.systems.len());
let mut working_memory = BitVec::repeat(false, self.systems.len());
for i in 0..self.systems.len() {
working_memory.clone_from_bitslice(self.transitive_dependencies.get_unchecked(i));
*working_memory[..].not() |= &self.sync_systems;
if working_memory.all() {
syncs.set_unchecked(i, true);
}
}
self.sync_systems = syncs;
}
#[inline(always)]
unsafe fn compute_transitive_dependencies_bi(&mut self) {
self.transitive_dependencies_bi = self.compute_transitive_dependencies_inverse();
self.transitive_dependencies_bi |= &self.transitive_dependencies;
}
#[inline(always)]
unsafe fn compute_transitive_dependencies_inverse(&mut self) -> SystemFlagsList {
let mut inverse = SystemFlagsList::new(false, self.systems.len());
for i in (0..self.systems.len()).rev() {
let mut edit = inverse.edit_unchecked(i);
edit.set_unchecked(i, true);
let holder = self.systems.get_unchecked(i);
for i in (0..holder.handle.dependency_len()).map(|x| holder.handle.dependency_id(x)) {
edit.or_into_unchecked(i as usize);
}
}
inverse
}
#[inline(always)]
fn topological_sort_systems(
descriptors: &TypeMap<SystemInitializer>,
) -> Vec<SystemStateRef<'_>> {
unsafe {
let mut sort: TopologicalSort<SystemStateRef<'_>> = TopologicalSort::new();
for state in descriptors.values() {
sort.insert(SystemStateRef(state));
for dependency in state.descriptor().dependencies().as_inner() {
sort.add_dependency(
SystemStateRef(
descriptors
.get(&dependency.dependency_id().into())
.unwrap_unchecked(),
),
SystemStateRef(state),
);
}
}
sort.collect::<Vec<_>>()
}
}
#[inline(always)]
unsafe fn update_holder_data(
data: &SystemHolder,
descriptors: &TypeMap<SystemInitializer>,
state: &SystemInitializer,
) {
data.handle.set_id(state.id());
for (index, dependency) in state
.descriptor()
.dependencies()
.as_inner()
.into_iter()
.enumerate()
{
data.handle.set_dependency_id(
index as u16,
descriptors
.get(&dependency.dependency_id().into())
.unwrap_unchecked()
.id(),
);
}
}
#[inline(always)]
unsafe fn compact_system_id(system: u16, remaining_systems: &BitVec) -> u16 {
(*bitvec::ptr::bitslice_from_raw_parts(remaining_systems.as_bitptr(), system as usize))
.count_ones() as u16
}
#[inline(always)]
unsafe fn compact_transitive_dependencies(
holder: &SystemHolder,
connected: &BitVec,
old_transitive_dependencies_mut: &BitSlice,
transitive_dependencies: &mut SystemFlagsList,
transitive_dependencies_mut: &mut SystemFlagsList,
) {
let mut edit = transitive_dependencies.edit_unchecked(holder.handle.id() as usize);
let mut edit_mut = transitive_dependencies_mut.edit_unchecked(holder.handle.id() as usize);
edit.set(holder.handle.id() as usize, true);
edit_mut.set(holder.handle.id() as usize, true);
for i in 0..holder.handle.dependency_len() {
let old_global_index = holder.handle.dependency_id(i);
let global_index = Self::compact_system_id(old_global_index, connected);
edit.or_with_unchecked(global_index as usize);
if *old_transitive_dependencies_mut.get_unchecked(old_global_index as usize) {
edit_mut.or_with_unchecked(global_index as usize);
}
holder.handle.set_dependency_id(i, global_index);
}
}
#[inline(always)]
unsafe fn drop_dead_holders(connected: &BitVec, old_systems: &mut [MaybeUninit<SystemHolder>]) {
for dead_system in connected.iter_zeros() {
old_systems
.get_unchecked_mut(dead_system)
.assume_init_drop();
}
}
}
impl Default for ContextInner {
#[inline(always)]
fn default() -> Self {
Self::with_threadpool(HardwareThreadPool::default())
}
}
struct SystemInitializer {
descriptor: Box<dyn SystemDescriptor>,
id: Cell<u16>,
top_level: Cell<bool>,
}
impl SystemInitializer {
#[inline(always)]
pub fn new(descriptor: Box<dyn SystemDescriptor>, top_level: bool) -> Self {
Self {
descriptor,
id: Cell::new(u16::MAX),
top_level: Cell::new(top_level),
}
}
#[inline(always)]
pub fn descriptor(&self) -> &dyn SystemDescriptor {
&*self.descriptor
}
#[inline(always)]
pub fn id(&self) -> u16 {
self.id.get()
}
#[inline(always)]
pub fn set_id(&self, id: u16) {
self.id.set(id);
}
#[inline(always)]
pub fn top_level(&self) -> bool {
self.top_level.get()
}
#[inline(always)]
pub fn set_top_level(&self, top_level: bool) {
self.top_level.set(top_level);
}
}
#[derive(Copy, Clone)]
struct SystemStateRef<'a>(&'a SystemInitializer);
impl<'a> SystemStateRef<'a> {
#[inline(always)]
pub fn into_inner(self) -> &'a SystemInitializer {
self.0
}
}
impl<'a> Deref for SystemStateRef<'a> {
type Target = SystemInitializer;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<'a> Hash for SystemStateRef<'a> {
#[inline(always)]
fn hash<H: Hasher>(&self, state: &mut H) {
(self.0 as *const _ as usize).hash(state);
}
}
impl<'a> PartialEq for SystemStateRef<'a> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self.0 as *const _, other.0 as *const _)
}
}
impl<'a> Eq for SystemStateRef<'a> {}
struct SystemHolder {
pub handle: Arc<ContextHandleInner>,
pub system_id: TypeId,
pub value: RwCell<MaybeUninit<Box<dyn Any>>>,
}
impl SystemHolder {
#[allow(clippy::arc_with_non_send_sync)]
#[inline(always)]
pub unsafe fn new(
system_id: TypeId,
dependency_len: usize,
event_sender: std::sync::mpsc::Sender<Event>,
context: *const RwCell<ContextInner>,
) -> Self {
let mut dependency_ids = SmallVec::with_capacity(dependency_len);
dependency_ids.set_len(dependency_len);
Self {
handle: Arc::new(ContextHandleInner {
context,
event_sender: wasm_sync::Mutex::new(event_sender),
dependency_ids,
id: Cell::new(0),
}),
system_id,
value: RwCell::new(MaybeUninit::uninit()),
}
}
#[inline(always)]
pub unsafe fn drop(&self) {
let mut value = self.value.borrow_mut();
value.assume_init_drop();
assert!(
Arc::strong_count(&self.handle) == 1,
"Attempted to retain context handle beyond system lifetime."
);
}
}
#[derive(Clone, Debug, Default)]
struct SystemFlagsList {
data: BitVec,
stride: usize,
}
impl SystemFlagsList {
#[inline(always)]
pub fn new(bit: bool, size: usize) -> Self {
Self {
data: BitVec::repeat(bit, size * size),
stride: size,
}
}
#[inline(always)]
pub unsafe fn edit_unchecked(&mut self, index: usize) -> SystemFlagsListEdit<'_> {
let (rest, first) = self.data.split_at_unchecked_mut(index * self.stride);
SystemFlagsListEdit {
editable: &mut *bitvec::ptr::bitslice_from_raw_parts_mut(
first.as_mut_bitptr(),
self.stride,
),
rest,
stride: self.stride,
}
}
#[inline(always)]
pub unsafe fn get_unchecked(&self, index: usize) -> &BitSlice {
&*bitvec::ptr::bitslice_from_raw_parts(
self.data.as_bitptr().add(index * self.stride),
self.stride,
)
}
}
impl BitOrAssign<&SystemFlagsList> for SystemFlagsList {
#[inline(always)]
fn bitor_assign(&mut self, rhs: &SystemFlagsList) {
self.data |= &rhs.data;
}
}
struct SystemFlagsListEdit<'a> {
editable: &'a mut BitSlice<BitSafeUsize>,
rest: &'a mut BitSlice<BitSafeUsize>,
stride: usize,
}
impl<'a> SystemFlagsListEdit<'a> {
#[inline(always)]
pub unsafe fn or_with_unchecked(&mut self, index: usize) {
*self.editable |= &*bitvec::ptr::bitslice_from_raw_parts(
self.rest.as_bitptr().add(index * self.stride),
self.stride,
);
}
#[inline(always)]
pub unsafe fn or_into_unchecked(&mut self, index: usize) {
*bitvec::ptr::bitslice_from_raw_parts_mut(
self.rest.as_mut_bitptr().add(index * self.stride),
self.stride,
) |= &*self.editable;
}
}
impl<'a> Deref for SystemFlagsListEdit<'a> {
type Target = BitSlice<BitSafeUsize>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.editable
}
}
impl<'a> DerefMut for SystemFlagsListEdit<'a> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
self.editable
}
}
#[derive(Debug)]
pub struct SystemRef<'a, T: ?Sized> {
inner: RwCellGuard<'a, T>,
}
impl<'a, T: ?Sized> SystemRef<'a, T> {
#[inline(always)]
fn new(inner: RwCellGuard<'a, T>) -> Self {
Self { inner }
}
#[inline(always)]
pub fn map<U, F>(orig: SystemRef<'a, T>, f: F) -> SystemRef<'a, U>
where
F: FnOnce(&T) -> &U,
U: ?Sized,
{
SystemRef::new(RwCellGuard::map(orig.inner, f))
}
}
impl<'a, T: ?Sized> Deref for SystemRef<'a, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[derive(Debug)]
pub struct SystemRefMut<'a, T: ?Sized> {
inner: RwCellGuardMut<'a, T>,
}
impl<'a, T: ?Sized> SystemRefMut<'a, T> {
#[inline(always)]
fn new(inner: RwCellGuardMut<'a, T>) -> Self {
Self { inner }
}
#[inline(always)]
pub fn map<U, F>(orig: SystemRefMut<'a, T>, f: F) -> SystemRefMut<'a, U>
where
F: FnOnce(&mut T) -> &mut U,
U: ?Sized,
{
SystemRefMut::new(RwCellGuardMut::map(orig.inner, f))
}
}
impl<'a, T: ?Sized> Deref for SystemRefMut<'a, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<'a, T: ?Sized> DerefMut for SystemRefMut<'a, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
#[derive(Clone, Debug, Default)]
struct EventMap {
handlers: TypeMap<SmallVec<[EventHandlerEntry; Self::DEFAULT_HANDLER_BUFFER_SIZE]>>,
}
impl EventMap {
const DEFAULT_HANDLER_BUFFER_SIZE: usize = 4;
#[inline(always)]
pub fn add_handlers(&mut self, system_id: u16, handlers: &ConstList<'_, EventHandlerRaw>) {
for entry in handlers {
self.handlers
.entry(entry.event_id())
.or_default()
.push(EventHandlerEntry {
system_id,
handler: *entry.handler(),
});
}
}
#[inline(always)]
pub fn clear(&mut self) {
self.handlers.clear();
}
#[inline(always)]
pub fn handlers(&self, event: TypeId) -> &[EventHandlerEntry] {
self.handlers
.get(&event)
.map(|x| &x[..])
.unwrap_or_default()
}
}
#[derive(Copy, Clone, Debug, Default)]
struct EventHandlerEntry {
pub handler: EventInvoker,
pub system_id: u16,
}
#[derive(Default)]
pub struct EventBuffer {
events: SmallVec<[Box<dyn Any + Send + Sync>; Self::DEFAULT_EVENT_BUFFER_SIZE]>,
}
impl EventBuffer {
const DEFAULT_EVENT_BUFFER_SIZE: usize = 4;
}
impl EventQueue for EventBuffer {
fn with_many_boxed(
mut self,
events: impl IntoIterator<Item = Box<dyn Any + Send + Sync>>,
) -> Self {
self.events.extend(events);
self
}
}
struct ContextEventQueue<'a> {
ctx: &'a mut GeeseContext,
queue: EventBuffer,
}
impl<'a> EventQueue for ContextEventQueue<'a> {
fn with_many_boxed(
mut self,
events: impl IntoIterator<Item = Box<dyn Any + Send + Sync>>,
) -> Self {
self.queue.events.extend(events);
self
}
}
impl<'a> Drop for ContextEventQueue<'a> {
fn drop(&mut self) {
self.ctx.flush_buffer(take(&mut self.queue));
}
}
#[derive(Copy, Clone, Debug, Default)]
struct TypeIdBuilderHasher;
impl BuildHasher for TypeIdBuilderHasher {
type Hasher = TypeIdHasher;
#[inline(always)]
fn build_hasher(&self) -> Self::Hasher {
TypeIdHasher(MaybeUninit::uninit())
}
}
#[repr(transparent)]
struct TypeIdHasher(MaybeUninit<u64>);
impl Hasher for TypeIdHasher {
#[inline(always)]
fn finish(&self) -> u64 {
unsafe {
self.0.assume_init_read()
}
}
#[inline(always)]
fn write(&mut self, _: &[u8]) {
unsafe {
unreachable_unchecked();
}
}
#[inline(always)]
fn write_u64(&mut self, i: u64) {
self.0 = MaybeUninit::new(i);
}
}
pub mod notify {
use super::*;
pub(crate) struct AddSystem {
pub(super) executor: fn(&mut GeeseContext),
}
#[inline(always)]
pub fn add_system<S: GeeseSystem>() -> impl Send + Sync {
AddSystem {
executor: GeeseContext::add_system::<S>,
}
}
pub(crate) struct RemoveSystem {
pub(super) executor: fn(&mut GeeseContext),
}
#[inline(always)]
pub fn remove_system<S: GeeseSystem>() -> impl Send + Sync {
RemoveSystem {
executor: GeeseContext::remove_system::<S>,
}
}
pub(crate) struct ResetSystem {
pub(super) executor: fn(&mut GeeseContext),
}
#[inline(always)]
pub fn reset_system<S: GeeseSystem>() -> impl Send + Sync {
ResetSystem {
executor: GeeseContext::reset_system::<S>,
}
}
pub(crate) struct Delayed(pub(crate) Box<dyn Any + Send + Sync>);
#[inline(always)]
pub fn delayed<T: 'static + Send + Sync>(event: T) -> impl Send + Sync {
Delayed(Box::new(event))
}
pub(crate) struct Flush(pub EventBuffer);
impl EventQueue for Flush {
fn with_many_boxed(
mut self,
events: impl IntoIterator<Item = Box<dyn Any + Send + Sync>>,
) -> Self {
self.0.events.extend(events);
self
}
}
#[inline(always)]
pub fn flush() -> impl EventQueue + Send + Sync {
Flush(EventBuffer::default())
}
}
#[cfg(test)]
mod tests {
use super::*;
struct A;
impl A {
fn increment(&mut self, event: &Arc<AtomicUsize>) {
event.fetch_add(1, Ordering::Relaxed);
}
pub fn answer(&self) -> bool {
true
}
}
impl GeeseSystem for A {
const EVENT_HANDLERS: EventHandlers<Self> = event_handlers().with(Self::increment);
fn new(_: GeeseContextHandle<Self>) -> Self {
Self
}
}
struct B {
ctx: GeeseContextHandle<Self>,
}
impl B {
fn test_answer(&mut self, event: &Arc<AtomicBool>) {
event.store(self.ctx.get::<A>().answer(), Ordering::Relaxed);
}
}
impl GeeseSystem for B {
const DEPENDENCIES: Dependencies = dependencies().with::<A>();
const EVENT_HANDLERS: EventHandlers<Self> = event_handlers().with(Self::test_answer);
fn new(ctx: GeeseContextHandle<Self>) -> Self {
println!("made new b");
ctx.raise_event(());
Self { ctx }
}
}
struct C {
counter: AtomicUsize,
}
impl C {
pub fn counter(&self) -> usize {
self.counter.load(Ordering::Acquire)
}
fn increment_counter(&mut self, _: &()) {
self.counter.fetch_add(1, Ordering::AcqRel);
}
}
impl GeeseSystem for C {
const EVENT_HANDLERS: EventHandlers<Self> = event_handlers().with(Self::increment_counter);
fn new(_: GeeseContextHandle<Self>) -> Self {
Self {
counter: AtomicUsize::new(0),
}
}
}
struct D;
impl GeeseSystem for D {
const DEPENDENCIES: Dependencies = dependencies().with::<A>().with::<C>();
fn new(ctx: GeeseContextHandle<Self>) -> Self {
ctx.get::<C>().counter.store(4, Ordering::Release);
Self
}
}
struct E {
value: i32,
}
impl GeeseSystem for E {
fn new(_: GeeseContextHandle<Self>) -> Self {
Self { value: 0 }
}
}
struct F {
ctx: GeeseContextHandle<Self>,
}
impl F {
fn increment_value(&mut self, _: &()) {
self.ctx.get_mut::<E>().value += 1;
}
}
impl GeeseSystem for F {
const DEPENDENCIES: Dependencies = dependencies().with::<Mut<E>>();
const EVENT_HANDLERS: EventHandlers<Self> = event_handlers().with(Self::increment_value);
fn new(ctx: GeeseContextHandle<Self>) -> Self {
Self { ctx }
}
}
struct G {
ctx: GeeseContextHandle<Self>,
}
impl G {
fn negate_value(&mut self, _: &()) {
self.ctx.get_mut::<E>().value *= -1;
}
}
impl GeeseSystem for G {
const DEPENDENCIES: Dependencies = dependencies().with::<Mut<E>>().with::<F>();
const EVENT_HANDLERS: EventHandlers<Self> = event_handlers().with(Self::negate_value);
fn new(ctx: GeeseContextHandle<Self>) -> Self {
ctx.raise_event(());
Self { ctx }
}
}
struct H {
ctx: GeeseContextHandle<Self>,
not_safe: PhantomData<*const u8>,
}
impl H {
fn decrement(&mut self, event: &isize) {
if *event > 0 {
self.ctx.raise_event(*event - 1);
println!(
"J on thread {:?} count {event:?}",
std::thread::current().id()
);
if *event == 25 {
self.ctx.raise_event(());
}
}
}
}
impl GeeseSystem for H {
const EVENT_HANDLERS: EventHandlers<Self> = event_handlers().with(Self::decrement);
fn new(ctx: GeeseContextHandle<Self>) -> Self {
Self {
ctx,
not_safe: PhantomData,
}
}
}
struct I {
ctx: GeeseContextHandle<Self>,
last_value: usize,
}
impl I {
fn decrement(&mut self, event: &usize) {
if *event > 0 {
println!(
"I on thread {:?} count {event:?}",
std::thread::current().id()
);
self.last_value = *event;
self.ctx.raise_event(*event - 1);
}
}
fn hit_it(&mut self, _: &()) {
println!("Other hit it at {:?}", self.last_value);
}
}
impl GeeseSystem for I {
const EVENT_HANDLERS: EventHandlers<Self> =
event_handlers().with(Self::decrement).with(Self::hit_it);
fn new(ctx: GeeseContextHandle<Self>) -> Self {
Self { ctx, last_value: 0 }
}
}
struct J;
impl GeeseSystem for J {
const DEPENDENCIES: Dependencies = dependencies().with::<H>().with::<I>();
fn new(_: GeeseContextHandle<Self>) -> Self {
Self
}
}
struct K {
value: i32,
}
impl K {
fn increase(&mut self, value: &i32) {
assert!(*value > self.value);
self.value = *value;
}
}
impl GeeseSystem for K {
const EVENT_HANDLERS: EventHandlers<Self> = event_handlers().with(Self::increase);
fn new(_: GeeseContextHandle<Self>) -> Self {
Self { value: 0 }
}
}
#[test]
fn test_single_system() {
let ab = Arc::new(AtomicUsize::new(0));
let mut ctx = GeeseContext::default();
ctx.flush().with(notify::add_system::<A>()).with(ab.clone());
assert!(ab.load(Ordering::Relaxed) == 1);
}
#[test]
fn test_dependent_system() {
let ab = Arc::new(AtomicBool::new(false));
let mut ctx = GeeseContext::default();
ctx.flush().with(notify::add_system::<B>()).with(ab.clone());
assert!(ab.load(Ordering::Relaxed));
}
#[test]
fn test_system_reload_one() {
let mut ctx = GeeseContext::default();
ctx.flush()
.with(notify::add_system::<C>())
.with(notify::add_system::<B>());
assert_eq!(ctx.get::<C>().counter(), 1);
ctx.flush().with(notify::reset_system::<A>());
assert_eq!(ctx.get::<C>().counter(), 2);
}
#[test]
fn test_system_reload_order() {
let mut ctx = GeeseContext::default();
ctx.flush()
.with(notify::add_system::<D>())
.with(notify::add_system::<B>());
assert_eq!(ctx.get::<C>().counter(), 5);
ctx.flush().with(notify::reset_system::<A>());
assert_eq!(ctx.get::<C>().counter(), 5);
}
#[test]
#[should_panic]
fn test_add_system_event_twice_panic() {
let mut ctx = GeeseContext::default();
ctx.flush()
.with(notify::add_system::<B>())
.with(notify::add_system::<B>());
}
#[test]
#[should_panic]
fn test_remove_system_event_unknown_panic() {
let mut ctx = GeeseContext::default();
ctx.flush().with(notify::remove_system::<B>());
}
#[test]
fn test_mut_dependency() {
let mut ctx = GeeseContext::default();
ctx.flush().with(notify::add_system::<G>());
assert_eq!(ctx.get::<E>().value, -1);
}
#[test]
fn test_multiple_threads() {
let mut ctx = GeeseContext::with_threadpool(HardwareThreadPool::new(2));
ctx.flush()
.with(notify::add_system::<J>())
.with(50usize)
.with(50isize);
}
#[test]
fn test_flush() {
let mut ctx = GeeseContext::default();
ctx.flush()
.with(notify::add_system::<K>())
.with(1i32)
.with(notify::flush().with_many([2i32, 3]))
.with(4i32);
assert!(ctx.get::<K>().value == 4);
}
#[test]
#[should_panic]
fn test_no_flush() {
let mut ctx = GeeseContext::default();
ctx.flush()
.with(notify::add_system::<K>())
.with(1i32)
.with(4i32)
.with(2i32)
.with(3i32);
}
}