use rsynko_session::*;
use std::cell::Cell;
use std::rc::Rc;
use std::time::Duration;
#[derive(Debug, Default)]
pub struct ReferenceSession {
requests: Vec<ReferenceRequest>,
clock: Duration,
}
#[derive(Debug)]
struct ReferenceRequest {
id: usize,
wanted: Wanted,
says: usize,
beginnable: bool,
attended: bool,
told: Vec<Telling>,
abandonments: Rc<Cell<usize>>,
}
#[derive(Debug)]
pub struct ReferenceRun {
work: usize,
said: Vec<usize>,
held: bool,
abandoning: bool,
abandonments: Rc<Cell<usize>>,
}
impl ReferenceSession {
fn request(&self, id: usize) -> &ReferenceRequest {
self.requests.iter().find(|request| request.id == id).expect("an authored request")
}
fn request_mut(&mut self, id: usize) -> &mut ReferenceRequest {
self.requests.iter_mut().find(|request| request.id == id).expect("an authored request")
}
fn author(&mut self, says: usize, beginnable: bool) -> usize {
let id = self.requests.len();
self.requests.push(ReferenceRequest {
id,
wanted: Wanted::Running,
says,
beginnable,
attended: false,
told: Vec::new(),
abandonments: Rc::new(Cell::new(0)),
});
id
}
}
impl SessionSorts for ReferenceSession {
type Id = usize;
type Run = ReferenceRun;
type Report = usize;
type Ending = ();
type Refusal = String;
}
impl UndertakingAlg for ReferenceSession {
fn unattended(&self) -> Vec<usize> {
self.requests.iter().filter(|request| !request.attended).map(|request| request.id).collect()
}
fn begin(&self, id: &usize) -> Result<ReferenceRun, String> {
let request = self.request(*id);
if !request.beginnable {
return Err("the work refuses to begin".to_owned());
}
Ok(ReferenceRun {
work: request.says,
said: Vec::new(),
held: false,
abandoning: false,
abandonments: Rc::clone(&request.abandonments),
})
}
}
impl RunReadAlg for ReferenceSession {
fn run_is_over(&self, run: &ReferenceRun) -> bool {
run.work == 0
}
fn read_run(&self, run: &mut ReferenceRun) -> Vec<usize> {
if run.abandoning {
run.work = 0;
run.said.clear();
return Vec::new();
}
if run.held {
return Vec::new();
}
let said = std::mem::take(&mut run.said);
if run.work > 0 {
run.work -= 1;
run.said.push(run.work);
}
said
}
fn end_run(&self, _run: ReferenceRun) -> Result<(), String> {
Ok(())
}
}
impl RunHoldAlg for ReferenceSession {
fn holding_is_possible(&self) -> bool {
true
}
fn hold_run(&self, run: &mut ReferenceRun, held: bool) {
run.held = held;
}
fn abandon_run(&self, run: &mut ReferenceRun) {
run.abandoning = true;
run.abandonments.set(run.abandonments.get() + 1);
}
}
impl AttentionAlg for ReferenceSession {
fn begun(&mut self, id: &usize, _holdable: bool) {
let request = self.request_mut(*id);
request.attended = true;
request.told.push(Telling::Begun);
}
fn heard(&mut self, id: &usize, _report: usize) {
self.request_mut(*id).told.push(Telling::Heard);
}
fn ran_for(&mut self, id: &usize, elapsed: Duration) {
self.request_mut(*id).told.push(Telling::RanFor(elapsed));
}
fn ended(&mut self, id: &usize, ending: Result<(), String>) {
let request = self.request_mut(*id);
request.attended = true;
request.told.push(match ending {
Ok(()) => Telling::Ended,
Err(_) => Telling::Refused,
});
}
fn wanted(&self, id: &usize) -> Wanted {
self.request(*id).wanted
}
}
impl ClockAlg for ReferenceSession {
type Moment = Duration;
fn now(&self) -> Duration {
self.clock
}
fn since(&self, moment: &Duration) -> Duration {
self.clock.saturating_sub(*moment)
}
}
impl SessionLawFixture for ReferenceSession {
fn law_wanting(&mut self, says: usize) -> usize {
self.author(says, true)
}
fn law_unbeginnable(&mut self) -> usize {
self.author(0, false)
}
fn law_wants(&mut self, id: &usize, wanted: Wanted) {
self.request_mut(*id).wanted = wanted;
}
fn law_passes(&mut self, elapsed: Duration) {
self.clock = self.clock.saturating_add(elapsed);
}
fn law_told(&self, id: &usize) -> Vec<Telling> {
self.request(*id).told.clone()
}
fn law_abandonments(&self, id: &usize) -> usize {
self.request(*id).abandonments.get()
}
}