use sim_kernel::Ref;
#[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,
})
}
}