visualizer/
visualizations.rs

1use serde::Serialize;
2use std::borrow::Cow;
3
4use crate::Visualization;
5
6// This file should provide types to build JSON documents matching
7// the schema at https://hediet.github.io/visualization/docs/visualization-data-schema.json.
8
9pub enum True {
10    True,
11}
12
13impl Default for True {
14    fn default() -> Self {
15        True::True
16    }
17}
18
19impl Serialize for True {
20    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
21    where
22        S: serde::Serializer,
23    {
24        serializer.serialize_bool(true)
25    }
26}
27
28#[derive(Serialize)]
29#[serde(rename_all = "camelCase")]
30pub struct Text<'t> {
31    kind: TextKind,
32    text: Cow<'t, str>,
33    #[serde(skip_serializing_if = "Option::is_none")]
34    file_name: Option<String>,
35}
36
37#[derive(Serialize, Default)]
38pub struct TextKind {
39    text: True,
40}
41
42impl<'t> Text<'t> {
43    pub fn new(text: Cow<'t, str>) -> Self {
44        Self {
45            text,
46            file_name: None,
47            kind: TextKind::default(),
48        }
49    }
50
51    pub fn with_file_name(&mut self, file_name: String) -> &mut Text<'t> {
52        self.file_name = Some(file_name);
53        self
54    }
55}
56
57impl<'t> Visualization for Text<'t> {
58    fn to_json(&self) -> String {
59        serde_json::to_string(self).unwrap()
60    }
61}
62
63#[derive(Serialize)]
64#[serde(rename_all = "camelCase")]
65pub struct PngImage<'t> {
66    kind: PngImageKind,
67    base64_data: Cow<'t, str>,
68}
69
70#[derive(Serialize, Default)]
71#[serde(rename_all = "camelCase")]
72pub struct PngImageKind {
73    image_png: True,
74}
75
76impl<'t> PngImage<'t> {
77    pub fn new(png_data: &[u8]) -> Self {
78        Self {
79            kind: PngImageKind::default(),
80            base64_data: base64::encode(png_data).into(),
81        }
82    }
83}
84
85impl<'t> Visualization for PngImage<'t> {
86    fn to_json(&self) -> String {
87        serde_json::to_string(self).unwrap()
88    }
89}
90
91#[derive(Serialize)]
92#[serde(rename_all = "camelCase")]
93pub struct Plotly {
94    kind: PlotlyKind,
95    data: Vec<PlotlySeries>,
96}
97
98#[derive(Serialize)]
99#[serde(rename_all = "camelCase")]
100pub struct PlotlySeries {
101    #[serde(skip_serializing_if = "Option::is_none")]
102    x: Option<Vec<f64>>,
103
104    #[serde(skip_serializing_if = "Option::is_none")]
105    y: Option<Vec<f64>>,
106
107    #[serde(skip_serializing_if = "Option::is_none")]
108    z: Option<Vec<f64>>,
109}
110
111impl Default for PlotlySeries {
112    fn default() -> PlotlySeries {
113        PlotlySeries {
114            x: None,
115            y: None,
116            z: None,
117        }
118    }
119}
120
121impl PlotlySeries {
122    pub fn set_y(&mut self, ys: Vec<f64>) -> &mut Self {
123        self.y = Some(ys);
124        self
125    }
126
127    pub fn with_y(mut self, ys: Vec<f64>) -> Self {
128        self.y = Some(ys);
129        self
130    }
131}
132
133#[derive(Serialize, Default)]
134#[serde(rename_all = "camelCase")]
135pub struct PlotlyKind {
136    plotly: True,
137}
138
139impl Plotly {
140    pub fn of_y(ys: &[f64]) -> Self {
141        Plotly {
142            kind: PlotlyKind::default(),
143            data: vec![PlotlySeries::default().with_y(ys.into())],
144        }
145    }
146}
147
148impl<'t> Visualization for Plotly {
149    fn to_json(&self) -> String {
150        serde_json::to_string(self).unwrap()
151    }
152}