use std::collections::BTreeMap;
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::Notify;
use crate::chart::{DataPoint, SymbolInfo};
#[derive(Debug)]
pub struct StudyState {
pub data: Vec<DataPoint>,
pub symbol_info: Option<SymbolInfo>,
pub error_count: u32,
pub completed: bool,
pub errored: bool,
pub error_message: Option<String>,
pub first_data_at: Option<Instant>,
pub total_points: usize,
pub notify: Arc<Notify>,
}
impl StudyState {
#[cfg(test)]
pub fn new() -> Self {
Self::with_notify(Arc::new(Notify::new()))
}
pub fn with_notify(notify: Arc<Notify>) -> Self {
Self {
data: Vec::new(),
symbol_info: None,
error_count: 0,
completed: false,
errored: false,
error_message: None,
first_data_at: None,
total_points: 0,
notify,
}
}
pub fn with_capacity_and_notify(capacity: usize, notify: Arc<Notify>) -> Self {
Self {
data: Vec::with_capacity(capacity),
..Self::with_notify(notify)
}
}
pub fn record_points(&mut self, points: Vec<DataPoint>, count: usize) {
if self.first_data_at.is_none() {
self.first_data_at = Some(Instant::now());
}
self.data.extend(points);
self.total_points += count;
}
pub fn record_symbol_info(&mut self, info: SymbolInfo) {
self.symbol_info = Some(info);
}
pub fn record_error(&mut self) -> bool {
self.error_count += 1;
self.error_count > 5
}
pub fn complete(&mut self) {
self.completed = true;
self.notify.notify_waiters();
}
pub fn fail(&mut self, msg: String) {
self.errored = true;
self.error_message = Some(msg);
self.notify.notify_waiters();
}
#[inline]
pub fn is_done(&self) -> bool {
self.completed || self.errored
}
pub fn finalize(&mut self) -> Vec<DataPoint> {
let mut map = BTreeMap::new();
for dp in self.data.drain(..) {
let ts = dp.value.first().copied().map(|v| v as i64).unwrap_or(0);
let key = if ts != 0 {
(ts, dp.index)
} else {
(0, dp.index)
};
map.insert(key, dp);
}
map.into_values().collect()
}
}