use genawaiter::rc::{Co, Gen};
use std::cell::RefCell;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
#[derive(Debug)]
enum ValueRepr {
Int(i64),
Thunk((i64, i64)),
}
#[derive(Clone, Debug)]
struct Value(Rc<RefCell<ValueRepr>>);
impl Value {
fn force(&self) {
let mut inner = self.0.borrow_mut();
match *inner {
ValueRepr::Int(_) => return,
ValueRepr::Thunk((a, b)) => {
*inner = ValueRepr::Int(a + b);
}
}
}
fn is_forced(&self) -> bool {
matches!(*self.0.borrow(), ValueRepr::Int(_))
}
fn int(&self) -> i64 {
match *self.0.borrow() {
ValueRepr::Int(i) => i,
ValueRepr::Thunk(_) => panic!("unforced thunk!"),
}
}
}
impl From<i64> for Value {
fn from(value: i64) -> Self {
Value(Rc::new(RefCell::new(ValueRepr::Int(value))))
}
}
impl From<(i64, i64)> for Value {
fn from(value: (i64, i64)) -> Self {
Value(Rc::new(RefCell::new(ValueRepr::Thunk(value))))
}
}
async fn list_maker(values: Vec<Value>, co: Co<Value>) -> Vec<i64> {
let mut output: Vec<i64> = vec![];
for value in values {
if !value.is_forced() {
co.yield_(value.clone()).await;
}
output.push(value.int());
}
output
}
async fn list_reverser(values: Vec<Value>, co: Co<Value>) -> Vec<i64> {
let mut output = list_maker(values, co).await;
output.reverse();
output
}
struct Frame {
gen: Gen<Value, (), Pin<Box<dyn Future<Output = Vec<i64>>>>>,
}
fn pin_future(
f: impl Future<Output = Vec<i64>> + 'static,
) -> Pin<Box<dyn Future<Output = Vec<i64>>>> {
Box::pin(f)
}
fn main() {
let mut frames: Vec<Frame> = vec![];
let values: Vec<Value> = vec![
42.into(),
(12, 54).into(),
4.into(),
(40, 2).into(),
2.into(),
];
let second = values.clone();
frames.push(Frame {
gen: Gen::new(|co| pin_future(list_maker(values, co))),
});
frames.push(Frame {
gen: Gen::new(|co| pin_future(list_reverser(second, co))),
});
for (idx, mut frame) in frames.into_iter().enumerate() {
loop {
match frame.gen.resume() {
genawaiter::GeneratorState::Yielded(val) => {
println!("yielded {:?} in frame {}", val, idx);
val.force();
}
genawaiter::GeneratorState::Complete(list) => {
println!("result {}: {:?}", idx, list);
break;
}
}
}
}
}