use odem_rs::{
core::ops::waker,
prelude::*,
tracing::{Level, info},
};
use std::{cell::Cell, pin::pin, task::Waker};
use Message::*;
enum Message<T> {
Primed(Option<T>),
Linked(Waker),
}
struct Uplink<T>(Cell<Message<T>>);
impl<T> Uplink<T> {
pub fn new() -> Self {
Self(Cell::new(Primed(None)))
}
pub fn interrupt(&self, value: T) -> Result<(), T> {
match self.0.replace(Primed(Some(value))) {
Primed(None) => Ok(()),
Primed(Some(old_val)) => Err(old_val), Linked(waker) => {
waker.wake();
Ok(())
}
}
}
pub async fn interruption(&self) -> T {
loop {
if let Primed(Some(v)) = self.0.replace(Primed(None)) {
break v;
}
self.0.set(Linked(waker().await));
sleep().await;
}
}
}
struct Sleeper {
pub link: Uplink<i32>,
}
impl Behavior for Sleeper {
type Output = ();
async fn actions(&self, _: &Sim<()>) -> Self::Output {
info!("Order: {}", self.link.interruption().await);
}
}
async fn operator(sim: &Sim) {
let smith = pin!(Agent::new(Sleeper {
link: Uplink::new()
}));
let puck = sim.activate(smith);
sim.advance(1.0).await;
puck.subject().link.interrupt(66).expect("awaiting orders");
sim.advance(1.0).await;
}
fn main() {
tracing_subscriber::fmt()
.with_max_level(Level::INFO)
.with_target(false)
.with_timer(model_time!("[{time}]"))
.init();
Simulator::default().run(operator).unwrap();
}