use sim_kernel::Ref;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CoroutineFrameStep<T = Ref> {
Produced(T),
Consumed(T),
Complete,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum CoroutineFrameTurn {
Produce,
Consume,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CoroutineFrame<T = Ref> {
produced: Vec<T>,
consumed: Vec<T>,
produced_index: usize,
consumed_index: usize,
turn: CoroutineFrameTurn,
}
impl<T> CoroutineFrame<T> {
pub fn new(produced: Vec<T>, consumed: Vec<T>) -> Self {
Self {
produced,
consumed,
produced_index: 0,
consumed_index: 0,
turn: CoroutineFrameTurn::Produce,
}
}
pub fn resume(&mut self) -> CoroutineFrameStep<T>
where
T: Clone,
{
loop {
match self.turn {
CoroutineFrameTurn::Produce => {
self.turn = CoroutineFrameTurn::Consume;
if let Some(value) = self.produced.get(self.produced_index).cloned() {
self.produced_index += 1;
return CoroutineFrameStep::Produced(value);
}
}
CoroutineFrameTurn::Consume => {
self.turn = CoroutineFrameTurn::Produce;
if let Some(value) = self.consumed.get(self.consumed_index).cloned() {
self.consumed_index += 1;
return CoroutineFrameStep::Consumed(value);
}
}
}
if self.is_complete() {
return CoroutineFrameStep::Complete;
}
}
}
pub fn is_complete(&self) -> bool {
self.produced_index >= self.produced.len() && self.consumed_index >= self.consumed.len()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CoroutineLane {
First,
Second,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CoroutineStep {
Yielded {
lane: CoroutineLane,
value: Ref,
},
Exhausted,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Coroutine {
first: Vec<Ref>,
second: Vec<Ref>,
first_index: usize,
second_index: usize,
next_lane: CoroutineLane,
}
impl Coroutine {
pub fn alternating(first: Vec<Ref>, second: Vec<Ref>) -> Self {
Self {
first,
second,
first_index: 0,
second_index: 0,
next_lane: CoroutineLane::First,
}
}
pub fn resume(&mut self) -> CoroutineStep {
let step = match self.next_lane {
CoroutineLane::First => self.resume_first().or_else(|| self.resume_second()),
CoroutineLane::Second => self.resume_second().or_else(|| self.resume_first()),
};
step.unwrap_or(CoroutineStep::Exhausted)
}
fn resume_first(&mut self) -> Option<CoroutineStep> {
let value = self.first.get(self.first_index).cloned()?;
self.first_index += 1;
self.next_lane = CoroutineLane::Second;
Some(CoroutineStep::Yielded {
lane: CoroutineLane::First,
value,
})
}
fn resume_second(&mut self) -> Option<CoroutineStep> {
let value = self.second.get(self.second_index).cloned()?;
self.second_index += 1;
self.next_lane = CoroutineLane::First;
Some(CoroutineStep::Yielded {
lane: CoroutineLane::Second,
value,
})
}
}