use std::time::Instant;
use crate::error::Result;
pub trait Machine {
type Event;
fn handle_input(&mut self, wire: &[u8]) -> Result<usize>;
fn poll_transmit(&mut self, out: &mut Vec<u8>) -> bool;
fn handle_eof(&mut self) -> Result<()> {
Ok(())
}
fn poll_event(&mut self) -> Option<Self::Event>;
fn handle_timeout(&mut self, now: Instant) {
let _ = now;
}
fn next_timeout(&self) -> Option<Instant> {
None
}
fn is_finished(&self) -> bool;
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Default)]
struct EchoLine {
outbox: Vec<u8>,
events: Vec<usize>,
done: bool,
}
impl Machine for EchoLine {
type Event = usize;
fn handle_input(&mut self, wire: &[u8]) -> Result<usize> {
if let Some(pos) = wire.iter().position(|&b| b == b'\n') {
let take = pos + 1;
self.outbox.extend_from_slice(&wire[..take]);
self.events.push(take);
self.done = true;
Ok(take)
} else {
self.outbox.extend_from_slice(wire);
Ok(wire.len())
}
}
fn poll_transmit(&mut self, out: &mut Vec<u8>) -> bool {
if self.outbox.is_empty() {
return false;
}
out.append(&mut self.outbox);
true
}
fn poll_event(&mut self) -> Option<usize> {
if self.events.is_empty() {
None
} else {
Some(self.events.remove(0))
}
}
fn is_finished(&self) -> bool {
self.done
}
}
#[test]
fn echo_line_drives_to_completion() {
let mut m = EchoLine::default();
assert!(!m.is_finished());
assert_eq!(m.handle_input(b"hel").unwrap(), 3);
let mut out = Vec::new();
assert!(m.poll_transmit(&mut out));
assert_eq!(out, b"hel");
assert!(m.poll_event().is_none());
assert!(!m.is_finished());
assert_eq!(m.handle_input(b"lo\nignored").unwrap(), 3);
out.clear();
assert!(m.poll_transmit(&mut out));
assert_eq!(out, b"lo\n");
assert!(!m.poll_transmit(&mut out)); assert_eq!(m.poll_event(), Some(3));
assert!(m.poll_event().is_none());
assert!(m.is_finished());
assert!(m.next_timeout().is_none());
}
}