navi_vm/plot_row_stream.rs
1use navi_visuals::{DrawEvent, SeriesEvent};
2
3use crate::{Error, Event, RunHandle};
4
5/// An iterator over per-bar `plot()` rows returned by
6/// [`Instance::plot_rows`](crate::Instance::plot_rows).
7///
8/// Call [`columns`](PlotRowStream::columns) once to obtain the column titles,
9/// then drive the stream with [`next_row`](PlotRowStream::next_row).
10///
11/// # Example
12///
13/// ```rust,ignore
14/// let mut stream = instance.plot_rows(symbol, tf);
15/// let columns = stream.columns().to_vec();
16/// while let Some(row) = stream.next_row().await {
17/// let row = row?;
18/// // row is &[Option<f64>] aligned to `columns`
19/// }
20/// ```
21pub struct PlotRowStream {
22 pub(crate) columns: Vec<Option<String>>,
23 pub(crate) handle: RunHandle,
24 pub(crate) plot_indexes: Vec<Option<usize>>,
25 pub(crate) row: Vec<Option<f64>>,
26 pub(crate) row_open: bool,
27 /// When `true`, clear the row buffer at the start of the next `next_row`
28 /// call instead of immediately after yielding, so the caller can hold the
29 /// `&[Option<f64>]` borrow until the next call.
30 pub(crate) needs_reset: bool,
31}
32
33impl PlotRowStream {
34 /// Returns the `plot()` column titles in declaration order.
35 pub fn columns(&self) -> &[Option<String>] {
36 &self.columns
37 }
38
39 /// Returns the next completed bar row, or `None` when the stream ends.
40 ///
41 /// The returned slice borrows from an internal buffer that is reused
42 /// across calls; copy it (e.g. `.to_vec()`) if you need it to outlive
43 /// the next `next_row` call.
44 pub async fn next_row(&mut self) -> Option<Result<&[Option<f64>], Error>> {
45 if self.needs_reset {
46 self.row.fill(None);
47 self.needs_reset = false;
48 }
49
50 loop {
51 match self.handle.next_event().await {
52 None => {
53 return if self.row_open {
54 self.row_open = false;
55 Some(Ok(&self.row))
56 } else {
57 None
58 };
59 }
60 Some(Err(e)) => return Some(Err(e)),
61 Some(Ok(Event::Draw(DrawEvent::NewBar { .. }))) => {
62 if self.row_open {
63 self.needs_reset = true;
64 return Some(Ok(&self.row));
65 }
66 self.row_open = true;
67 }
68 Some(Ok(Event::Draw(DrawEvent::Series(SeriesEvent::UpdatePlot {
69 id,
70 value,
71 ..
72 })))) => {
73 if let Some(Some(index)) = self.plot_indexes.get(id as usize) {
74 self.row[*index] = value;
75 }
76 }
77 Some(Ok(_)) => {}
78 }
79 }
80 }
81}