Commit 55e21f18 authored by Ralf's avatar Ralf
Browse files

change environment around to no longer use select

parent 2c222eda
use std::time::Duration;
use chan::Receiver;
use std::thread;
use std::sync::mpsc::{channel, Sender, Receiver};
use util::timeout_chan;
use input::Event;
#[must_use]
......@@ -64,9 +64,24 @@ pub enum EventsResult {
Quit,
}
enum EventOrTimer {
Ev(Event),
Timeout(u32),
}
pub struct SensorStates {
door_locked: Option<bool>,
}
pub struct Environment {
events: Receiver<Event>,
door_locked: bool,
events: Receiver<EventOrTimer>,
sender: Sender<EventOrTimer>,
sensors: SensorStates,
cur_id: u32, // current ID used for timeout events
}
pub struct EventSender {
sender: Sender<EventOrTimer>,
}
macro_rules! handle_events {
......@@ -82,64 +97,79 @@ macro_rules! handle_events_timeout {
}
impl Environment {
pub fn handle_events(&mut self, mut handlers: Vec<EventHandler>) -> EventsResult {
for ev in self.events.clone() {
match self.handle_event(&mut handlers, ev) {
Some(result) => return result,
_ => {}
}
}
return EventsResult::ShuttingDown;
pub fn new() -> (Environment, EventSender) {
let (tx, rx) = channel();
( Environment { events: rx, sender: tx.clone(), sensors: SensorStates::new(), cur_id: 0 },
EventSender { sender: tx } )
}
pub fn handle_events(&mut self, handlers: Vec<EventHandler>) -> EventsResult {
self.cur_id = u32::wrapping_add(self.cur_id, 1); // make sure we ignore old timeouts
self.handle_events_cur_id(handlers)
}
pub fn handle_events_timeout(&mut self,
d: Duration,
mut handlers: Vec<EventHandler>)
-> EventsResult {
let timeout_chan = timeout_chan(d);
let events = self.events.clone();
loop {
chan_select! {
timeout_chan.recv() => return EventsResult::Timeout,
events.recv() -> ev => {
match ev {
None => return EventsResult::ShuttingDown,
Some(ev) => {
match self.handle_event(&mut handlers, ev) {
Some(result) => return result,
_ => {},
}
handlers: Vec<EventHandler>)
-> EventsResult
{
let sender = self.sender.clone();
// make sure we ignore old timeouts
let id = { self.cur_id = u32::wrapping_add(self.cur_id, 1); self.cur_id };
// spawn a thread that sends a timeout event with this id in [d] time
thread::spawn(move || {
thread::sleep(d);
// if sending fails, we just ignore that -- it means the timeout is not necessary any more
let _ = sender.send(EventOrTimer::Timeout(id));
});
// now we are ready to listen for events
self.handle_events_cur_id(handlers)
}
fn handle_events_cur_id(&mut self, mut handlers: Vec<EventHandler>) -> EventsResult
{
for ev in self.events.iter() {
match ev {
EventOrTimer::Timeout(id) => {
if id == self.cur_id {
return EventsResult::Timeout;
}
// old timeout event, ignore
},
EventOrTimer::Ev(ev) => {
// a regular event
self.sensors.record_state(&ev);
// forward to all handlers
for handler in handlers.iter_mut() {
match handler.run(ev) {
HandlerResult::Continue => {}
HandlerResult::QuitLoop => return EventsResult::Quit,
}
}
}
}
}
return EventsResult::ShuttingDown;
}
pub fn sensors(&self) -> &SensorStates {
&self.sensors
}
}
impl SensorStates {
fn new() -> SensorStates {
SensorStates { door_locked: None }
}
fn handle_event(&mut self,
handlers: &mut Vec<EventHandler>,
ev: Event)
-> Option<EventsResult> {
self.record_state(&ev);
for handler in handlers.iter_mut() {
match handler.run(ev) {
HandlerResult::Continue => {}
HandlerResult::QuitLoop => return Some(EventsResult::Quit),
}
}
return None;
pub fn door_locked(&self) -> Option<bool> {
self.door_locked
}
fn record_state(&mut self, ev: &Event) {
match ev {
&Event::DoorLocked(b) => self.door_locked = b,
&Event::DoorLocked(b) => self.door_locked = Some(b),
_ => {}
}
}
pub fn door_locked(&self) -> bool {
true
}
}
......@@ -46,7 +46,7 @@ impl State for UnLockingState {
}));
actors.lock = locker.terminate();
if r != EventsResult::Timeout {
assert!(r == EventsResult::ShuttingDown || env.door_locked() == locking);
assert!(r == EventsResult::ShuttingDown || env.sensors().door_locked() == Some(locking));
break; // the retries
}
}
......
use std::time::Duration;
use std::thread;
use chan;
pub mod wakeable;
pub fn timeout_chan(d: Duration) -> chan::Receiver<()> {
let (s, r) = chan::sync(0);
thread::spawn(move || {
thread::sleep(d);
drop(s);
});
r
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment