Skip to main content

pine_core/
output.rs

1// Output-related types, traits, and implementations
2
3use std::collections::HashMap;
4
5/// Represents a color with RGBA components
6#[derive(Clone, Debug, PartialEq)]
7pub struct Color {
8    pub r: u8, // Red component (0-255)
9    pub g: u8, // Green component (0-255)
10    pub b: u8, // Blue component (0-255)
11    pub t: u8, // Transparency (0-100)
12}
13
14impl Color {
15    pub fn new(r: u8, g: u8, b: u8, t: u8) -> Self {
16        Color { r, g, b, t }
17    }
18}
19
20/// Represents a label drawable object
21#[derive(Clone, Debug)]
22pub struct Label {
23    pub x: f64,
24    pub y: f64,
25    pub text: String,
26    pub xloc: String,
27    pub yloc: String,
28    pub color: Option<Color>,
29    pub style: String,
30    pub textcolor: Option<Color>,
31    pub size: String,
32    pub textalign: String,
33    pub tooltip: Option<String>,
34    pub text_font_family: String,
35}
36
37/// Represents a box drawable object
38/// A `fill(...)` between two plots or hlines.
39#[derive(Clone, Debug)]
40pub struct FillObject {
41    /// Id of the first plot/hline (`None` when it was `na`).
42    pub id1: Option<usize>,
43    /// Id of the second plot/hline.
44    pub id2: Option<usize>,
45    pub color: Option<Color>,
46    pub title: String,
47}
48
49/// Chart-wide settings written by global functions like `bgcolor`/`barcolor`.
50#[derive(Clone, Debug, Default)]
51pub struct GlobalContext {
52    /// Background color (`bgcolor`).
53    pub bgcolor: Option<Color>,
54    /// Price-bar color (`barcolor`).
55    pub barcolor: Option<Color>,
56}
57
58/// An `alertcondition(...)` declaration — a named alert with a message.
59#[derive(Clone, Debug, Default)]
60pub struct AlertCondition {
61    pub title: String,
62    pub message: String,
63}
64
65/// The `indicator(...)` declaration — a script's identity and display settings.
66#[derive(Clone, Debug, Default)]
67pub struct Indicator {
68    pub title: String,
69    pub shorttitle: String,
70    pub overlay: bool,
71    pub format: String,
72    pub precision: Option<i64>,
73    pub timeframe: String,
74}
75
76/// The `library(...)` declaration — marks a script as a reusable library.
77#[derive(Clone, Debug, Default)]
78pub struct Library {
79    pub title: String,
80    pub overlay: bool,
81    pub dynamic_requests: Option<bool>,
82}
83
84/// A trend line drawn between two points, `(x1, y1)`–`(x2, y2)`.
85#[derive(Clone, Debug)]
86pub struct LineObject {
87    pub x1: f64,
88    pub y1: f64,
89    pub x2: f64,
90    pub y2: f64,
91    pub xloc: String,
92    pub extend: String,
93    pub color: Option<Color>,
94    pub style: String,
95    pub width: f64,
96}
97
98/// One cell of a [`Table`].
99#[derive(Clone, Debug, Default)]
100pub struct TableCell {
101    pub text: String,
102    pub text_color: Option<Color>,
103    pub bgcolor: Option<Color>,
104    pub text_size: String,
105    pub text_halign: String,
106    pub text_valign: String,
107}
108
109/// A table overlay: a fixed grid of cells anchored to a chart position.
110#[derive(Clone, Debug)]
111pub struct Table {
112    pub position: String,
113    pub columns: usize,
114    pub rows: usize,
115    pub bgcolor: Option<Color>,
116    pub cells: HashMap<(usize, usize), TableCell>,
117}
118
119#[derive(Clone, Debug)]
120pub struct PineBox {
121    pub left: f64,
122    pub top: f64,
123    pub right: f64,
124    pub bottom: f64,
125    pub border_color: Option<Color>,
126    pub border_width: f64,
127    pub border_style: String,
128    pub extend: String,
129    pub xloc: String,
130    pub bgcolor: Option<Color>,
131    pub text: String,
132    pub text_size: f64,
133    pub text_color: Option<Color>,
134    pub text_halign: String,
135    pub text_valign: String,
136    pub text_wrap: String,
137    pub text_font_family: String,
138}
139
140/// Represents a plot output
141#[derive(Clone, Debug, Default)]
142pub struct Plot {
143    pub series: f64,
144    pub title: String,
145    pub color: Option<Color>,
146    pub linewidth: f64,
147    pub style: String,
148    pub trackprice: bool,
149    pub histbase: f64,
150    pub offset: f64,
151    pub join: bool,
152    pub editable: bool,
153    pub show_last: Option<f64>,
154    pub display: String,
155    pub format: Option<String>,
156    pub precision: Option<f64>,
157    pub force_overlay: bool,
158    pub linestyle: String,
159}
160
161/// Represents a plotarrow output
162#[derive(Clone, Debug)]
163pub struct Plotarrow {
164    pub series: f64,
165    pub title: String,
166    pub colorup: Option<Color>,
167    pub colordown: Option<Color>,
168    pub offset: f64,
169    pub minheight: f64,
170    pub maxheight: f64,
171    pub editable: bool,
172    pub show_last: Option<f64>,
173    pub display: String,
174    pub format: Option<String>,
175    pub precision: Option<f64>,
176    pub force_overlay: bool,
177}
178
179/// Represents a plotbar output
180#[derive(Clone, Debug)]
181pub struct Plotbar {
182    pub open: f64,
183    pub high: f64,
184    pub low: f64,
185    pub close: f64,
186    pub title: String,
187    pub color: Option<Color>,
188    pub editable: bool,
189    pub show_last: Option<f64>,
190    pub display: String,
191    pub format: Option<String>,
192    pub precision: Option<f64>,
193    pub force_overlay: bool,
194}
195
196/// Represents a plotcandle output
197#[derive(Clone, Debug)]
198pub struct Plotcandle {
199    pub open: f64,
200    pub high: f64,
201    pub low: f64,
202    pub close: f64,
203    pub title: String,
204    pub color: Option<Color>,
205    pub wickcolor: Option<Color>,
206    pub editable: bool,
207    pub show_last: Option<f64>,
208    pub bordercolor: Option<Color>,
209    pub display: String,
210    pub format: Option<String>,
211    pub precision: Option<f64>,
212    pub force_overlay: bool,
213}
214
215/// Represents a plotchar output
216#[derive(Clone, Debug)]
217pub struct Plotchar {
218    pub series: f64,
219    pub title: String,
220    pub char: String,
221    pub location: String,
222    pub color: Option<Color>,
223    pub offset: f64,
224    pub text: String,
225    pub textcolor: Option<Color>,
226    pub editable: bool,
227    pub size: String,
228    pub show_last: Option<f64>,
229    pub display: String,
230    pub format: Option<String>,
231    pub precision: Option<f64>,
232    pub force_overlay: bool,
233}
234
235/// Represents a plotshape output
236#[derive(Clone, Debug)]
237pub struct Plotshape {
238    pub series: f64,
239    pub title: String,
240    pub style: String,
241    pub location: String,
242    pub color: Option<Color>,
243    pub offset: f64,
244    pub text: String,
245    pub textcolor: Option<Color>,
246    pub editable: bool,
247    pub size: String,
248    pub show_last: Option<f64>,
249    pub display: String,
250    pub format: Option<String>,
251    pub precision: Option<f64>,
252    pub force_overlay: bool,
253}
254
255/// Log level
256#[derive(Debug, Clone, Copy, PartialEq, Eq)]
257pub enum LogLevel {
258    Info,
259    Warning,
260    Error,
261}
262
263/// A log entry with level and message
264#[derive(Debug, Clone)]
265pub struct LogEntry {
266    pub level: LogLevel,
267    pub message: String,
268}
269
270/// The default value of a declared input, preserved with its type so a host can
271/// render the right settings widget.
272#[derive(Debug, Clone, PartialEq)]
273pub enum InputValue {
274    Int(i64),
275    Float(f64),
276    Bool(bool),
277    Str(String),
278    Color(Color),
279}
280
281/// A declared script input (`input.int(...)`, `input.source(...)`, ...).
282///
283/// Recorded into the output so a host can enumerate a script's configurable
284/// settings without executing anything itself. The script still receives the
285/// default value at runtime.
286#[derive(Debug, Clone)]
287pub struct Input {
288    /// Which `input.*` function declared it: `"int"`, `"float"`, `"bool"`,
289    /// `"string"`, `"source"`, `"color"`, `"session"`, `"time"`.
290    pub kind: String,
291    /// Display title (`title` argument), empty when none was given.
292    pub title: String,
293    /// Group the input belongs to (`group` argument), empty when none.
294    pub group: String,
295    /// Default value returned to the script.
296    pub default: InputValue,
297}
298
299/// Base trait for all output implementations
300///
301/// This trait defines the minimal contract that all output types must implement.
302/// Extension traits (LogOutput, PlotOutput, etc.) add additional capabilities.
303pub trait PineOutput: Default + Clone + std::fmt::Debug + 'static {
304    /// Clear all output data for a new iteration
305    fn clear(&mut self);
306}
307
308/// Extension trait for logging output
309pub trait LogOutput: PineOutput {
310    /// Add a log entry with the given level and message
311    fn add_log(&mut self, level: LogLevel, message: String);
312    /// Get all log entries
313    fn get_logs(&self) -> &[LogEntry];
314}
315
316/// Macro to easily implement all output traits by delegating to a base field
317///
318/// # Example
319/// ```ignore
320/// impl_output_traits_delegate!(CustomOutput, base);
321/// ```
322#[macro_export]
323macro_rules! impl_output_traits_delegate {
324    ($type:ty, $field:ident) => {
325        impl $crate::LogOutput for $type {
326            fn add_log(&mut self, level: $crate::LogLevel, message: String) {
327                self.$field.add_log(level, message)
328            }
329            fn get_logs(&self) -> &[$crate::LogEntry] {
330                self.$field.get_logs()
331            }
332        }
333
334        impl $crate::PlotOutput for $type {
335            fn add_plot(&mut self, plot: $crate::Plot) {
336                self.$field.add_plot(plot)
337            }
338            fn plots(&self) -> &[$crate::Plot] {
339                self.$field.plots()
340            }
341            fn add_plotarrow(&mut self, arrow: $crate::Plotarrow) {
342                self.$field.add_plotarrow(arrow)
343            }
344            fn plotarrows(&self) -> &[$crate::Plotarrow] {
345                self.$field.plotarrows()
346            }
347            fn add_plotbar(&mut self, bar: $crate::Plotbar) {
348                self.$field.add_plotbar(bar)
349            }
350            fn plotbars(&self) -> &[$crate::Plotbar] {
351                self.$field.plotbars()
352            }
353            fn add_plotcandle(&mut self, candle: $crate::Plotcandle) {
354                self.$field.add_plotcandle(candle)
355            }
356            fn plotcandles(&self) -> &[$crate::Plotcandle] {
357                self.$field.plotcandles()
358            }
359            fn add_plotchar(&mut self, char: $crate::Plotchar) {
360                self.$field.add_plotchar(char)
361            }
362            fn plotchars(&self) -> &[$crate::Plotchar] {
363                self.$field.plotchars()
364            }
365            fn add_plotshape(&mut self, shape: $crate::Plotshape) {
366                self.$field.add_plotshape(shape)
367            }
368            fn plotshapes(&self) -> &[$crate::Plotshape] {
369                self.$field.plotshapes()
370            }
371        }
372
373        impl $crate::LabelOutput for $type {
374            fn add_label(&mut self, label: $crate::Label) -> usize {
375                self.$field.add_label(label)
376            }
377            fn get_label(&self, id: usize) -> Option<&$crate::Label> {
378                self.$field.get_label(id)
379            }
380            fn get_label_mut(&mut self, id: usize) -> Option<&mut $crate::Label> {
381                self.$field.get_label_mut(id)
382            }
383            fn delete_label(&mut self, id: usize) -> bool {
384                self.$field.delete_label(id)
385            }
386        }
387
388        impl $crate::BoxOutput for $type {
389            fn add_box(&mut self, box_obj: $crate::PineBox) -> usize {
390                self.$field.add_box(box_obj)
391            }
392            fn get_box(&self, id: usize) -> Option<&$crate::PineBox> {
393                self.$field.get_box(id)
394            }
395            fn get_box_mut(&mut self, id: usize) -> Option<&mut $crate::PineBox> {
396                self.$field.get_box_mut(id)
397            }
398            fn delete_box(&mut self, id: usize) -> bool {
399                self.$field.delete_box(id)
400            }
401        }
402
403        impl $crate::InputOutput for $type {
404            fn add_input(&mut self, input: $crate::Input) {
405                self.$field.add_input(input)
406            }
407            fn inputs(&self) -> &[$crate::Input] {
408                self.$field.inputs()
409            }
410        }
411
412        impl $crate::MetadataOutput for $type {
413            fn set_indicator(&mut self, indicator: $crate::Indicator) {
414                self.$field.set_indicator(indicator)
415            }
416            fn indicator(&self) -> Option<&$crate::Indicator> {
417                self.$field.indicator()
418            }
419            fn set_library(&mut self, library: $crate::Library) {
420                self.$field.set_library(library)
421            }
422            fn library(&self) -> Option<&$crate::Library> {
423                self.$field.library()
424            }
425        }
426
427        impl $crate::AlertConditionOutput for $type {
428            fn add_alertcondition(&mut self, alert: $crate::AlertCondition) {
429                self.$field.add_alertcondition(alert)
430            }
431            fn alertconditions(&self) -> &[$crate::AlertCondition] {
432                self.$field.alertconditions()
433            }
434        }
435
436        impl $crate::FillOutput for $type {
437            fn add_fill(&mut self, fill: $crate::FillObject) {
438                self.$field.add_fill(fill)
439            }
440            fn fills(&self) -> &[$crate::FillObject] {
441                self.$field.fills()
442            }
443        }
444
445        impl $crate::GlobalOutput for $type {
446            fn set_bgcolor(&mut self, color: Option<$crate::Color>) {
447                self.$field.set_bgcolor(color)
448            }
449            fn set_barcolor(&mut self, color: Option<$crate::Color>) {
450                self.$field.set_barcolor(color)
451            }
452            fn global_context(&self) -> &$crate::GlobalContext {
453                self.$field.global_context()
454            }
455        }
456
457        impl $crate::LineOutput for $type {
458            fn add_line(&mut self, line: $crate::LineObject) -> usize {
459                self.$field.add_line(line)
460            }
461            fn get_line(&self, id: usize) -> Option<&$crate::LineObject> {
462                self.$field.get_line(id)
463            }
464            fn get_line_mut(&mut self, id: usize) -> Option<&mut $crate::LineObject> {
465                self.$field.get_line_mut(id)
466            }
467            fn delete_line(&mut self, id: usize) -> bool {
468                self.$field.delete_line(id)
469            }
470        }
471
472        impl $crate::TableOutput for $type {
473            fn add_table(&mut self, table: $crate::Table) -> usize {
474                self.$field.add_table(table)
475            }
476            fn get_table(&self, id: usize) -> Option<&$crate::Table> {
477                self.$field.get_table(id)
478            }
479            fn get_table_mut(&mut self, id: usize) -> Option<&mut $crate::Table> {
480                self.$field.get_table_mut(id)
481            }
482            fn delete_table(&mut self, id: usize) -> bool {
483                self.$field.delete_table(id)
484            }
485        }
486    };
487}
488
489/// Extension trait for plot-related output
490pub trait PlotOutput: PineOutput {
491    /// Add a plot output
492    fn add_plot(&mut self, plot: Plot);
493    /// Get all plot outputs
494    fn plots(&self) -> &[Plot];
495
496    /// Add a plotarrow output
497    fn add_plotarrow(&mut self, arrow: Plotarrow);
498    /// Get all plotarrow outputs
499    fn plotarrows(&self) -> &[Plotarrow];
500
501    /// Add a plotbar output
502    fn add_plotbar(&mut self, bar: Plotbar);
503    /// Get all plotbar outputs
504    fn plotbars(&self) -> &[Plotbar];
505
506    /// Add a plotcandle output
507    fn add_plotcandle(&mut self, candle: Plotcandle);
508    /// Get all plotcandle outputs
509    fn plotcandles(&self) -> &[Plotcandle];
510
511    /// Add a plotchar output
512    fn add_plotchar(&mut self, char: Plotchar);
513    /// Get all plotchar outputs
514    fn plotchars(&self) -> &[Plotchar];
515
516    /// Add a plotshape output
517    fn add_plotshape(&mut self, shape: Plotshape);
518    /// Get all plotshape outputs
519    fn plotshapes(&self) -> &[Plotshape];
520}
521
522/// Extension trait for label output
523pub trait LabelOutput: PineOutput {
524    /// Add a label and return its ID
525    fn add_label(&mut self, label: Label) -> usize;
526    /// Get a reference to a label by ID
527    fn get_label(&self, id: usize) -> Option<&Label>;
528    /// Get a mutable reference to a label by ID
529    fn get_label_mut(&mut self, id: usize) -> Option<&mut Label>;
530    /// Delete a label by ID and return true if it existed
531    fn delete_label(&mut self, id: usize) -> bool;
532}
533
534/// Extension trait for box output
535pub trait BoxOutput: PineOutput {
536    /// Add a box and return its ID
537    fn add_box(&mut self, box_obj: PineBox) -> usize;
538    /// Get a reference to a box by ID
539    fn get_box(&self, id: usize) -> Option<&PineBox>;
540    /// Get a mutable reference to a box by ID
541    fn get_box_mut(&mut self, id: usize) -> Option<&mut PineBox>;
542    /// Delete a box by ID and return true if it existed
543    fn delete_box(&mut self, id: usize) -> bool;
544}
545
546/// Extension trait for table output
547pub trait TableOutput: PineOutput {
548    /// Add a table and return its ID
549    fn add_table(&mut self, table: Table) -> usize;
550    /// Get a reference to a table by ID
551    fn get_table(&self, id: usize) -> Option<&Table>;
552    /// Get a mutable reference to a table by ID
553    fn get_table_mut(&mut self, id: usize) -> Option<&mut Table>;
554    /// Delete a table by ID and return true if it existed
555    fn delete_table(&mut self, id: usize) -> bool;
556}
557
558/// Extension trait for line output
559pub trait LineOutput: PineOutput {
560    /// Add a line and return its ID
561    fn add_line(&mut self, line: LineObject) -> usize;
562    /// Get a reference to a line by ID
563    fn get_line(&self, id: usize) -> Option<&LineObject>;
564    /// Get a mutable reference to a line by ID
565    fn get_line_mut(&mut self, id: usize) -> Option<&mut LineObject>;
566    /// Delete a line by ID and return true if it existed
567    fn delete_line(&mut self, id: usize) -> bool;
568}
569
570/// Extension trait for recording `fill(...)` areas.
571pub trait FillOutput: PineOutput {
572    fn add_fill(&mut self, fill: FillObject);
573    fn fills(&self) -> &[FillObject];
574}
575
576/// Extension trait for chart-wide globals (`bgcolor`, `barcolor`).
577pub trait GlobalOutput: PineOutput {
578    fn set_bgcolor(&mut self, color: Option<Color>);
579    fn set_barcolor(&mut self, color: Option<Color>);
580    /// The accumulated chart-wide settings.
581    fn global_context(&self) -> &GlobalContext;
582}
583
584/// Extension trait for recording declared alert conditions.
585pub trait AlertConditionOutput: PineOutput {
586    /// Record a declared alert condition.
587    fn add_alertcondition(&mut self, alert: AlertCondition);
588    /// Every alert condition declared so far, in declaration order.
589    fn alertconditions(&self) -> &[AlertCondition];
590}
591
592/// Extension trait for a script's declaration statement — `indicator(...)` or
593/// `library(...)` (a script has at most one).
594pub trait MetadataOutput: PineOutput {
595    /// Record the indicator declaration.
596    fn set_indicator(&mut self, indicator: Indicator);
597    /// The indicator declaration, if the script declared one.
598    fn indicator(&self) -> Option<&Indicator>;
599    /// Record the library declaration.
600    fn set_library(&mut self, library: Library);
601    /// The library declaration, if the script declared one.
602    fn library(&self) -> Option<&Library>;
603}
604
605/// Extension trait for recording declared inputs
606pub trait InputOutput: PineOutput {
607    /// Record a declared input.
608    fn add_input(&mut self, input: Input);
609    /// Every input declared so far, in declaration order.
610    fn inputs(&self) -> &[Input];
611}
612
613/// Default implementation of PineOutput that supports all features
614#[derive(Default, Clone, Debug)]
615pub struct DefaultPineOutput {
616    /// Label storage for drawable objects
617    labels: HashMap<usize, Label>,
618    /// Next label ID
619    next_label_id: usize,
620    /// Box storage for drawable objects
621    boxes: HashMap<usize, PineBox>,
622    /// Next box ID
623    next_box_id: usize,
624    /// Line storage for drawable objects
625    lines: HashMap<usize, LineObject>,
626    /// Next line ID
627    next_line_id: usize,
628    /// Table storage for drawable objects
629    tables: HashMap<usize, Table>,
630    /// Next table ID
631    next_table_id: usize,
632    /// Plot outputs
633    plots: Vec<Plot>,
634    /// Plotarrow outputs
635    plotarrows: Vec<Plotarrow>,
636    /// Plotbar outputs
637    plotbars: Vec<Plotbar>,
638    /// Plotcandle outputs
639    plotcandles: Vec<Plotcandle>,
640    /// Plotchar outputs
641    plotchars: Vec<Plotchar>,
642    /// Plotshape outputs
643    plotshapes: Vec<Plotshape>,
644    /// Log entries
645    logs: Vec<LogEntry>,
646    /// Declared inputs
647    inputs: Vec<Input>,
648    /// The `indicator(...)` declaration, if any.
649    indicator: Option<Indicator>,
650    /// The `library(...)` declaration, if any.
651    library: Option<Library>,
652    /// Chart-wide settings (`bgcolor`, `barcolor`).
653    globals: GlobalContext,
654    /// Declared alert conditions.
655    alertconditions: Vec<AlertCondition>,
656    /// `fill(...)` areas.
657    fills: Vec<FillObject>,
658}
659
660impl PineOutput for DefaultPineOutput {
661    fn clear(&mut self) {
662        self.labels.clear();
663        self.boxes.clear();
664        self.plots.clear();
665        self.plotarrows.clear();
666        self.plotbars.clear();
667        self.plotcandles.clear();
668        self.plotchars.clear();
669        self.plotshapes.clear();
670        self.logs.clear();
671        self.inputs.clear();
672        self.indicator = None;
673        self.globals = GlobalContext::default();
674        self.alertconditions.clear();
675        self.fills.clear();
676        self.lines.clear();
677        self.tables.clear();
678        // Reset ID counters
679        self.next_label_id = 0;
680        self.next_box_id = 0;
681        self.next_line_id = 0;
682        self.next_table_id = 0;
683    }
684}
685
686impl LogOutput for DefaultPineOutput {
687    fn add_log(&mut self, level: LogLevel, message: String) {
688        self.logs.push(LogEntry { level, message });
689    }
690
691    fn get_logs(&self) -> &[LogEntry] {
692        &self.logs
693    }
694}
695
696impl PlotOutput for DefaultPineOutput {
697    fn add_plot(&mut self, plot: Plot) {
698        self.plots.push(plot);
699    }
700
701    fn plots(&self) -> &[Plot] {
702        &self.plots
703    }
704
705    fn add_plotarrow(&mut self, arrow: Plotarrow) {
706        self.plotarrows.push(arrow);
707    }
708
709    fn plotarrows(&self) -> &[Plotarrow] {
710        &self.plotarrows
711    }
712
713    fn add_plotbar(&mut self, bar: Plotbar) {
714        self.plotbars.push(bar);
715    }
716
717    fn plotbars(&self) -> &[Plotbar] {
718        &self.plotbars
719    }
720
721    fn add_plotcandle(&mut self, candle: Plotcandle) {
722        self.plotcandles.push(candle);
723    }
724
725    fn plotcandles(&self) -> &[Plotcandle] {
726        &self.plotcandles
727    }
728
729    fn add_plotchar(&mut self, char: Plotchar) {
730        self.plotchars.push(char);
731    }
732
733    fn plotchars(&self) -> &[Plotchar] {
734        &self.plotchars
735    }
736
737    fn add_plotshape(&mut self, shape: Plotshape) {
738        self.plotshapes.push(shape);
739    }
740
741    fn plotshapes(&self) -> &[Plotshape] {
742        &self.plotshapes
743    }
744}
745
746impl LabelOutput for DefaultPineOutput {
747    fn add_label(&mut self, label: Label) -> usize {
748        let id = self.next_label_id;
749        self.next_label_id += 1;
750        self.labels.insert(id, label);
751        id
752    }
753
754    fn get_label(&self, id: usize) -> Option<&Label> {
755        self.labels.get(&id)
756    }
757
758    fn get_label_mut(&mut self, id: usize) -> Option<&mut Label> {
759        self.labels.get_mut(&id)
760    }
761
762    fn delete_label(&mut self, id: usize) -> bool {
763        self.labels.remove(&id).is_some()
764    }
765}
766
767impl BoxOutput for DefaultPineOutput {
768    fn add_box(&mut self, box_obj: PineBox) -> usize {
769        let id = self.next_box_id;
770        self.next_box_id += 1;
771        self.boxes.insert(id, box_obj);
772        id
773    }
774
775    fn get_box(&self, id: usize) -> Option<&PineBox> {
776        self.boxes.get(&id)
777    }
778
779    fn get_box_mut(&mut self, id: usize) -> Option<&mut PineBox> {
780        self.boxes.get_mut(&id)
781    }
782
783    fn delete_box(&mut self, id: usize) -> bool {
784        self.boxes.remove(&id).is_some()
785    }
786}
787
788impl LineOutput for DefaultPineOutput {
789    fn add_line(&mut self, line: LineObject) -> usize {
790        let id = self.next_line_id;
791        self.next_line_id += 1;
792        self.lines.insert(id, line);
793        id
794    }
795
796    fn get_line(&self, id: usize) -> Option<&LineObject> {
797        self.lines.get(&id)
798    }
799
800    fn get_line_mut(&mut self, id: usize) -> Option<&mut LineObject> {
801        self.lines.get_mut(&id)
802    }
803
804    fn delete_line(&mut self, id: usize) -> bool {
805        self.lines.remove(&id).is_some()
806    }
807}
808
809impl TableOutput for DefaultPineOutput {
810    fn add_table(&mut self, table: Table) -> usize {
811        let id = self.next_table_id;
812        self.next_table_id += 1;
813        self.tables.insert(id, table);
814        id
815    }
816
817    fn get_table(&self, id: usize) -> Option<&Table> {
818        self.tables.get(&id)
819    }
820
821    fn get_table_mut(&mut self, id: usize) -> Option<&mut Table> {
822        self.tables.get_mut(&id)
823    }
824
825    fn delete_table(&mut self, id: usize) -> bool {
826        self.tables.remove(&id).is_some()
827    }
828}
829
830impl InputOutput for DefaultPineOutput {
831    fn add_input(&mut self, input: Input) {
832        self.inputs.push(input);
833    }
834
835    fn inputs(&self) -> &[Input] {
836        &self.inputs
837    }
838}
839
840impl MetadataOutput for DefaultPineOutput {
841    fn set_indicator(&mut self, indicator: Indicator) {
842        self.indicator = Some(indicator);
843    }
844
845    fn indicator(&self) -> Option<&Indicator> {
846        self.indicator.as_ref()
847    }
848
849    fn set_library(&mut self, library: Library) {
850        self.library = Some(library);
851    }
852
853    fn library(&self) -> Option<&Library> {
854        self.library.as_ref()
855    }
856}
857
858impl AlertConditionOutput for DefaultPineOutput {
859    fn add_alertcondition(&mut self, alert: AlertCondition) {
860        self.alertconditions.push(alert);
861    }
862
863    fn alertconditions(&self) -> &[AlertCondition] {
864        &self.alertconditions
865    }
866}
867
868impl FillOutput for DefaultPineOutput {
869    fn add_fill(&mut self, fill: FillObject) {
870        self.fills.push(fill);
871    }
872
873    fn fills(&self) -> &[FillObject] {
874        &self.fills
875    }
876}
877
878impl GlobalOutput for DefaultPineOutput {
879    fn set_bgcolor(&mut self, color: Option<Color>) {
880        self.globals.bgcolor = color;
881    }
882
883    fn set_barcolor(&mut self, color: Option<Color>) {
884        self.globals.barcolor = color;
885    }
886
887    fn global_context(&self) -> &GlobalContext {
888        &self.globals
889    }
890}