use std::cell::RefCell;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll};
use logicaffeine_runtime::{ChanId, RtPayload, SelectArm, Task, TaskId};
pub enum BlockingRequest<'a> {
NewChan(Option<usize>),
Send(ChanId, RtPayload),
TrySend(ChanId, RtPayload),
Recv(ChanId),
TryRecv(ChanId),
Select(Vec<SelectArm>),
Sleep(u64),
Spawn(Box<dyn Task<'a> + 'a>),
Await(TaskId),
Abort(TaskId),
Close(ChanId),
}
pub enum ResumeValue {
None,
Payload(RtPayload),
Chan(ChanId),
Task(TaskId),
Select { arm: usize, payload: RtPayload },
}
impl ResumeValue {
pub fn into_payload(self) -> RtPayload {
match self {
ResumeValue::Payload(p) => p,
_ => RtPayload::Nothing,
}
}
pub fn into_chan(self) -> Option<ChanId> {
match self {
ResumeValue::Chan(c) => Some(c),
_ => None,
}
}
pub fn into_task(self) -> Option<TaskId> {
match self {
ResumeValue::Task(t) => Some(t),
_ => None,
}
}
pub fn into_select(self) -> Option<(usize, RtPayload)> {
match self {
ResumeValue::Select { arm, payload } => Some((arm, payload)),
_ => None,
}
}
}
pub struct YieldState<'a> {
pub request: Option<BlockingRequest<'a>>,
pub resume: ResumeValue,
}
impl<'a> YieldState<'a> {
pub fn new() -> Self {
YieldState { request: None, resume: ResumeValue::None }
}
}
impl<'a> Default for YieldState<'a> {
fn default() -> Self {
YieldState::new()
}
}
pub type Yield<'a> = Rc<RefCell<YieldState<'a>>>;
pub struct YieldFuture<'a> {
yielded: bool,
ys: Yield<'a>,
}
impl<'a> YieldFuture<'a> {
pub fn new(ys: Yield<'a>) -> Self {
YieldFuture { yielded: false, ys }
}
}
impl<'a> Future for YieldFuture<'a> {
type Output = ResumeValue;
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<ResumeValue> {
if !self.yielded {
self.yielded = true;
Poll::Pending
} else {
let mut st = self.ys.borrow_mut();
Poll::Ready(std::mem::replace(&mut st.resume, ResumeValue::None))
}
}
}