mondrian_charts/fiberplane/
types.rs

1use crate::types::*;
2pub use fiberplane_models::notebooks::{GraphType, StackingType};
3pub use fiberplane_models::providers::{Metric, ProviderEvent, Timeseries};
4pub use fiberplane_models::timestamps::{TimeRange, Timestamp};
5use serde::Serialize;
6use std::collections::BTreeMap;
7
8/// All the data necessary to generate an abstract chart from an array of
9/// timeseries.
10pub struct TimeseriesSourceData<'source, 'slice, 'value> {
11    /// The type of chart to display.
12    pub graph_type: GraphType,
13
14    /// The type of stacking to apply to the chart.
15    pub stacking_type: StackingType,
16
17    /// Array of timeseries data to display in the chart.
18    ///
19    /// Make sure the timeseries contains data for the given time range, or you
20    /// may not see any results.
21    pub timeseries_data: &'slice [&'source Timeseries],
22
23    /// The time range to be displayed.
24    pub time_range: TimeRange,
25
26    /// Additional values that will be plotted on the chart, but which are not
27    /// part of any timeseries. These are not plotted, but are taken into
28    /// account when deciding the range of the Y axis.
29    pub additional_values: &'value [f64],
30}
31
32/// All the data necessary to generate an abstract chart from a combination of
33/// timeseries data, events and an optional target latency.
34pub struct CombinedSourceData<'source, 'slice> {
35    /// The type of stacking to apply to the chart.
36    ///
37    /// **Warning:** This property is accepted for consistency, but setting it
38    /// to anything except [GraphType::Line] will cause the events to be
39    /// ignored.
40    pub graph_type: GraphType,
41
42    /// The type of stacking to apply to the chart.
43    pub stacking_type: StackingType,
44
45    /// Array of timeseries data to display in the chart.
46    ///
47    /// Make sure the timeseries contains data for the given time range, or you
48    /// may not see any results.
49    pub timeseries_data: &'slice [&'source Timeseries],
50
51    /// Array of events to display in the chart.
52    ///
53    /// Note that events will not be displayed if the `graph_type` is anything
54    /// other than [`GraphType::Line`].
55    pub events: &'slice [&'source ProviderEvent],
56
57    /// Optional target latency to display on the chart, in seconds.
58    pub target_latency: Option<f64>,
59
60    /// The time range to be displayed.
61    pub time_range: TimeRange,
62}
63
64/// Source type for series in charts that contain combined data sources.
65#[derive(Serialize)]
66#[non_exhaustive]
67#[serde(tag = "type", rename_all = "snake_case")]
68pub enum SeriesSource<'source> {
69    Timeseries(&'source Timeseries),
70    Events,
71    TargetLatency,
72}
73
74impl<'source> From<&'source Timeseries> for SeriesSource<'source> {
75    fn from(value: &'source Timeseries) -> Self {
76        Self::Timeseries(value)
77    }
78}
79
80/// Source type for points in charts that contain combined data sources.
81#[derive(Serialize)]
82#[non_exhaustive]
83#[serde(tag = "type", rename_all = "snake_case")]
84pub enum PointSource<'source> {
85    Metric(&'source Metric),
86    Event(&'source ProviderEvent),
87    None,
88}
89
90impl<'source> From<&'source Metric> for PointSource<'source> {
91    fn from(value: &'source Metric) -> Self {
92        Self::Metric(value)
93    }
94}
95
96impl<'source> From<MondrianChart<&'source Timeseries, &'source Metric>>
97    for MondrianChart<SeriesSource<'source>, PointSource<'source>>
98{
99    fn from(value: MondrianChart<&'source Timeseries, &'source Metric>) -> Self {
100        Self {
101            shape_lists: value.shape_lists.into_iter().map(ShapeList::into).collect(),
102            x_axis: value.x_axis,
103            y_axis: value.y_axis,
104        }
105    }
106}
107
108/// A map that holds arbitrary values per timestamp.
109///
110/// The keys in the map represent timestamps, while the values are generic and
111/// are calculated over all the metrics matching that timestamp.
112pub(crate) type Buckets<T> = BTreeMap<Timestamp, T>;
113
114/// Represents the minimum and maximum values inside a series of numbers.
115#[derive(Clone, Copy)]
116pub(crate) struct MinMax(pub f64, pub f64);
117
118impl MinMax {
119    pub fn from_value(value: f64) -> Self {
120        Self(value, value)
121    }
122
123    #[must_use]
124    pub fn extend_with_other(mut self, other: Self) -> Self {
125        if other.0 < self.0 {
126            self.0 = other.0;
127        }
128        if other.1 > self.1 {
129            self.1 = other.1;
130        }
131
132        self
133    }
134
135    #[must_use]
136    pub fn extend_with_value(mut self, value: f64) -> Self {
137        if value < self.0 {
138            self.0 = value;
139        } else if value > self.1 {
140            self.1 = value;
141        }
142
143        self
144    }
145}
146
147impl<'source> From<ShapeList<&'source Timeseries, &'source Metric>>
148    for ShapeList<SeriesSource<'source>, PointSource<'source>>
149{
150    fn from(value: ShapeList<&'source Timeseries, &'source Metric>) -> Self {
151        Self {
152            shapes: value.shapes.into_iter().map(Shape::into).collect(),
153            source: value.source.into(),
154        }
155    }
156}
157
158impl<'source> From<Shape<&'source Metric>> for Shape<PointSource<'source>> {
159    fn from(other: Shape<&'source Metric>) -> Self {
160        match other {
161            Shape::Area(area) => Shape::Area(area.into()),
162            Shape::Line(line) => Shape::Line(line.into()),
163            Shape::Point(point) => Shape::Point(point.into()),
164            Shape::Rectangle(rectangle) => Shape::Rectangle(rectangle.into()),
165        }
166    }
167}
168
169impl<'source> From<Area<&'source Metric>> for Area<PointSource<'source>> {
170    fn from(value: Area<&'source Metric>) -> Self {
171        Self {
172            area_gradient_shown: None,
173            points: value.points.into_iter().map(AreaPoint::into).collect(),
174        }
175    }
176}
177
178impl<'source> From<AreaPoint<&'source Metric>> for AreaPoint<PointSource<'source>> {
179    fn from(value: AreaPoint<&'source Metric>) -> Self {
180        Self {
181            x: value.x,
182            y_min: value.y_min,
183            y_max: value.y_max,
184            source: value.source.into(),
185        }
186    }
187}
188
189impl<'source> From<Line<&'source Metric>> for Line<PointSource<'source>> {
190    fn from(value: Line<&'source Metric>) -> Self {
191        Self {
192            area_gradient_shown: None,
193            points: value.points.into_iter().map(Point::into).collect(),
194        }
195    }
196}
197
198impl<'source> From<Point<&'source Metric>> for Point<PointSource<'source>> {
199    fn from(value: Point<&'source Metric>) -> Self {
200        Self {
201            x: value.x,
202            y: value.y,
203            source: value.source.into(),
204        }
205    }
206}
207
208impl<'source> From<Rectangle<&'source Metric>> for Rectangle<PointSource<'source>> {
209    fn from(value: Rectangle<&'source Metric>) -> Self {
210        Self {
211            x: value.x,
212            y: value.y,
213            width: value.width,
214            height: value.height,
215            source: value.source.into(),
216        }
217    }
218}
219
220pub(crate) type StackedChartBuckets = Buckets<StackedChartBucketValue>;
221
222#[derive(Clone, Copy, Default)]
223pub(crate) struct StackedChartBucketValue {
224    /// Used to keep track of how much a bucket is "filled" while calculating
225    /// the area shapes.
226    pub current_y: f64,
227
228    /// The sum of all values in the bucket.
229    pub total: f64,
230}