#![feature(coroutines, coroutine_trait)]
use desim::prelude::*;
use desim::resources::SimpleResource;
use rand::rngs::SmallRng as Rng;
use rand::{RngCore as RngT, SeedableRng};
#[derive(Copy, Clone, Debug)]
enum PCBStage {
Init,
RequestPip,
RequestEt,
InWork,
SurfaceMountPlaced,
ThruHolePlaced,
ElectricalTestPerformed,
Done,
}
#[derive(Clone, Debug)]
struct PCBState {
pcb_id: usize,
effect: Effect,
log: bool,
stage: PCBStage,
}
impl SimState for PCBState {
fn get_effect(&self) -> Effect {
self.effect
}
fn set_effect(&mut self, e: Effect) {
self.effect = e;
}
fn should_log(&self) -> bool {
self.log
}
}
#[derive(Copy, Clone)]
struct Resources {
pip: ResourceId, et: ResourceId, }
struct PCBStateCtx {
rng: Rng,
res: Resources,
state: PCBState,
}
impl PCBStateCtx {
fn new(r: Resources) -> PCBStateCtx {
PCBStateCtx {
rng: Rng::from_entropy(),
res: r,
state: PCBState {
pcb_id: 0,
effect: Effect::Wait,
log: true,
stage: PCBStage::Init,
},
}
}
fn set_new_id(&mut self, pcb_id: usize) {
self.state.pcb_id = pcb_id;
}
#[inline]
fn res(&mut self, r_id: ResourceId, should_log: bool, stage: PCBStage, need: bool) -> PCBState {
let mut r_state = self.state.clone();
r_state.stage = stage;
r_state.log = should_log;
if need {
r_state.effect = Effect::Request(r_id);
} else {
r_state.effect = Effect::Release(r_id);
self.state.stage = stage;
}
r_state
}
#[inline]
fn work(&self, should_log: bool, service_time: f64, stage: PCBStage) -> PCBState {
let mut r_state = self.state.clone();
r_state.stage = stage;
r_state.log = should_log;
r_state.effect = Effect::TimeOut(service_time);
r_state
}
fn need_pip(&mut self) -> PCBState {
self.res(self.res.pip, true, PCBStage::RequestPip, true)
}
fn need_et(&mut self) -> PCBState {
self.res(self.res.et, true, PCBStage::RequestEt, true)
}
fn free_pip(&mut self, stage_end: PCBStage) -> PCBState {
self.res(self.res.pip, true, stage_end, false)
}
fn free_et(&mut self, stage_end: PCBStage) -> PCBState {
self.res(self.res.et, true, stage_end, false)
}
fn pip_work(&mut self) -> PCBState {
let st = match self.state.stage {
PCBStage::Init => (15 + self.rng.next_u32() % 20) as f64,
PCBStage::SurfaceMountPlaced => (30 + self.rng.next_u32() % 20) as f64,
_ => 0.0_f64,
};
self.work(true, st, PCBStage::InWork)
}
fn et_work(&mut self) -> PCBState {
let st = match self.state.stage {
PCBStage::ThruHolePlaced => (5 + self.rng.next_u32() % 5) as f64,
_ => 0.0_f64,
};
self.work(true, st, PCBStage::InWork)
}
fn mark(&mut self, stage: PCBStage) -> PCBState {
self.state.stage = PCBStage::Init;
let mut r_state = self.state.clone();
r_state.stage = stage;
r_state.log = true;
r_state.effect = Effect::Trace;
r_state
}
}
fn process_code(r: Resources) -> Box<Process<PCBState>> {
Box::new(move |_| {
let mut current_pcb_id = 0;
let mut ctx = PCBStateCtx::new(r);
loop {
yield ctx.need_pip();
yield ctx.pip_work();
yield ctx.free_pip(PCBStage::SurfaceMountPlaced);
yield ctx.need_pip();
yield ctx.pip_work();
yield ctx.free_pip(PCBStage::ThruHolePlaced);
yield ctx.need_et();
yield ctx.et_work();
yield ctx.free_et(PCBStage::ElectricalTestPerformed);
yield ctx.mark(PCBStage::Done);
current_pcb_id += 1;
ctx.set_new_id(current_pcb_id);
}
})
}
fn main() {
let mut s = Simulation::new();
let pip = s.create_resource(Box::new(SimpleResource::new(1)));
let et = s.create_resource(Box::new(SimpleResource::new(1)));
let res = Resources { pip, et };
for _ in 1..5 {
let p = s.create_process(process_code(res));
s.schedule_event(
0.0,
p,
PCBState {
pcb_id: 0,
effect: Effect::Event {
time: 0.,
process: p,
},
log: true,
stage: PCBStage::Init,
},
);
}
s = s.run(EndCondition::Time(500.0));
let evts = s.processed_events();
println!("time: (pid, pcb_id) action stage");
for (ev, state) in evts {
println!(
"{:?}: id({},{}) {:?}, {:?}",
ev.time(),
ev.process(),
state.pcb_id,
state.effect,
state.stage
);
}
}