chart_js_wrapper/
common.rs1use std::fmt;
2use std::fmt::Write;
3use sailfish::RenderError;
4use sailfish::runtime::{Buffer, Render};
5use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
6use serde::de::Visitor;
7
8#[derive(Debug, Clone, Copy, PartialEq)]
10pub struct Percent(pub f32);
11
12impl Serialize for Percent {
13 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
14 where S: Serializer {
15 let s = format!("{}%", self.0);
16 serializer.serialize_str(&s)
17 }
18}
19
20impl<'de> Deserialize<'de> for Percent {
21 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
22 where D: Deserializer<'de> {
23 let s = String::deserialize(deserializer)?;
24 let trimmed = s.trim_end_matches('%');
25 trimmed.parse::<f32>()
26 .map(Percent)
27 .map_err(de::Error::custom)
28 }
29}
30
31
32#[derive(Debug, Clone, Copy, PartialEq)]
34pub struct Pixels(pub usize);
35
36impl Serialize for Pixels {
37 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
38 where S: Serializer {
39 let s = format!("{}px", self.0);
40 serializer.serialize_str(&s)
41 }
42}
43
44impl<'de> Deserialize<'de> for Pixels {
45 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
46 where D: Deserializer<'de> {
47 let s = String::deserialize(deserializer)?;
48 let trimmed = s.trim_end_matches("px");
49 trimmed.parse::<usize>()
50 .map(Pixels)
51 .map_err(de::Error::custom)
52 }
53}
54
55
56#[derive(Serialize, Deserialize, Debug, Clone)]
57#[serde(untagged)]
58pub enum Size{
59 Percent(Percent),
60 Pixel(Pixels)
61}
62
63
64impl Render for Size{
65 fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
66 b.write_str(&self.to_string())?;
67 Ok(())
68 }
69}
70
71impl Size{
72 pub fn to_string(&self) -> String{
73 match self{
74 Size::Percent(p) => format!("{}%", p.0),
75 Size::Pixel(p) => format!("{}px", p.0)
76 }
77 }
78
79 pub fn percent(f: f32) -> Self{
80 Size::Percent(Percent(f))
81 }
82
83 pub fn pixels(f: usize) -> Self{
84 Size::Pixel(Pixels(f))
85 }
86
87}
88
89#[derive(Debug,Clone, PartialEq)]
90pub struct Rgb(pub u8,pub u8,pub u8);
91
92impl Serialize for Rgb {
93 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
94 where
95 S: Serializer,
96 {
97 let s = format!("rgb({}, {}, {})", self.0, self.1, self.2);
98 serializer.serialize_str(&s)
99 }
100}
101
102impl<'de> Deserialize<'de> for Rgb {
103 fn deserialize<D>(deserializer: D) -> Result<Rgb, D::Error>
104 where
105 D: Deserializer<'de>,
106 {
107 struct RgbVisitor;
108
109 impl<'de> Visitor<'de> for RgbVisitor {
110 type Value = Rgb;
111
112 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
113 formatter.write_str(r#"a string in the format "rgb(r, g, b)""#)
114 }
115
116 fn visit_str<E>(self, v: &str) -> Result<Rgb, E>
117 where
118 E: de::Error,
119 {
120 let v = v.trim();
121 if !v.starts_with("rgb(") || !v.ends_with(')') {
122 return Err(E::custom("invalid format"));
123 }
124
125 let content = &v[4..v.len() - 1]; let parts: Vec<&str> = content.split(',').map(str::trim).collect();
127 if parts.len() != 3 {
128 return Err(E::custom("expected three components"));
129 }
130
131 let r = parts[0].parse::<u8>().map_err(E::custom)?;
132 let g = parts[1].parse::<u8>().map_err(E::custom)?;
133 let b = parts[2].parse::<u8>().map_err(E::custom)?;
134
135 Ok(Rgb(r, g, b))
136 }
137 }
138
139 deserializer.deserialize_str(RgbVisitor)
140 }
141}
142
143#[derive(Serialize, Deserialize, Debug, Clone)]
144pub struct Padding {
145 #[serde(skip_serializing_if = "Option::is_none")]
146 pub top: Option<f32>,
147 #[serde(skip_serializing_if = "Option::is_none")]
148 pub bottom: Option<f32>,
149 #[serde(skip_serializing_if = "Option::is_none")]
150 pub left: Option<f32>,
151 #[serde(skip_serializing_if = "Option::is_none")]
152 pub right: Option<f32>
153}