use core::{
any::TypeId,
pin::Pin,
sync::atomic::{AtomicBool, Ordering},
task::{Context, Poll, Waker},
};
use alloc::{
boxed::Box,
sync::{Arc, Weak},
task::Wake,
vec::Vec,
};
use amity::{flip_queue::FlipQueue, ring_buffer::RingBuffer};
use hashbrown::HashMap;
use slab::Slab;
use crate::{
entity::{EntityId, EntityRef},
system::State,
type_id,
world::{World, WorldLocal},
};
mod entity;
mod futures;
mod tls;
mod world;
pub use self::{entity::*, futures::*, world::*};
pub trait Flow {
unsafe fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()>;
}
trait MakeFlow: 'static {
type Flow: Flow;
fn make_flow(self) -> Option<Self::Flow>;
}
#[inline]
pub unsafe fn get_flow_world<'a>() -> &'a mut WorldLocal {
unsafe { tls::get_world_mut() }
}
trait AnyMakeFlows {
fn flow_id(&self) -> TypeId;
fn drain(&mut self, flows: &mut HashMap<TypeId, AnyQueue>);
}
impl<'a> dyn AnyMakeFlows + 'a {
#[inline]
unsafe fn downcast_mut<F: 'static>(&mut self) -> &mut TypedMakeFlows<F> {
debug_assert_eq!(self.flow_id(), type_id::<F>());
unsafe { &mut *(self as *mut Self as *mut TypedMakeFlows<F>) }
}
}
type FlowMake<F> = <F as MakeFlow>::Flow;
struct TypedMakeFlows<F> {
array: Vec<F>,
}
impl<F> AnyMakeFlows for TypedMakeFlows<F>
where
F: MakeFlow,
{
fn flow_id(&self) -> TypeId {
type_id::<F>()
}
fn drain(&mut self, flows: &mut HashMap<TypeId, AnyQueue>) {
if self.array.is_empty() {
return;
}
let flow_id = type_id::<FlowMake<F>>();
let queue = flows
.entry(flow_id)
.or_insert_with(AnyQueue::new::<FlowMake<F>>);
let typed_flows = unsafe { queue.flows.downcast_mut::<FlowMake<F>>() };
typed_flows.array.reserve(self.array.len());
for make_flow in self.array.drain(..) {
if let Some(flow) = make_flow.make_flow() {
let task_id = typed_flows.array.vacant_key();
let needs_wake = Arc::new(AtomicBool::new(false));
let task = FlowTask {
flow: Box::pin(flow),
needs_wake: needs_wake.clone(),
waker: Waker::from(Arc::new(FlowWaker {
task_id,
flip: Arc::downgrade(&queue.flip),
needs_wake,
})),
};
typed_flows.array.insert(task);
queue.ready.push(task_id);
}
}
}
}
pub(crate) struct NewFlows {
map: HashMap<TypeId, Box<dyn AnyMakeFlows>>,
}
impl NewFlows {
pub fn new() -> Self {
NewFlows {
map: HashMap::new(),
}
}
fn typed_new_flows<F>(&mut self) -> &mut TypedMakeFlows<F>
where
F: MakeFlow,
{
let new_flows = self
.map
.entry(type_id::<F>())
.or_insert_with(|| Box::new(TypedMakeFlows::<F> { array: Vec::new() }));
unsafe { new_flows.downcast_mut::<F>() }
}
fn add<F>(&mut self, flow: F)
where
F: MakeFlow,
{
let typed_new_flows = self.typed_new_flows();
typed_new_flows.array.push(flow);
}
}
trait AnyFlows {
#[cfg(debug_assertions)]
fn flow_id(&self) -> TypeId;
unsafe fn execute(&mut self, front: &[usize], back: &[usize]);
}
impl dyn AnyFlows {
#[inline]
unsafe fn downcast_mut<F: 'static>(&mut self) -> &mut TypedFlows<F> {
#[cfg(debug_assertions)]
assert_eq!(self.flow_id(), type_id::<F>());
unsafe { &mut *(self as *mut Self as *mut TypedFlows<F>) }
}
}
struct FlowWaker {
task_id: usize,
needs_wake: Arc<AtomicBool>,
flip: Weak<FlipQueue<usize>>,
}
impl Wake for FlowWaker {
#[inline]
fn wake(self: Arc<Self>) {
self.wake_by_ref();
}
#[inline]
fn wake_by_ref(self: &Arc<Self>) {
let needs_wake = self.needs_wake.fetch_and(false, Ordering::Acquire);
if !needs_wake {
return;
}
let Some(flip) = self.flip.upgrade() else {
return;
};
flip.push_sync(self.task_id);
}
}
struct FlowTask<F> {
flow: Pin<Box<F>>,
needs_wake: Arc<AtomicBool>,
waker: Waker,
}
struct TypedFlows<F> {
array: Slab<FlowTask<F>>,
}
impl<F> TypedFlows<F>
where
F: Flow + 'static,
{
#[inline]
unsafe fn execute(&mut self, ids: &[usize]) {
for &id in ids {
let Some(task) = self.array.get_mut(id) else {
continue;
};
let mut cx = Context::from_waker(&task.waker);
let pinned = task.flow.as_mut();
task.needs_wake.store(true, Ordering::Release);
let poll = unsafe { F::poll(pinned, &mut cx) };
if let Poll::Ready(()) = poll {
self.array.remove(id);
}
}
}
}
impl<F> AnyFlows for TypedFlows<F>
where
F: Flow + 'static,
{
#[cfg(debug_assertions)]
fn flow_id(&self) -> TypeId {
type_id::<F>()
}
unsafe fn execute(&mut self, front: &[usize], back: &[usize]) {
unsafe {
self.execute(front);
}
unsafe {
self.execute(back);
}
}
}
struct AnyQueue {
flip: Arc<FlipQueue<usize>>,
ready: RingBuffer<usize>,
flows: Box<dyn AnyFlows>,
}
impl AnyQueue {
fn new<F>() -> Self
where
F: Flow + 'static,
{
AnyQueue {
flip: Arc::new(FlipQueue::new()),
ready: RingBuffer::new(),
flows: Box::new(TypedFlows::<F> { array: Slab::new() }),
}
}
}
pub struct Flows {
new_flows: NewFlows,
map: HashMap<TypeId, AnyQueue>,
}
impl Default for Flows {
fn default() -> Self {
Self::new()
}
}
impl Flows {
pub fn new() -> Self {
Flows {
new_flows: NewFlows::new(),
map: HashMap::new(),
}
}
fn collect_new_flows<'a>(&mut self, world: &'a mut World) -> Option<tls::WorldGuard<'a>> {
let world = world.local();
core::mem::swap(&mut self.new_flows, world.new_flows.get_mut());
let guard = tls::WorldGuard::new(world);
for typed in self.map.values_mut() {
debug_assert!(typed.ready.is_empty());
typed.flip.swap_buffer(&mut typed.ready);
}
for (_, typed) in &mut self.new_flows.map {
typed.drain(&mut self.map);
}
Some(guard)
}
pub fn execute(&mut self, world: &mut World) {
world.maintenance();
let Some(_guard) = self.collect_new_flows(world) else {
return;
};
for typed in self.map.values_mut() {
let (front, back) = typed.ready.as_slices();
unsafe {
typed.flows.execute(front, back);
}
typed.ready.clear();
}
}
pub fn enter<F, R>(world: &mut World, f: F) -> R
where
F: FnOnce(FlowWorld) -> R,
{
let guard = tls::WorldGuard::new(world.local());
let r = f(FlowWorld::new());
drop(guard);
r
}
}
pub fn flows_system(world: &mut World, mut flows: State<Flows>) {
let flows = &mut *flows;
flows.execute(world);
}
struct EntityIntoFlow<F> {
entity: EntityId,
f: F,
}
impl<F> MakeFlow for EntityIntoFlow<F>
where
F: IntoEntityFlow,
{
type Flow = F::Flow;
fn make_flow(self) -> Option<F::Flow> {
let e = FlowEntity::new(self.entity);
if e.is_alive() {
unsafe { self.f.into_entity_flow(e) }
} else {
None
}
}
}
struct WorldIntoFlow<F> {
f: F,
}
impl<F> MakeFlow for WorldIntoFlow<F>
where
F: IntoFlow,
{
type Flow = F::Flow;
fn make_flow(self) -> Option<F::Flow> {
self.f.into_flow(FlowWorld::new())
}
}
impl World {
pub fn spawn_flow<F>(&mut self, flow: F)
where
F: IntoFlow,
{
self.new_flows.get_mut().add(WorldIntoFlow { f: flow });
}
pub fn spawn_flow_for<F>(&mut self, entity: EntityId, flow: F)
where
F: IntoEntityFlow,
{
self.new_flows
.get_mut()
.add(EntityIntoFlow { entity, f: flow });
}
}
impl WorldLocal {
pub fn spawn_flow<F>(&self, flow: F)
where
F: IntoFlow,
{
unsafe { &mut *self.new_flows.get() }.add(WorldIntoFlow { f: flow });
}
pub fn spawn_flow_for<F>(&self, entity: EntityId, flow: F)
where
F: IntoEntityFlow,
{
unsafe { &mut *self.new_flows.get() }.add(EntityIntoFlow { entity, f: flow });
}
}
impl FlowWorld {
pub fn spawn_flow<F>(self, flow: F)
where
F: IntoFlow,
{
let world = unsafe { self.get() };
world.spawn_flow(flow);
}
pub fn spawn_flow_for<F>(&self, entity: EntityId, flow: F)
where
F: IntoEntityFlow,
{
let world = unsafe { self.get() };
world.spawn_flow_for(entity, flow);
}
}
impl EntityRef<'_> {
pub fn spawn_flow<F>(&mut self, f: F)
where
F: crate::flow::IntoEntityFlow,
{
let id = self.id();
self.world().spawn_flow_for(id, f);
}
}