use alloc::alloc::{dealloc, Layout};
use alloc::boxed::Box;
use core::default::Default;
use core::ptr;
#[cfg(nightly)]
use core::marker::{Send, Sync};
pub trait App: Default + 'static {
type BlackBox;
type Message: 'static;
#[doc(hidden)]
#[inline]
fn __render(&mut self, _addr: A<Self>) {}
#[doc(hidden)]
#[inline]
fn __hydrate(&mut self, _addr: A<Self>) {}
#[doc(hidden)]
#[inline]
fn __dispatch(&mut self, _msg: Self::Message, _addr: A<Self>) {}
}
pub struct Addr<A: App>(pub(crate) Context<A>);
#[cfg(not(debug_assertions))]
impl<A: App> Drop for Addr<A> {
fn drop(&mut self) {
panic!("drop app")
}
}
#[macro_export]
macro_rules! run {
($ty:ty) => {
unsafe { $crate::A::run(<$ty as core::default::Default>::default()) }
};
}
pub struct A<I: App>(&'static Addr<I>);
pub use self::A as DeLorean;
use crate::{stc_to_ptr, Context};
#[cfg(nightly)]
impl<I: App> !Send for A<I> {}
#[cfg(nightly)]
impl<I: App> !Sync for A<I> {}
impl<I: App> Clone for A<I> {
#[inline(always)]
fn clone(&self) -> Self {
A(self.0)
}
}
impl<I: App> Copy for A<I> {}
impl<I: App> A<I> {
pub unsafe fn run(a: I) -> A<I> {
let addr = A(Addr::new(a));
addr.hydrate();
addr
}
#[cfg(debug_assertions)]
pub unsafe fn dealloc(self) {
self.0.dealloc();
}
pub fn send(self, msg: I::Message) {
self.ctx().push(msg);
self.update();
}
#[inline]
unsafe fn hydrate(self) {
let ctx = self.ctx();
debug_assert!(!ctx.is_ready());
ctx.app().__hydrate(self);
ctx.ready(true);
}
#[inline]
fn update(self) {
let ctx = self.ctx();
if ctx.is_ready() {
ctx.ready(false);
unsafe {
while let Some(msg) = ctx.pop() {
ctx.app().__dispatch(msg, self);
while let Some(msg) = ctx.pop() {
ctx.app().__dispatch(msg, self);
}
ctx.app().__render(self);
}
}
ctx.ready(true);
}
}
#[inline]
fn ctx(&self) -> &Context<I> {
&(self.0).0
}
}
impl<I: App> Addr<I> {
#[inline]
fn new(a: I) -> &'static Addr<I> {
Box::leak(Box::new(Addr(Context::new(a))))
}
#[cfg(debug_assertions)]
pub(crate) unsafe fn dealloc(&'static self) {
let p = stc_to_ptr(self);
ptr::drop_in_place(p);
dealloc(p as *mut u8, Layout::new::<Addr<I>>());
}
}