pub struct Scope {
data: Vec<(f64, f64)>,
name: &'static str,
}
impl Scope {
pub fn new(name: &'static str) -> Self {
Self {
data: Vec::new(),
name,
}
}
pub fn with_capacity(name: &'static str, capacity: usize) -> Self {
Self {
data: Vec::with_capacity(capacity),
name,
}
}
pub fn record(&mut self, time: f64, value: f64) {
self.data.push((time, value));
}
pub fn name(&self) -> &str {
self.name
}
pub fn data(&self) -> &[(f64, f64)] {
&self.data
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn last_value(&self) -> Option<f64> {
self.data.last().map(|&(_, v)| v)
}
pub fn to_csv(&self) -> String {
let mut csv = format!("time,{}\n", self.name);
for &(t, v) in &self.data {
csv.push_str(&format!("{},{}\n", t, v));
}
csv
}
pub fn clear(&mut self) {
self.data.clear();
}
pub fn max_value(&self) -> Option<f64> {
self.data.iter().map(|&(_, v)| v).reduce(f64::max)
}
pub fn min_value(&self) -> Option<f64> {
self.data.iter().map(|&(_, v)| v).reduce(f64::min)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn record_and_retrieve() {
let mut scope = Scope::new("test");
scope.record(0.0, 1.0);
scope.record(0.1, 2.0);
assert_eq!(scope.len(), 2);
assert_eq!(scope.data()[0], (0.0, 1.0));
assert_eq!(scope.data()[1], (0.1, 2.0));
}
#[test]
fn last_value() {
let mut scope = Scope::new("test");
assert_eq!(scope.last_value(), None);
scope.record(0.0, 42.0);
assert_eq!(scope.last_value(), Some(42.0));
}
#[test]
fn csv_output() {
let mut scope = Scope::new("temperature");
scope.record(0.0, 25.0);
scope.record(0.1, 26.0);
let csv = scope.to_csv();
assert!(csv.starts_with("time,temperature\n"));
assert!(csv.contains("0,25\n"));
}
#[test]
fn min_max() {
let mut scope = Scope::new("test");
scope.record(0.0, 5.0);
scope.record(0.1, 2.0);
scope.record(0.2, 8.0);
assert_eq!(scope.max_value(), Some(8.0));
assert_eq!(scope.min_value(), Some(2.0));
}
#[test]
fn clear_empties() {
let mut scope = Scope::new("test");
scope.record(0.0, 1.0);
scope.clear();
assert!(scope.is_empty());
}
}