use std::cell::RefCell;
use std::rc::Rc;
use std::time::Duration;
use runite::channel::mpsc;
use runite::time::sleep;
const FRAMES: u32 = 30;
const FRAME_TIME: Duration = Duration::from_millis(20);
const WIDTH: usize = 24;
#[derive(Default)]
struct Scene {
ball: usize,
direction: i32,
banner: &'static str,
pulses: u32,
}
fn render(frame: u32, scene: &Scene) {
let mut lane = vec![b'.'; WIDTH];
lane[scene.ball] = b'o';
println!(
"frame {frame:>2} |{}| {:<12} pulses={}",
String::from_utf8_lossy(&lane),
scene.banner,
scene.pulses,
);
}
fn main() {
let scene = Rc::new(RefCell::new(Scene {
direction: 1,
banner: "loading...",
..Scene::default()
}));
let (raf_tx, mut raf_rx) = mpsc::channel::<u32>(1);
let animation = {
let scene = Rc::clone(&scene);
runite::spawn(async move {
while let Some(_frame) = raf_rx.recv().await {
let mut scene = scene.borrow_mut();
let next = scene.ball as i32 + scene.direction;
if next < 0 || next >= WIDTH as i32 {
scene.direction = -scene.direction;
}
scene.ball = (scene.ball as i32 + scene.direction) as usize;
}
})
};
{
let scene = Rc::clone(&scene);
runite::spawn(async move {
for _ in 0..5 {
sleep(Duration::from_millis(90)).await;
scene.borrow_mut().pulses += 1;
}
});
}
{
let scene = Rc::clone(&scene);
runite::spawn(async move {
sleep(Duration::from_millis(250)).await; scene.borrow_mut().banner = "data loaded";
});
}
for frame in 0..FRAMES {
let _ = raf_tx.try_send(frame);
runite::run_until_stalled();
render(frame, &scene.borrow());
std::thread::sleep(FRAME_TIME); }
drop(raf_tx);
runite::run_until_stalled();
drop(animation);
let scene = scene.borrow();
println!("---");
println!(
"{} frames; banner={:?}; {} timer pulses fired while the host owned the thread",
FRAMES, scene.banner, scene.pulses
);
assert_eq!(
scene.banner, "data loaded",
"the async load should have landed"
);
assert!(
scene.pulses >= 4,
"timer task should have pulsed during the run"
);
}