charming/element/
color.rs

1use serde::de::{self, Deserializer, MapAccess, Unexpected, Visitor};
2use serde::ser::{SerializeStruct, Serializer};
3use serde::{Deserialize, Serialize};
4use std::fmt;
5
6#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Copy)]
7#[serde(rename_all = "snake_case")]
8pub enum ColorBy {
9    Series,
10    Data,
11}
12
13impl From<&str> for ColorBy {
14    fn from(s: &str) -> Self {
15        match s {
16            "series" => Self::Series,
17            "data" => Self::Data,
18            _ => panic!("Invalid ColorBy"),
19        }
20    }
21}
22
23#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone)]
24pub struct ColorStop {
25    offset: f64,
26    color: String,
27}
28
29impl ColorStop {
30    pub fn new<F: Into<f64>, S: Into<String>>(offset: F, color: S) -> Self {
31        Self {
32            offset: offset.into(),
33            color: color.into(),
34        }
35    }
36}
37
38#[derive(Debug, PartialEq, PartialOrd, Clone)]
39pub enum Color {
40    Value(String),
41    LinearGradient {
42        x: f64,
43        y: f64,
44        x2: f64,
45        y2: f64,
46        color_stops: Vec<ColorStop>,
47    },
48    RadialGradient {
49        x: f64,
50        y: f64,
51        r: f64,
52        color_stops: Vec<ColorStop>,
53    },
54}
55
56impl Serialize for Color {
57    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
58    where
59        S: Serializer,
60    {
61        match self {
62            Color::Value(rgb) => serializer.serialize_str(rgb),
63            Color::LinearGradient {
64                x,
65                y,
66                x2,
67                y2,
68                color_stops,
69            } => {
70                let mut s = serializer.serialize_struct("LinearGradient", 5)?;
71                s.serialize_field("type", "linear")?;
72                s.serialize_field("x", x)?;
73                s.serialize_field("y", y)?;
74                s.serialize_field("x2", x2)?;
75                s.serialize_field("y2", y2)?;
76                s.serialize_field("colorStops", color_stops)?;
77                s.end()
78            }
79            Color::RadialGradient {
80                x,
81                y,
82                r,
83                color_stops,
84            } => {
85                let mut s = serializer.serialize_struct("RadialGradient", 4)?;
86                s.serialize_field("type", "radial")?;
87                s.serialize_field("x", x)?;
88                s.serialize_field("y", y)?;
89                s.serialize_field("r", r)?;
90                s.serialize_field("colorStops", color_stops)?;
91                s.end()
92            }
93        }
94    }
95}
96
97impl<'de> Deserialize<'de> for Color {
98    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
99    where
100        D: Deserializer<'de>,
101    {
102        // Try to parse as a simple string first
103        struct ColorVisitor;
104
105        impl<'de> Visitor<'de> for ColorVisitor {
106            type Value = Color;
107
108            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
109                formatter.write_str("a string or a gradient object with type field")
110            }
111
112            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
113            where
114                E: de::Error,
115            {
116                Ok(Color::Value(value.to_string()))
117            }
118
119            fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
120            where
121                M: MapAccess<'de>,
122            {
123                use serde_json::Value as JsonValue;
124
125                // Deserialize the map into a generic serde_json::Map first
126                let mut temp_map = serde_json::Map::new();
127                let mut type_value = None;
128                while let Some((key, value)) = map.next_entry::<String, JsonValue>()? {
129                    if key == "type" {
130                        type_value = Some(value.clone())
131                    }
132                    temp_map.insert(key, value);
133                }
134
135                let type_value = type_value.ok_or_else(|| de::Error::missing_field("type"))?;
136
137                let type_value = type_value.as_str().ok_or_else(|| {
138                    de::Error::invalid_type(Unexpected::Other("non-string"), &"a string")
139                })?;
140
141                let temp_value = JsonValue::Object(temp_map);
142
143                match type_value {
144                    "linear" => {
145                        #[derive(Deserialize)]
146                        struct LinearGradientDef {
147                            x: f64,
148                            y: f64,
149                            x2: f64,
150                            y2: f64,
151                            #[serde(rename = "colorStops")]
152                            color_stops: Vec<ColorStop>,
153                        }
154
155                        let gradient: LinearGradientDef =
156                            serde_json::from_value(temp_value).map_err(de::Error::custom)?;
157
158                        Ok(Color::LinearGradient {
159                            x: gradient.x,
160                            y: gradient.y,
161                            x2: gradient.x2,
162                            y2: gradient.y2,
163                            color_stops: gradient.color_stops,
164                        })
165                    }
166                    "radial" => {
167                        #[derive(Deserialize)]
168                        struct RadialGradientDef {
169                            x: f64,
170                            y: f64,
171                            r: f64,
172                            #[serde(rename = "colorStops")]
173                            color_stops: Vec<ColorStop>,
174                        }
175
176                        let gradient: RadialGradientDef =
177                            serde_json::from_value(temp_value).map_err(de::Error::custom)?;
178
179                        Ok(Color::RadialGradient {
180                            x: gradient.x,
181                            y: gradient.y,
182                            r: gradient.r,
183                            color_stops: gradient.color_stops,
184                        })
185                    }
186                    other => Err(de::Error::unknown_variant(other, &["linear", "radial"])),
187                }
188            }
189        }
190
191        deserializer.deserialize_any(ColorVisitor)
192    }
193}
194
195impl From<&str> for Color {
196    fn from(s: &str) -> Self {
197        Color::Value(s.to_string())
198    }
199}
200
201impl From<String> for Color {
202    fn from(s: String) -> Self {
203        Color::Value(s)
204    }
205}