openpine_vm/
series.rs

1use std::{collections::VecDeque, fmt, ops::Index};
2
3use gc_arena::Collection;
4use serde::{Deserialize, Serialize};
5
6use crate::{objects::gc_trace_any, raw_value::RawValue};
7
8/// A bar-aligned series of values.
9///
10/// Internally this is backed by a `VecDeque` and is used to represent Pine-like
11/// series variables (one value per bar). You don't construct `Series` directly;
12/// it is returned by [`Instance::chart()`](crate::Instance::chart) inside
13/// visual primitives like [`Plot`](crate::visuals::Plot).
14///
15/// # Examples
16///
17/// ```no_run
18/// # use openpine_vm::*;
19/// # async fn example() {
20/// # let source = "//@version=6\nindicator(\"\")\nplot(close)";
21/// # let provider = Vec::<Candlestick>::new();
22/// # let mut instance = Instance::builder(provider, source, TimeFrame::days(1),
23/// #     "NASDAQ:AAPL").build().await.unwrap();
24/// # instance.run_to_end("NASDAQ:AAPL", TimeFrame::days(1)).await.unwrap();
25/// let chart = instance.chart();
26/// for (id, sg) in chart.series_graphs() {
27///     if let Some(plot) = sg.as_plot() {
28///         // Access by index
29///         if let Some(value) = plot.series.get(0) {
30///             println!("First bar value: {:?}", value);
31///         }
32///
33///         // Iterate over all values (by reference)
34///         for (i, val) in (&plot.series).into_iter().enumerate() {
35///             println!("Bar {}: {:?}", i, val);
36///         }
37///
38///         println!("Total bars: {}", plot.series.len());
39///     }
40/// }
41/// # }
42/// ```
43pub struct Series<T> {
44    queue: VecDeque<T>,
45}
46
47impl<T> Clone for Series<T>
48where
49    T: Clone,
50{
51    fn clone(&self) -> Self {
52        Self {
53            queue: self.queue.clone(),
54        }
55    }
56}
57
58impl<T> fmt::Debug for Series<T>
59where
60    T: fmt::Debug,
61{
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        self.queue.fmt(f)
64    }
65}
66
67impl<T> Serialize for Series<T>
68where
69    T: Serialize,
70{
71    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
72    where
73        S: serde::Serializer,
74    {
75        self.queue.serialize(serializer)
76    }
77}
78
79impl<'de, T> Deserialize<'de> for Series<T>
80where
81    T: Deserialize<'de>,
82{
83    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
84    where
85        D: serde::Deserializer<'de>,
86    {
87        let queue = VecDeque::deserialize(deserializer)?;
88        Ok(Series { queue })
89    }
90}
91
92impl<T> Index<usize> for Series<T> {
93    type Output = T;
94
95    #[inline]
96    fn index(&self, index: usize) -> &Self::Output {
97        &self.queue[index]
98    }
99}
100
101impl<T> IntoIterator for Series<T> {
102    type Item = T;
103    type IntoIter = std::collections::vec_deque::IntoIter<T>;
104
105    #[inline]
106    fn into_iter(self) -> Self::IntoIter {
107        self.queue.into_iter()
108    }
109}
110
111impl<'a, T> IntoIterator for &'a Series<T> {
112    type Item = &'a T;
113    type IntoIter = std::collections::vec_deque::Iter<'a, T>;
114
115    #[inline]
116    fn into_iter(self) -> Self::IntoIter {
117        self.queue.iter()
118    }
119}
120
121impl<T> Series<T> {
122    /// Creates a `Series` from an existing `VecDeque`.
123    #[inline]
124    pub(crate) fn from_queue(queue: VecDeque<T>) -> Self {
125        Self { queue }
126    }
127
128    /// Returns an iterator over references to the elements.
129    #[inline]
130    pub fn iter(&self) -> std::collections::vec_deque::Iter<'_, T> {
131        self.queue.iter()
132    }
133}
134
135impl<T> Series<T>
136where
137    T: Default,
138{
139    #[inline]
140    pub(crate) fn new() -> Self {
141        Self {
142            queue: VecDeque::new(),
143        }
144    }
145
146    #[inline]
147    pub(crate) fn update(&mut self, value: T) {
148        let idx = self.queue.len() - 1;
149        self.queue[idx] = value;
150    }
151
152    #[inline]
153    pub(crate) fn truncate(&mut self, length: usize) -> usize {
154        let mut removed_count = 0;
155        while self.queue.len() > length {
156            self.queue.pop_front();
157            removed_count += 1;
158        }
159        removed_count
160    }
161
162    #[inline]
163    pub(crate) fn append_new(&mut self) {
164        self.queue.push_back(T::default());
165    }
166
167    /// Returns the value at `index`, or `None` if out of bounds.
168    #[inline]
169    pub fn get(&self, index: usize) -> Option<&T> {
170        self.queue.get(index)
171    }
172
173    /// Returns the number of elements in the series.
174    #[inline]
175    pub fn len(&self) -> usize {
176        self.queue.len()
177    }
178
179    /// Returns true if the series contains no elements.
180    #[inline]
181    pub fn is_empty(&self) -> bool {
182        self.queue.is_empty()
183    }
184
185    /// Returns the last element in the series, or `None` if empty.
186    #[inline]
187    pub fn last(&self) -> Option<&T> {
188        self.queue.back()
189    }
190}
191
192impl Series<RawValue> {
193    pub(crate) fn gc_trace(&self, cc: &Collection) {
194        for value in self.queue.iter().copied() {
195            gc_trace_any(value, cc);
196        }
197    }
198}