use bevy::{
ecs::system::{BoxedSystem, Command, StaticSystemParam, SystemParam},
prelude::*,
utils::HashMap,
};
use pecs_macro::{asyn, impl_all_promises, impl_any_promises};
use std::{
any::type_name,
cell::RefCell,
marker::PhantomData,
mem,
sync::{Arc, RwLock},
thread::{self, ThreadId},
};
pub mod app;
mod impls;
pub mod timer;
pub mod ui;
pub struct AsynOps<T>(pub T);
impl<T: Clone> Clone for AsynOps<T> {
fn clone(&self) -> Self {
AsynOps(self.0.clone())
}
}
impl<T: Copy> Copy for AsynOps<T> {}
pub fn promise_resolve<S: 'static, R: 'static>(world: &mut World, id: PromiseId, state: S, result: R) {
let registry = world
.get_resource_or_insert_with(PromiseRegistry::<S, R>::default)
.clone();
if let Some(resolve) = {
let mut write = registry.0.write().unwrap();
let prom = write.get_mut(&id).unwrap();
mem::take(&mut prom.resolve)
} {
resolve(world, state, result)
}
registry.0.write().unwrap().remove(&id);
}
pub fn promise_register<S: 'static, R: 'static>(world: &mut World, mut promise: Promise<S, R>) {
let id = promise.id;
let register = promise.register;
promise.register = None;
let registry = world
.get_resource_or_insert_with(PromiseRegistry::<S, R>::default)
.clone();
registry.0.write().unwrap().insert(id, promise);
if let Some(register) = register {
register(world, id)
}
}
pub fn promise_discard<S: 'static, R: 'static>(world: &mut World, id: PromiseId) {
let registry = world
.get_resource_or_insert_with(PromiseRegistry::<S, R>::default)
.clone();
if let Some(discard) = {
let mut write = registry.0.write().unwrap();
if let Some(prom) = write.get_mut(&id) {
mem::take(&mut prom.discard)
} else {
error!(
"Internal promise error: trying to discard complete {id}<{}, {}>",
type_name::<S>(),
type_name::<R>(),
);
None
}
} {
discard(world, id);
}
registry.0.write().unwrap().remove(&id);
}
pub trait PromiseParams: 'static + SystemParam + Send + Sync {}
impl<T: 'static + SystemParam + Send + Sync> PromiseParams for T {}
pub struct Asyn<Input, Output: 'static, Params: PromiseParams> {
pub marker: PhantomData<Params>,
pub body: fn(In<Input>, StaticSystemParam<Params>) -> Output,
}
impl<Input, Otput: 'static, Params: PromiseParams> Clone for Asyn<Input, Otput, Params> {
fn clone(&self) -> Self {
Asyn {
body: self.body.clone(),
marker: self.marker,
}
}
}
impl<Input, Output: 'static, Params: PromiseParams> PartialEq for Asyn<Input, Output, Params> {
fn eq(&self, other: &Self) -> bool {
self.ptr() == other.ptr()
}
}
impl<Input, Output: 'static, Params: PromiseParams> Eq for Asyn<Input, Output, Params> {}
impl<Input, Output: 'static, Params: PromiseParams> std::hash::Hash for Asyn<Input, Output, Params> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.ptr().hash(state)
}
}
impl<Input, Output: 'static, Params: PromiseParams> Asyn<Input, Output, Params> {
pub fn new(body: fn(In<Input>, StaticSystemParam<Params>) -> Output) -> Self {
Asyn {
body,
marker: PhantomData,
}
}
fn ptr(&self) -> *const fn(In<Input>, StaticSystemParam<Params>) -> Output {
self.body as *const fn(In<Input>, StaticSystemParam<Params>) -> Output
}
}
impl<Input: 'static, Output: 'static, Params: PromiseParams> Asyn<Input, Output, Params> {
pub fn run(&self, input: Input, world: &mut World) -> Output {
let registry = world
.get_resource_or_insert_with(SystemRegistry::<Input, Output, Params>::default)
.clone();
let mut write = registry.0.write().unwrap();
let key = self.clone();
let system = write.entry(key).or_insert_with(|| {
let mut sys = Box::new(IntoSystem::into_system(self.body));
sys.initialize(world);
sys
});
let result = system.run(input, world);
system.apply_deferred(world);
result
}
}
thread_local!(static PROMISE_LOCAL_ID: std::cell::RefCell<usize> = RefCell::new(0));
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct PromiseId {
thread: ThreadId,
local: usize,
}
impl PromiseId {
pub fn new() -> PromiseId {
PROMISE_LOCAL_ID.with(|id| {
let mut new_id = id.borrow_mut();
*new_id += 1;
PromiseId {
thread: thread::current().id(),
local: *new_id,
}
})
}
}
impl std::fmt::Display for PromiseId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let t = format!("{:?}", self.thread);
write!(
f,
"Promise({}:{})",
t.strip_prefix("ThreadId(").unwrap().strip_suffix(")").unwrap(),
self.local
)
}
}
impl std::fmt::Debug for PromiseId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self}")
}
}
pub enum PromiseResult<S, R> {
Resolve(S, R),
Await(Promise<S, R>),
}
impl<S, R> From<Promise<S, R>> for PromiseResult<S, R> {
fn from(value: Promise<S, R>) -> Self {
PromiseResult::Await(value)
}
}
impl From<()> for PromiseResult<(), ()> {
fn from(_: ()) -> Self {
PromiseResult::Resolve((), ())
}
}
impl<S: 'static> From<PromiseState<S>> for PromiseResult<S, ()> {
fn from(state: PromiseState<S>) -> Self {
PromiseResult::Resolve(state.value, ())
}
}
#[derive(Resource)]
struct PromiseRegistry<S, R>(Arc<RwLock<HashMap<PromiseId, Promise<S, R>>>>);
impl<S, R> Default for PromiseRegistry<S, R> {
fn default() -> Self {
PromiseRegistry(Arc::new(RwLock::new(HashMap::new())))
}
}
impl<S, R> Clone for PromiseRegistry<S, R> {
fn clone(&self) -> Self {
PromiseRegistry(self.0.clone())
}
}
#[derive(Resource)]
struct SystemRegistry<In, Out: 'static, Params: PromiseParams>(
Arc<RwLock<HashMap<Asyn<In, Out, Params>, BoxedSystem<In, Out>>>>,
);
impl<In, Out, Params: PromiseParams> Clone for SystemRegistry<In, Out, Params> {
fn clone(&self) -> Self {
SystemRegistry(self.0.clone())
}
}
impl<In, Out, Params: PromiseParams> Default for SystemRegistry<In, Out, Params> {
fn default() -> Self {
SystemRegistry(Arc::new(RwLock::new(HashMap::new())))
}
}
pub enum Repeat<R> {
Continue,
Break(R),
}
impl Repeat<()> {
pub fn forever() -> Self {
Repeat::Continue
}
}
pub struct Promise<S, R> {
id: PromiseId,
register: Option<Box<dyn FnOnce(&mut World, PromiseId)>>,
discard: Option<Box<dyn FnOnce(&mut World, PromiseId)>>,
resolve: Option<Box<dyn FnOnce(&mut World, S, R)>>,
}
unsafe impl<S, R> Send for Promise<S, R> {}
unsafe impl<S, R> Sync for Promise<S, R> {}
impl<S: 'static> Promise<S, ()> {
pub fn from(state: S) -> Promise<S, ()> {
Self::new(state, asyn!(s => s))
}
}
impl<S: 'static, R: 'static> Promise<S, R> {
pub fn start(func: Asyn![() => S, R]) -> Promise<S, R> {
Promise::new((), func)
}
pub fn new<D: 'static>(default_state: D, func: Asyn![D => S, R]) -> Promise<S, R> {
let id = PromiseId::new();
Promise {
id,
resolve: None,
discard: None,
register: Some(Box::new(move |world, id| {
let pr = func.run((PromiseState::new(default_state), ()), world).into();
match pr {
PromiseResult::Resolve(s, r) => promise_resolve::<S, R>(world, id, s, r),
PromiseResult::Await(mut p) => {
if p.resolve.is_some() {
error!(
"Misconfigured {}<{}, {}>, resolve already defined",
p.id,
type_name::<S>(),
type_name::<R>(),
);
return;
}
p.resolve = Some(Box::new(move |world, s, r| promise_resolve::<S, R>(world, id, s, r)));
promise_register::<S, R>(world, p);
}
}
})),
}
}
pub fn register<F: 'static + FnOnce(&mut World, PromiseId), D: 'static + FnOnce(&mut World, PromiseId)>(
on_invoke: F,
on_discard: D,
) -> Promise<S, R> {
Promise {
id: PromiseId::new(),
resolve: None,
register: Some(Box::new(on_invoke)),
discard: Some(Box::new(on_discard)),
}
}
pub fn repeat(state: S, func: Asyn![S => S, Repeat<R>]) -> Promise<S, R> {
Promise::new(
(state, func),
asyn!(s => {
let (state, func) = s.value;
let next = func.clone();
Promise::new(state, func).map(|state| (state, next)).then(asyn!(s, r => {
let (state, next) = s.value;
match r {
Repeat::Continue => PromiseResult::Await(Promise::repeat(state, next)),
Repeat::Break(result) => PromiseResult::Resolve(state, result)
}
}))
}),
)
}
}
impl<R: 'static> Promise<(), R> {
pub fn resolve(result: R) -> PromiseResult<(), R> {
PromiseResult::Resolve((), result)
}
}
impl Promise<(), ()> {
pub fn pass() -> PromiseResult<(), ()> {
PromiseResult::Resolve((), ())
}
pub fn any<T: AnyPromises>(any: T) -> Promise<(), T::Result> {
any.register()
}
pub fn all<T: AllPromises>(any: T) -> Promise<(), T::Result> {
any.register()
}
}
pub struct PromiseCommand<R> {
id: PromiseId,
result: R,
}
impl<R> PromiseCommand<R> {
pub fn resolve(id: PromiseId, result: R) -> Self {
PromiseCommand { id, result }
}
}
impl<R: 'static + Send + Sync> Command for PromiseCommand<R> {
fn apply(self, world: &mut World) {
promise_resolve::<(), R>(world, self.id, (), self.result);
}
}
impl<R: 'static, S: 'static> Command for Promise<S, R> {
fn apply(self, world: &mut World) {
promise_register::<S, R>(world, self)
}
}
pub trait PromiseCommandsArg {}
impl PromiseCommandsArg for PromiseId {}
impl<S: 'static, R: 'static> PromiseCommandsArg for Promise<S, R> {}
pub struct PromiseCommands<'w, 's, 'a, T> {
data: Option<T>,
commands: Option<&'a mut Commands<'w, 's>>,
finally: Option<fn(&'a mut Commands<'w, 's>, T)>,
}
impl<'w, 's, 'a> PromiseCommands<'w, 's, 'a, PromiseId> {
pub fn resolve<R: 'static + Send + Sync>(&mut self, value: R) {
let commands = mem::take(&mut self.commands).unwrap();
let id = mem::take(&mut self.data).unwrap();
commands.add(PromiseCommand::<R>::resolve(id, value));
}
}
impl<'w, 's, 'a, T> Drop for PromiseCommands<'w, 's, 'a, T> {
fn drop(&mut self) {
let commands = mem::take(&mut self.commands);
let data = mem::take(&mut self.data);
if let Some(commands) = commands {
if let Some(data) = data {
if let Some(finally) = &self.finally {
finally(commands, data)
}
}
}
}
}
pub trait PromiseCommandsExtension<'w, 's, T> {
fn promise<'a>(&'a mut self, promise: T) -> PromiseCommands<'w, 's, 'a, T>;
}
impl<'w, 's, S: 'static, F: FnOnce() -> S> PromiseCommandsExtension<'w, 's, F> for Commands<'w, 's> {
fn promise<'a>(&'a mut self, arg: F) -> PromiseCommands<'w, 's, 'a, F> {
PromiseCommands {
data: Some(arg),
commands: Some(self),
finally: None,
}
}
}
impl<'w, 's> PromiseCommandsExtension<'w, 's, PromiseId> for Commands<'w, 's> {
fn promise<'a>(&'a mut self, arg: PromiseId) -> PromiseCommands<'w, 's, 'a, PromiseId> {
PromiseCommands {
data: Some(arg),
commands: Some(self),
finally: None,
}
}
}
impl<'w, 's, S: 'static, R: 'static> PromiseCommandsExtension<'w, 's, Promise<S, R>> for Commands<'w, 's> {
fn promise<'a>(&'a mut self, arg: Promise<S, R>) -> PromiseCommands<'w, 's, 'a, Promise<S, R>> {
PromiseCommands {
data: Some(arg),
commands: Some(self),
finally: Some(|commands, promise| commands.add(promise)),
}
}
}
pub struct PromiseChain<'w, 's, 'a, S: 'static, R: 'static> {
commands: Option<&'a mut Commands<'w, 's>>,
promise: Option<Promise<S, R>>,
}
impl<'w, 's, 'a, S: 'static, R: 'static> Drop for PromiseChain<'w, 's, 'a, S, R> {
fn drop(&mut self) {
if let Some(commands) = mem::take(&mut self.commands) {
if let Some(promise) = mem::take(&mut self.promise) {
commands.add(|world: &mut World| promise_register(world, promise))
}
}
}
}
pub struct PromiseState<S> {
pub value: S,
}
impl<S: 'static> PromiseState<S> {
pub fn new(value: S) -> PromiseState<S> {
PromiseState { value }
}
pub fn asyn(self) -> AsynOps<S> {
AsynOps(self.value)
}
pub fn resolve<R>(self, result: R) -> PromiseResult<S, R> {
PromiseResult::Resolve(self.value, result)
}
pub fn pass(self) -> PromiseResult<S, ()> {
PromiseResult::Resolve(self.value, ())
}
pub fn map<S2: 'static, F: FnOnce(S) -> S2>(self, map: F) -> PromiseState<S2> {
PromiseState { value: map(self.value) }
}
pub fn with<S2: 'static>(self, value: S2) -> PromiseState<S2> {
PromiseState { value }
}
pub fn start<S2: 'static, R2: 'static>(self, func: Asyn![S => S2, R2]) -> Promise<S2, R2> {
Promise::new(self.value, func)
}
pub fn repeat<R2: 'static>(self, func: Asyn![S => S, Repeat<R2>]) -> Promise<S, R2> {
Promise::repeat(self.value, func)
}
pub fn any<A: AnyPromises>(self, any: A) -> Promise<S, A::Result> {
any.register().with(self.value)
}
pub fn all<A: AllPromises>(self, all: A) -> Promise<S, A::Result> {
all.register().with(self.value)
}
}
impl<S: std::fmt::Display> std::fmt::Display for PromiseState<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.value.fmt(f)
}
}
impl<S: 'static> std::ops::Deref for PromiseState<S> {
type Target = S;
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<S: 'static> std::ops::DerefMut for PromiseState<S> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.value
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for PromiseState<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "PromiseState({:?})", self.value)
}
}
pub struct MutPtr<T>(*mut T);
unsafe impl<T> Send for MutPtr<T> {}
unsafe impl<T> Sync for MutPtr<T> {}
impl<T> Clone for MutPtr<T> {
fn clone(&self) -> Self {
MutPtr(self.0)
}
}
impl<T> MutPtr<T> {
pub fn new(value: T) -> MutPtr<T> {
let b = Box::new(value);
MutPtr(Box::leak(b) as *mut T)
}
pub fn get(&mut self) -> T {
if self.0.is_null() {
panic!("Ups.")
}
let b = unsafe { Box::from_raw(self.0) };
self.0 = std::ptr::null_mut();
*b
}
pub fn get_ref(&self) -> &T {
if self.0.is_null() {
panic!("Ups.");
}
unsafe { self.0.as_ref().unwrap() }
}
pub fn get_mut(&mut self) -> &mut T {
if self.0.is_null() {
panic!("Ups.");
}
unsafe { self.0.as_mut().unwrap() }
}
pub fn is_valid(&self) -> bool {
!self.0.is_null()
}
}
pub trait AnyPromises {
type Result: 'static;
fn register(self) -> Promise<(), Self::Result>;
}
pub trait AllPromises {
type Result: 'static;
fn register(self) -> Promise<(), Self::Result>;
}
impl<S: 'static, R: 'static> AnyPromises for Vec<Promise<S, R>> {
type Result = (S, R);
fn register(self) -> Promise<(), Self::Result> {
let ids: Vec<PromiseId> = self.iter().map(|p| p.id).collect();
let discard_ids = ids.clone();
Promise::register(
move |world, any_id| {
let mut idx = 0usize;
for promise in self {
let ids = ids.clone();
promise_register(
world,
promise.map(move |s| (s, any_id, idx, ids)).then(asyn!(|s, r| {
let (state, any_id, idx, ids) = s.value;
Promise::<(), ()>::register(
move |world, _id| {
for (i, id) in ids.iter().enumerate() {
if i != idx {
promise_discard::<S, R>(world, *id);
}
}
promise_resolve::<(), (S, R)>(world, any_id, (), (state, r))
},
|_, _| {},
)
})),
);
idx += 1;
}
},
move |world, _| {
for id in discard_ids {
promise_discard::<S, R>(world, id);
}
},
)
}
}
impl<S: 'static, R: 'static> AllPromises for Vec<Promise<S, R>> {
type Result = Vec<(S, R)>;
fn register(self) -> Promise<(), Self::Result> {
let ids: Vec<PromiseId> = self.iter().map(|p| p.id).collect();
let size = ids.len();
Promise::register(
move |world, any_id| {
let value: Vec<Option<(S, R)>> = (0..size).map(|_| None).collect();
let value = MutPtr::new(value);
let mut idx = 0usize;
for promise in self {
let value = value.clone();
promise_register(
world,
promise.map(move |s| (s, any_id, idx, value)).then(asyn!(|s, r| {
let (s, any_id, idx, mut value) = s.value;
Promise::<(), ()>::register(
move |world, _id| {
value.get_mut()[idx] = Some((s, r));
if value.get_ref().iter().all(|v| v.is_some()) {
let value = value.get().into_iter().map(|v| v.unwrap()).collect();
promise_resolve::<(), Vec<(S, R)>>(world, any_id, (), value)
}
},
|_, _| {},
)
})),
);
idx += 1;
}
},
move |world, _| {
for id in ids {
promise_discard::<S, R>(world, id);
}
},
)
}
}
impl_any_promises! { 8 }
impl_all_promises! { 8 }
#[macro_export]
macro_rules! Asyn {
($is:ty => $os:ty, $or:ty) => {
$crate::Asyn<($crate::PromiseState<$is>, ()), impl 'static + Into<$crate::PromiseResult<$os, $or>>, impl $crate::PromiseParams>
};
($is:ty, $ir:ty => $os:ty, $or:ty) => {
$crate::Asyn<($crate::PromiseState<$is>, $ir), impl 'static + Into<$crate::PromiseResult<$os, $or>>, impl $crate::PromiseParams>
}
}
pub struct Promises<S: 'static, R: 'static>(Vec<Promise<S, R>>);
impl<S: 'static, R: 'static> Promises<S, R> {
pub fn any(self) -> Promise<(), (S, R)> {
PromiseState::new(()).any(self.0)
}
pub fn all(self) -> Promise<(), Vec<(S, R)>> {
PromiseState::new(()).all(self.0)
}
}
pub trait PromisesExtension<S: 'static, R: 'static> {
fn promise(self) -> Promises<S, R>;
}
impl<S: 'static, R: 'static, I: Iterator<Item = Promise<S, R>>> PromisesExtension<S, R> for I {
fn promise(self) -> Promises<S, R> {
Promises(self.collect())
}
}
pub trait PromiseLikeBase<S: 'static, R: 'static>
where
Self: Sized,
{
type Promise<S2: 'static, R2: 'static>;
fn then<S2: 'static, R2: 'static>(self, func: Asyn![S, R => S2, R2]) -> Self::Promise<S2, R2>;
fn map_result<R2: 'static, F: 'static + FnOnce(R) -> R2>(self, map: F) -> Self::Promise<S, R2>;
fn with_result<R2: 'static>(self, value: R2) -> Self::Promise<S, R2>;
fn map<S2: 'static, F: 'static + FnOnce(S) -> S2>(self, map: F) -> Self::Promise<S2, R>;
fn with<S2: 'static>(self, state: S2) -> Self::Promise<S2, R>;
}
pub trait PromiseLike<S: 'static>
where
Self: Sized + PromiseLikeBase<S, ()>,
{
fn then_repeat<R2: 'static>(self, func: Asyn![S => S, Repeat<R2>]) -> Self::Promise<S, R2>;
fn all<A: 'static + AllPromises>(self, all: A) -> Self::Promise<S, A::Result>;
fn any<A: 'static + AnyPromises>(self, any: A) -> Self::Promise<S, A::Result>;
}