use std::collections::VecDeque;
use std::sync::Arc;
use tokio::sync::RwLock;
use super::DataPoint;
pub struct Series<T: DataPoint> {
capacity: usize,
ring: VecDeque<T>,
dirty: usize,
}
impl<T: DataPoint> Series<T> {
pub fn new(capacity: usize) -> Self {
Self {
capacity: capacity.max(1),
ring: VecDeque::with_capacity(capacity),
dirty: 0,
}
}
pub fn push(&mut self, point: T) {
if self.ring.len() == self.capacity {
self.ring.pop_front();
}
self.ring.push_back(point);
self.dirty = self.dirty.saturating_add(1);
}
pub fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
for p in iter {
self.push(p);
}
}
pub fn upsert_by_ts(&mut self, point: T) {
let ts = point.timestamp_ms();
if let Some(pos) = self.ring.iter().rposition(|p| p.timestamp_ms() == ts) {
self.ring[pos] = point;
self.dirty = self.dirty.saturating_add(1);
return;
}
self.push(point);
}
pub fn tail(&self, n: usize) -> Vec<T> {
let take = n.min(self.ring.len());
let start = self.ring.len() - take;
self.ring.iter().skip(start).cloned().collect()
}
pub fn snapshot(&self) -> Vec<T> {
self.ring.iter().cloned().collect()
}
pub fn last(&self) -> Option<&T> {
self.ring.back()
}
pub fn len(&self) -> usize {
self.ring.len()
}
pub fn is_empty(&self) -> bool {
self.ring.is_empty()
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn dirty_count(&self) -> usize {
self.dirty
}
pub fn mark_clean(&mut self) {
self.dirty = 0;
}
pub fn seed(&mut self, points: Vec<T>) {
self.ring.clear();
let take = points.len().min(self.capacity);
let start = points.len() - take;
for p in points.into_iter().skip(start) {
self.ring.push_back(p);
}
self.dirty = 0;
}
}
pub type SharedSeries<T> = Arc<RwLock<Series<T>>>;