To separate responsibilities and not let individual modules get too big, we should move the data recorder implementation out of the simulation and into its own module. The result is as follows:
- Define the DataRecorder trait:
pub trait DataRecorder
{
fn init(&mut self, esp: Box<Building>, est: ElevatorState);
fn record(&mut self, est: ElevatorState, dst: u64);
fn summary(&mut self);
}
- Define the SimpleDataRecorder struct:
struct SimpleDataRecorder<W: Write>
{
esp: Box<Building>,
termwidth: u64,
termheight: u64,
stdout: raw::RawTerminal<W>,
log: File,
record_location: Vec<f64>,
record_velocity: Vec<f64>,
record_acceleration: Vec<f64>,
record_force: Vec<f64>,
}
- Define the SimpleDataRecorder constructor:
pub fn newSimpleDataRecorder(esp: Box<Building>) -> Box<DataRecorder>
{
let termsize = termion::terminal_size().ok();
Box::new(SimpleDataRecorder {
esp: esp.clone(),
termwidth: termsize.map(|(w,_)| w-2).expect("termwidth") as u64,
termheight: termsize.map(|(_,h)| h-2).expect("termheight") as u64,
stdout: io::stdout().into_raw_mode().unwrap(),
log: File::create("simulation.log").expect("log file"),
record_location: Vec::new(),
record_velocity: Vec::new(),
record_acceleration: Vec::new(),
record_force: Vec::new()
})
}
- Define the SimpleDataRecorder implementation of the DataRecorder trait:
impl<W: Write> DataRecorder for SimpleDataRecorder<W>
{
fn init(&mut self, esp: Box<Building>, est: ElevatorState)
{
...
}
fn record(&mut self, est: ElevatorState, dst: u64)
...
}
fn summary(&mut self)
{
...
}
}
- Define the miscellaneous helper functions:
fn variable_summary<W: Write>(stdout: &mut raw::RawTerminal<W>, vname: String, data: &Vec<f64>) {
let (avg, dev) = variable_summary_stats(data);
variable_summary_print(stdout, vname, avg, dev);
}
fn variable_summary_stats(data: &Vec<f64>) -> (f64, f64)
{
//calculate statistics
let N = data.len();
let sum = data.iter().sum::<f64>();
let avg = sum / (N as f64);
let dev = (
data.clone().into_iter()
.map(|v| (v - avg).powi(2))
.sum::<f64>()
/ (N as f64)
).sqrt();
(avg, dev)
}
fn variable_summary_print<W: Write>(stdout: &mut raw::RawTerminal<W>, vname: String, avg: f64, dev: f64)
{
//print formatted output
writeln!(stdout, "Average of {:25}{:.6}", vname, avg);
writeln!(stdout, "Standard deviation of {:14}{:.6}", vname, dev);
writeln!(stdout, "");
}