#[cfg(not(feature = "ethexe"))]
use crate::critical;
use crate::{MessageId, prelude::Box};
use core::{
future::Future,
pin::Pin,
task::{Context, Waker},
};
use futures::FutureExt;
use hashbrown::HashMap;
pub(crate) type FuturesMap = HashMap<MessageId, Task>;
type PinnedFuture = Pin<Box<dyn Future<Output = ()> + 'static>>;
pub struct Task {
waker: Waker,
future: PinnedFuture,
lock_exceeded: bool,
}
impl Task {
fn new<F>(future: F) -> Self
where
F: Future<Output = ()> + 'static,
{
Self {
waker: waker_fn::waker_fn(|| {}),
future: future.boxed_local(),
lock_exceeded: false,
}
}
pub(crate) fn set_lock_exceeded(&mut self) {
self.lock_exceeded = true;
}
}
pub fn message_loop<F>(future: F)
where
F: Future<Output = ()> + 'static,
{
let msg_id = crate::msg::id();
let task = super::futures().entry(msg_id).or_insert_with(|| {
#[cfg(not(feature = "ethexe"))]
{
let system_reserve_amount = crate::Config::system_reserve();
crate::exec::system_reserve_gas(system_reserve_amount)
.expect("Failed to reserve gas for system signal");
}
Task::new(future)
});
if task.lock_exceeded {
panic!(
"Message 0x{} has exceeded lock ownership time",
hex::encode(msg_id)
);
}
let mut cx = Context::from_waker(&task.waker);
if Pin::new(&mut task.future).poll(&mut cx).is_ready() {
super::futures().remove(&msg_id);
super::locks().remove_message_entry(msg_id);
#[cfg(not(feature = "ethexe"))]
let _ = critical::take_hook();
} else {
super::locks().wait(msg_id);
}
}