use crate::runtime::types::RoutinePendingState;
use std::{
cell::{Cell, RefCell},
future::Future,
pin::Pin,
rc::Rc,
task::{Context, Poll},
};
pub mod entry;
pub mod guest;
pub mod host;
pub mod instance;
pub mod model;
pub mod types;
thread_local! {
static SDK_WAKE_DEPTH: Cell<u32> = const { Cell::new(0) };
static CURRENT_INTERCEPTED_FUTURE: RefCell<Option<InterceptedFutureStatus>> =
const { RefCell::new(None) };
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum InterceptedFuturePollKind {
Construction,
Routine,
}
#[derive(Clone, Copy)]
enum InterceptedFutureState {
Interceptor {
has_activation: bool,
handler_result_ready: bool,
},
Handler,
}
impl InterceptedFutureState {
fn pending_state(self) -> RoutinePendingState {
match self {
Self::Interceptor {
has_activation: false,
..
} => RoutinePendingState::Interceptor,
Self::Interceptor {
has_activation: true,
..
} => RoutinePendingState::InterceptorWithActivation,
Self::Handler => RoutinePendingState::Handler,
}
}
}
#[derive(Clone, Copy)]
struct InterceptedFutureStatusInner {
state: InterceptedFutureState,
poll_kind: InterceptedFuturePollKind,
}
#[derive(Clone)]
pub(crate) struct InterceptedFutureStatus(Rc<Cell<InterceptedFutureStatusInner>>);
impl InterceptedFutureStatus {
pub(crate) fn new() -> Self {
Self(Rc::new(Cell::new(InterceptedFutureStatusInner {
state: InterceptedFutureState::Interceptor {
has_activation: false,
handler_result_ready: false,
},
poll_kind: InterceptedFuturePollKind::Routine,
})))
}
pub(crate) fn reset_for_poll(&self) {
let mut status = self.0.get();
if let InterceptedFutureState::Interceptor {
handler_result_ready,
..
} = status.state
{
status.state = InterceptedFutureState::Interceptor {
has_activation: false,
handler_result_ready,
};
self.0.set(status);
}
}
pub(crate) fn enter_handler(&self) -> bool {
let mut status = self.0.get();
let handler_result_ready = match status.state {
InterceptedFutureState::Interceptor {
handler_result_ready,
..
} => handler_result_ready,
InterceptedFutureState::Handler => false,
};
let should_poll =
handler_result_ready || status.poll_kind == InterceptedFuturePollKind::Routine;
status.state = InterceptedFutureState::Handler;
self.0.set(status);
should_poll
}
pub(crate) fn state(&self) -> RoutinePendingState {
self.0.get().state.pending_state()
}
pub(crate) fn mark_handler_result_ready(&self) {
let mut status = self.0.get();
if let InterceptedFutureState::Interceptor { has_activation, .. } = status.state {
status.state = InterceptedFutureState::Interceptor {
has_activation,
handler_result_ready: true,
};
self.0.set(status);
}
}
#[cfg(test)]
pub(crate) fn poll_kind(&self) -> InterceptedFuturePollKind {
self.0.get().poll_kind
}
fn mark_activation(&self) {
let mut status = self.0.get();
if let InterceptedFutureState::Interceptor {
handler_result_ready,
..
} = status.state
{
status.state = InterceptedFutureState::Interceptor {
has_activation: true,
handler_result_ready,
};
self.0.set(status);
}
}
}
pub(crate) struct InterceptedFuturePollGuard {
status: InterceptedFutureStatus,
previous_status: Option<InterceptedFutureStatus>,
previous_poll_kind: InterceptedFuturePollKind,
}
impl InterceptedFuturePollGuard {
pub(crate) fn new(
status: InterceptedFutureStatus,
poll_kind: InterceptedFuturePollKind,
) -> Self {
let mut inner_status = status.0.get();
let previous_poll_kind = inner_status.poll_kind;
inner_status.poll_kind = poll_kind;
status.0.set(inner_status);
let previous_status =
CURRENT_INTERCEPTED_FUTURE.with(|current| current.replace(Some(status.clone())));
Self {
status,
previous_status,
previous_poll_kind,
}
}
}
impl Drop for InterceptedFuturePollGuard {
fn drop(&mut self) {
let mut status = self.status.0.get();
status.poll_kind = self.previous_poll_kind;
self.status.0.set(status);
let previous_status = self.previous_status.take();
CURRENT_INTERCEPTED_FUTURE.with(|current| *current.borrow_mut() = previous_status);
}
}
pub(crate) fn mark_intercepted_future_activation() {
CURRENT_INTERCEPTED_FUTURE.with(|current| {
if let Some(status) = current.borrow().as_ref() {
status.mark_activation();
}
});
}
pub(crate) fn mark_intercepted_handler_ready() {
CURRENT_INTERCEPTED_FUTURE.with(|current| {
if let Some(status) = current.borrow().as_ref() {
status.mark_handler_result_ready();
}
});
}
#[doc(hidden)]
pub struct SdkWakeGuard {
_priv: (),
}
impl SdkWakeGuard {
#[doc(hidden)]
pub fn new() -> Self {
SDK_WAKE_DEPTH.with(|c| c.set(c.get() + 1));
Self { _priv: () }
}
}
impl Drop for SdkWakeGuard {
fn drop(&mut self) {
SDK_WAKE_DEPTH.with(|c| c.set(c.get() - 1));
}
}
#[doc(hidden)]
pub fn is_sdk_wake() -> bool {
SDK_WAKE_DEPTH.with(|c| c.get() > 0)
}
pub(crate) struct SdkGuardedFuture<F>(pub(crate) F);
impl<F: Future + Unpin> Future for SdkGuardedFuture<F> {
type Output = F::Output;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let _guard = SdkWakeGuard::new();
Pin::new(&mut self.0).poll(cx)
}
}