use std::{
cell::UnsafeCell,
future::Future,
mem::MaybeUninit,
ptr,
sync::{Arc, atomic::AtomicU8},
};
use moirai_core::task::TaskResultSender;
use super::{lifecycle::AsyncLifecycle, phase::ASYNC_IDLE};
use crate::{
metrics::ExecutorMetrics,
registry::{OwnedStateLease, StateLease, TaskLifecycleToken},
schedule::WorkSubmit,
};
pub(crate) struct AsyncFutureState<S, F, L = OwnedStateLease>
where
F: Future,
L: StateLease,
{
pub(super) lifecycle: UnsafeCell<AsyncLifecycle<L>>,
pub(super) future: UnsafeCell<MaybeUninit<F>>,
pub(super) result_sender: UnsafeCell<Option<TaskResultSender<F::Output>>>,
pub(super) metrics: Arc<ExecutorMetrics>,
pub(super) state: AtomicU8,
pub(super) future_present: UnsafeCell<bool>,
pub(super) scheduler: S,
}
unsafe impl<S, F, L> Send for AsyncFutureState<S, F, L>
where
S: Send + Sync,
F: Future + Send,
F::Output: Send,
L: StateLease,
{
}
unsafe impl<S, F, L> Sync for AsyncFutureState<S, F, L>
where
S: Send + Sync,
F: Future + Send,
F::Output: Send,
L: StateLease,
{
}
impl<S, F, L> AsyncFutureState<S, F, L>
where
S: WorkSubmit,
F: Future + Send + 'static,
F::Output: Send + 'static,
L: StateLease,
{
pub(crate) fn new(
scheduler: S,
future: F,
lifecycle: TaskLifecycleToken<L>,
result_sender: TaskResultSender<F::Output>,
metrics: Arc<ExecutorMetrics>,
) -> Arc<Self> {
Arc::new(Self {
lifecycle: UnsafeCell::new(AsyncLifecycle::Registered(lifecycle)),
future: UnsafeCell::new(MaybeUninit::new(future)),
result_sender: UnsafeCell::new(Some(result_sender)),
metrics,
state: AtomicU8::new(ASYNC_IDLE),
future_present: UnsafeCell::new(true),
scheduler,
})
}
}
impl<S, F, L> Drop for AsyncFutureState<S, F, L>
where
F: Future,
L: StateLease,
{
fn drop(&mut self) {
if *self.future_present.get_mut() {
unsafe {
ptr::drop_in_place((*self.future.get()).as_mut_ptr());
}
}
}
}