use std::collections::VecDeque;
use std::io::Write;
use std::sync::{Arc, Mutex};
use crate::plot::{Frame, Plot};
#[derive(Debug, Clone)]
pub struct Ring {
inner: Arc<Mutex<VecDeque<f64>>>,
capacity: usize,
}
impl Ring {
pub fn new(capacity: usize) -> Ring {
assert!(capacity > 0, "Ring::new requires a non-zero capacity");
Ring {
inner: Arc::new(Mutex::new(VecDeque::with_capacity(capacity))),
capacity,
}
}
pub fn push(&self, value: f64) {
let mut window = self.inner.lock().expect("ring lock");
if window.len() == self.capacity {
window.pop_front();
}
window.push_back(value);
}
pub fn snapshot(&self) -> Vec<f64> {
let window = self.inner.lock().expect("ring lock");
window.iter().copied().collect()
}
pub fn len(&self) -> usize {
self.inner.lock().expect("ring lock").len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Rate {
previous: Option<f64>,
}
impl Rate {
pub fn new() -> Rate {
Rate::default()
}
pub fn delta(&mut self, value: f64) -> f64 {
let delta = match (self.previous, value.is_finite()) {
(Some(previous), true) => value - previous,
_ => f64::NAN,
};
self.previous = value.is_finite().then_some(value);
delta
}
}
#[derive(Debug)]
pub struct Live<W: Write> {
out: W,
drawn_rows: usize,
}
impl<W: Write> Live<W> {
pub fn new(out: W) -> Live<W> {
Live { out, drawn_rows: 0 }
}
pub fn draw(&mut self, plot: &Plot<'_>, frame: &Frame) -> std::io::Result<()> {
let text = plot.render(frame);
let mut buffer = String::with_capacity(text.len() + 16);
if self.drawn_rows > 0 {
use std::fmt::Write as _;
let _ = write!(buffer, "\x1b[{}A\r\x1b[J", self.drawn_rows);
}
buffer.push_str(&text);
buffer.push('\n');
self.out.write_all(buffer.as_bytes())?;
self.out.flush()?;
self.drawn_rows = text.lines().count().max(1);
Ok(())
}
pub fn detach(&mut self) {
self.drawn_rows = 0;
}
}
#[cfg(test)]
#[path = "tests/stream_tests.rs"]
mod tests;