Skip to main content

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}