plotly_fork/common/
color.rs

1//! This module provides several user interfaces for describing a color to be
2//! used throughout the rest of the library. The easiest way of describing a
3//! colour is to use a `&str` or `String`, which is simply serialized as-is and
4//! passed on to the underlying `plotly.js` library. `plotly.js` supports [`CSS
5//! color formats`], and will fallback to some default color if the color string
6//! is malformed.
7//!
8//! For a more type-safe approach, the `RGB` or `RGBA` structs can be used to
9//! construct a valid color, which will then get serialized to an appropriate
10//! string representation. Cross-browser compatible [`predefined colors`] are
11//! supported via the `NamedColor` enum.
12//!
13//! The `Color` trait is public, and so can be implemented for custom colour
14//! types. The user can then implement a valid serialization function according
15//! to their own requirements. On the whole, that should be largely unnecessary
16//! given the functionality already provided within this module.
17//!
18//! [`CSS color formats`]: https://www.w3schools.com/cssref/css_colors_legal.asp
19//! [`predefined colors`]: https://www.w3schools.com/cssref/css_colors.asp
20
21use dyn_clone::DynClone;
22use erased_serde::Serialize as ErasedSerialize;
23use serde::Serialize;
24
25/// A marker trait allowing several ways to describe a color.
26pub trait Color: DynClone + ErasedSerialize + Send + Sync + std::fmt::Debug + 'static {}
27
28dyn_clone::clone_trait_object!(Color);
29erased_serde::serialize_trait_object!(Color);
30
31impl Color for NamedColor {}
32impl Color for &'static str {}
33impl Color for String {}
34impl Color for Rgb {}
35impl Color for Rgba {}
36
37/// ColorArray is only used internally to provide a helper method for converting
38/// Vec<impl Color> to Vec<Box<dyn Color>>, as we would otherwise fall foul of
39/// the orphan rules.
40pub(crate) struct ColorArray<C: Color>(pub(crate) Vec<C>);
41
42#[allow(clippy::from_over_into)]
43impl<C: Color> Into<Vec<Box<dyn Color>>> for ColorArray<C> {
44    fn into(self) -> Vec<Box<dyn Color>> {
45        self.0
46            .into_iter()
47            .map(|c| Box::new(c) as Box<dyn Color>)
48            .collect()
49    }
50}
51
52/// A type-safe way of constructing a valid RGB color from constituent R, G and
53/// B channels.
54#[derive(Debug, Clone, Copy)]
55pub struct Rgb {
56    pub(crate) r: u8,
57    pub(crate) g: u8,
58    pub(crate) b: u8,
59}
60
61impl Rgb {
62    /// Create a new Rgb instance.
63    pub fn new(r: u8, g: u8, b: u8) -> Rgb {
64        Rgb { r, g, b }
65    }
66}
67
68impl Serialize for Rgb {
69    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
70    where
71        S: serde::Serializer,
72    {
73        serializer.serialize_str(&format!("rgb({}, {}, {})", self.r, self.g, self.b))
74    }
75}
76
77/// A type-safe way of constructing a valid RGBA color from constituent R, G, B
78/// and A channels.
79#[derive(Debug, Clone, Copy)]
80pub struct Rgba {
81    pub(crate) r: u8,
82    pub(crate) g: u8,
83    pub(crate) b: u8,
84    pub(crate) a: f64,
85}
86
87impl Rgba {
88    /// Create a new Rgba instance.
89    pub fn new(r: u8, g: u8, b: u8, a: f64) -> Rgba {
90        Rgba { r, g, b, a }
91    }
92}
93
94impl Serialize for Rgba {
95    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
96    where
97        S: serde::Serializer,
98    {
99        serializer.serialize_str(&format!(
100            "rgba({}, {}, {}, {})",
101            self.r, self.g, self.b, self.a
102        ))
103    }
104}
105
106/// Cross-browser compatible [`predefined colors`].
107///
108/// [`predefined colors`]: https://www.w3schools.com/cssref/css_colors.asp
109#[derive(Debug, Clone, Copy, Serialize)]
110#[serde(rename_all = "lowercase")]
111pub enum NamedColor {
112    AliceBlue,
113    AntiqueWhite,
114    Aqua,
115    Aquamarine,
116    Azure,
117    Beige,
118    Bisque,
119    Black,
120    BlanchedAlmond,
121    Blue,
122    BlueViolet,
123    Brown,
124    BurlyWood,
125    CadetBlue,
126    Chartreuse,
127    Chocolate,
128    Coral,
129    CornflowerBlue,
130    CornSilk,
131    Crimson,
132    Cyan,
133    DarkBlue,
134    DarkCyan,
135    DarkGoldenrod,
136    DarkGray,
137    DarkGreen,
138    DarkGrey,
139    DarkKhaki,
140    DarkMagenta,
141    DarkOliveGreen,
142    DarkOrange,
143    DarkOrchid,
144    DarkRed,
145    DarkSalmon,
146    DarkSeaGreen,
147    DarkSlateBlue,
148    DarkSlateGray,
149    DarkSlateGrey,
150    DarkTurquoise,
151    DarkViolet,
152    DeepPink,
153    DeepSkyBlue,
154    DimGray,
155    DimGrey,
156    DodgerBlue,
157    FireBrick,
158    FloralWhite,
159    ForestGreen,
160    Fuchsia,
161    Gainsboro,
162    GhostWhite,
163    Gold,
164    Goldenrod,
165    Gray,
166    Green,
167    GreenYellow,
168    Grey,
169    Honeydew,
170    HotPink,
171    IndianRed,
172    Indigo,
173    Ivory,
174    Khaki,
175    Lavender,
176    LavenderBlush,
177    LawnGreen,
178    LemonChiffon,
179    LightBlue,
180    LightCoral,
181    LightCyan,
182    LightGoldenrodYellow,
183    LightGray,
184    LightGreen,
185    LightGrey,
186    LightPink,
187    LightSalmon,
188    LightSeaGreen,
189    LightSkyBlue,
190    LightSlateGray,
191    LightSlateGrey,
192    LightSteelBlue,
193    LightYellow,
194    Lime,
195    LimeGreen,
196    Linen,
197    Magenta,
198    Maroon,
199    MediumAquamarine,
200    MediumBlue,
201    MediumOrchid,
202    MediumPurple,
203    MediumSeaGreen,
204    MediumSlateBlue,
205    MediumSpringGreen,
206    MediumTurquoise,
207    MediumVioletRed,
208    MidnightBlue,
209    MintCream,
210    MistyRose,
211    Moccasin,
212    NavajoWhite,
213    Navy,
214    OldLace,
215    Olive,
216    OliveDrab,
217    Orange,
218    OrangeRed,
219    Orchid,
220    PaleGoldenrod,
221    PaleGreen,
222    PaleTurquoise,
223    PaleVioletRed,
224    PapayaWhip,
225    PeachPuff,
226    Peru,
227    Pink,
228    Plum,
229    PowderBlue,
230    Purple,
231    RebeccaPurple,
232    Red,
233    RosyBrown,
234    RoyalBlue,
235    SaddleBrown,
236    Salmon,
237    SandyBrown,
238    SeaGreen,
239    Seashell,
240    Sienna,
241    Silver,
242    SkyBlue,
243    SlateBlue,
244    SlateGray,
245    SlateGrey,
246    Snow,
247    SpringGreen,
248    SteelBlue,
249    Tan,
250    Teal,
251    Thistle,
252    Tomato,
253    Turquoise,
254    Violet,
255    Wheat,
256    White,
257    WhiteSmoke,
258    Yellow,
259    YellowGreen,
260    Transparent,
261}
262
263#[cfg(test)]
264mod tests {
265    use serde_json::{json, to_value};
266
267    use super::*;
268
269    #[test]
270    fn test_serialize_rgb() {
271        let rgb = Rgb::new(80, 90, 100);
272        assert_eq!(to_value(rgb).unwrap(), json!("rgb(80, 90, 100)"));
273    }
274
275    #[test]
276    fn test_serialize_rgba() {
277        let rgb = Rgba::new(80, 90, 100, 0.2);
278        assert_eq!(to_value(rgb).unwrap(), json!("rgba(80, 90, 100, 0.2)"));
279    }
280
281    #[test]
282    fn test_serialize_str() {
283        let color = "any_arbitrary_string";
284        assert_eq!(to_value(color).unwrap(), json!("any_arbitrary_string"));
285    }
286
287    #[test]
288    fn test_serialize_string() {
289        let color = "any_arbitrary_string".to_string();
290        assert_eq!(to_value(color).unwrap(), json!("any_arbitrary_string"));
291    }
292
293    #[test]
294    #[rustfmt::skip]
295    fn test_serialize_named_color() {
296        assert_eq!(to_value(NamedColor::AliceBlue).unwrap(), json!("aliceblue"));
297        assert_eq!(to_value(NamedColor::AntiqueWhite).unwrap(), json!("antiquewhite"));
298        assert_eq!(to_value(NamedColor::Aqua).unwrap(), json!("aqua"));
299        assert_eq!(to_value(NamedColor::Aquamarine).unwrap(), json!("aquamarine"));
300        assert_eq!(to_value(NamedColor::Azure).unwrap(), json!("azure"));
301        assert_eq!(to_value(NamedColor::Beige).unwrap(), json!("beige"));
302        assert_eq!(to_value(NamedColor::Bisque).unwrap(), json!("bisque"));
303        assert_eq!(to_value(NamedColor::Black).unwrap(), json!("black"));
304        assert_eq!(to_value(NamedColor::BlanchedAlmond).unwrap(), json!("blanchedalmond"));
305        assert_eq!(to_value(NamedColor::Blue).unwrap(), json!("blue"));
306        assert_eq!(to_value(NamedColor::BlueViolet).unwrap(), json!("blueviolet"));
307        assert_eq!(to_value(NamedColor::Brown).unwrap(), json!("brown"));
308        assert_eq!(to_value(NamedColor::BurlyWood).unwrap(), json!("burlywood"));
309        assert_eq!(to_value(NamedColor::CadetBlue).unwrap(), json!("cadetblue"));
310        assert_eq!(to_value(NamedColor::Chartreuse).unwrap(), json!("chartreuse"));
311        assert_eq!(to_value(NamedColor::Chocolate).unwrap(), json!("chocolate"));
312        assert_eq!(to_value(NamedColor::Coral).unwrap(), json!("coral"));
313        assert_eq!(to_value(NamedColor::CornflowerBlue).unwrap(), json!("cornflowerblue"));
314        assert_eq!(to_value(NamedColor::CornSilk).unwrap(), json!("cornsilk"));
315        assert_eq!(to_value(NamedColor::Crimson).unwrap(), json!("crimson"));
316        assert_eq!(to_value(NamedColor::Cyan).unwrap(), json!("cyan"));
317        assert_eq!(to_value(NamedColor::DarkBlue).unwrap(), json!("darkblue"));
318        assert_eq!(to_value(NamedColor::DarkCyan).unwrap(), json!("darkcyan"));
319        assert_eq!(to_value(NamedColor::DarkGoldenrod).unwrap(), json!("darkgoldenrod"));
320        assert_eq!(to_value(NamedColor::DarkGray).unwrap(), json!("darkgray"));
321        assert_eq!(to_value(NamedColor::DarkGrey).unwrap(), json!("darkgrey"));
322        assert_eq!(to_value(NamedColor::DarkGreen).unwrap(), json!("darkgreen"));
323        assert_eq!(to_value(NamedColor::DarkOrange).unwrap(), json!("darkorange"));
324        assert_eq!(to_value(NamedColor::DarkOrchid).unwrap(), json!("darkorchid"));
325        assert_eq!(to_value(NamedColor::DarkRed).unwrap(), json!("darkred"));
326        assert_eq!(to_value(NamedColor::DarkSalmon).unwrap(), json!("darksalmon"));
327        assert_eq!(to_value(NamedColor::DarkSeaGreen).unwrap(), json!("darkseagreen"));
328        assert_eq!(to_value(NamedColor::DarkSlateBlue).unwrap(), json!("darkslateblue"));
329        assert_eq!(to_value(NamedColor::DarkSlateGray).unwrap(), json!("darkslategray"));
330        assert_eq!(to_value(NamedColor::DarkSlateGrey).unwrap(), json!("darkslategrey"));
331        assert_eq!(to_value(NamedColor::DarkTurquoise).unwrap(), json!("darkturquoise"));
332        assert_eq!(to_value(NamedColor::DarkViolet).unwrap(), json!("darkviolet"));
333        assert_eq!(to_value(NamedColor::DeepPink).unwrap(), json!("deeppink"));
334        assert_eq!(to_value(NamedColor::DeepSkyBlue).unwrap(), json!("deepskyblue"));
335        assert_eq!(to_value(NamedColor::DimGray).unwrap(), json!("dimgray"));
336        assert_eq!(to_value(NamedColor::DimGrey).unwrap(), json!("dimgrey"));
337        assert_eq!(to_value(NamedColor::DodgerBlue).unwrap(), json!("dodgerblue"));
338        assert_eq!(to_value(NamedColor::FireBrick).unwrap(), json!("firebrick"));
339        assert_eq!(to_value(NamedColor::FloralWhite).unwrap(), json!("floralwhite"));
340        assert_eq!(to_value(NamedColor::ForestGreen).unwrap(), json!("forestgreen"));
341        assert_eq!(to_value(NamedColor::Fuchsia).unwrap(), json!("fuchsia"));
342        assert_eq!(to_value(NamedColor::Gainsboro).unwrap(), json!("gainsboro"));
343        assert_eq!(to_value(NamedColor::GhostWhite).unwrap(), json!("ghostwhite"));
344        assert_eq!(to_value(NamedColor::Gold).unwrap(), json!("gold"));
345        assert_eq!(to_value(NamedColor::Goldenrod).unwrap(), json!("goldenrod"));
346        assert_eq!(to_value(NamedColor::Gray).unwrap(), json!("gray"));
347        assert_eq!(to_value(NamedColor::Grey).unwrap(), json!("grey"));
348        assert_eq!(to_value(NamedColor::Green).unwrap(), json!("green"));
349        assert_eq!(to_value(NamedColor::GreenYellow).unwrap(), json!("greenyellow"));
350        assert_eq!(to_value(NamedColor::Honeydew).unwrap(), json!("honeydew"));
351        assert_eq!(to_value(NamedColor::HotPink).unwrap(), json!("hotpink"));
352        assert_eq!(to_value(NamedColor::IndianRed).unwrap(), json!("indianred"));
353        assert_eq!(to_value(NamedColor::Indigo).unwrap(), json!("indigo"));
354        assert_eq!(to_value(NamedColor::Ivory).unwrap(), json!("ivory"));
355        assert_eq!(to_value(NamedColor::Khaki).unwrap(), json!("khaki"));
356        assert_eq!(to_value(NamedColor::Lavender).unwrap(), json!("lavender"));
357        assert_eq!(to_value(NamedColor::LavenderBlush).unwrap(), json!("lavenderblush"));
358        assert_eq!(to_value(NamedColor::LawnGreen).unwrap(), json!("lawngreen"));
359        assert_eq!(to_value(NamedColor::LemonChiffon).unwrap(), json!("lemonchiffon"));
360        assert_eq!(to_value(NamedColor::LightBlue).unwrap(), json!("lightblue"));
361        assert_eq!(to_value(NamedColor::LightCoral).unwrap(), json!("lightcoral"));
362        assert_eq!(to_value(NamedColor::LightCyan).unwrap(), json!("lightcyan"));
363        assert_eq!(to_value(NamedColor::LightGoldenrodYellow).unwrap(), json!("lightgoldenrodyellow"));
364        assert_eq!(to_value(NamedColor::LightGray).unwrap(), json!("lightgray"));
365        assert_eq!(to_value(NamedColor::LightGrey).unwrap(), json!("lightgrey"));
366        assert_eq!(to_value(NamedColor::LightGreen).unwrap(), json!("lightgreen"));
367        assert_eq!(to_value(NamedColor::LightPink).unwrap(), json!("lightpink"));
368        assert_eq!(to_value(NamedColor::LightSalmon).unwrap(), json!("lightsalmon"));
369        assert_eq!(to_value(NamedColor::LightSeaGreen).unwrap(), json!("lightseagreen"));
370        assert_eq!(to_value(NamedColor::LightSkyBlue).unwrap(), json!("lightskyblue"));
371        assert_eq!(to_value(NamedColor::LightSlateGray).unwrap(), json!("lightslategray"));
372        assert_eq!(to_value(NamedColor::LightSlateGrey).unwrap(), json!("lightslategrey"));
373        assert_eq!(to_value(NamedColor::LightSteelBlue).unwrap(), json!("lightsteelblue"));
374        assert_eq!(to_value(NamedColor::LightYellow).unwrap(), json!("lightyellow"));
375        assert_eq!(to_value(NamedColor::Lime).unwrap(), json!("lime"));
376        assert_eq!(to_value(NamedColor::LimeGreen).unwrap(), json!("limegreen"));
377        assert_eq!(to_value(NamedColor::Linen).unwrap(), json!("linen"));
378        assert_eq!(to_value(NamedColor::Magenta).unwrap(), json!("magenta"));
379        assert_eq!(to_value(NamedColor::Maroon).unwrap(), json!("maroon"));
380        assert_eq!(to_value(NamedColor::MediumAquamarine).unwrap(), json!("mediumaquamarine"));
381        assert_eq!(to_value(NamedColor::MediumBlue).unwrap(), json!("mediumblue"));
382        assert_eq!(to_value(NamedColor::MediumOrchid).unwrap(), json!("mediumorchid"));
383        assert_eq!(to_value(NamedColor::MediumPurple).unwrap(), json!("mediumpurple"));
384        assert_eq!(to_value(NamedColor::MediumSeaGreen).unwrap(), json!("mediumseagreen"));
385        assert_eq!(to_value(NamedColor::MediumSlateBlue).unwrap(), json!("mediumslateblue"));
386        assert_eq!(to_value(NamedColor::MediumSpringGreen).unwrap(), json!("mediumspringgreen"));
387        assert_eq!(to_value(NamedColor::MediumTurquoise).unwrap(), json!("mediumturquoise"));
388        assert_eq!(to_value(NamedColor::MediumVioletRed).unwrap(), json!("mediumvioletred"));
389        assert_eq!(to_value(NamedColor::MidnightBlue).unwrap(), json!("midnightblue"));
390        assert_eq!(to_value(NamedColor::MintCream).unwrap(), json!("mintcream"));
391        assert_eq!(to_value(NamedColor::MistyRose).unwrap(), json!("mistyrose"));
392        assert_eq!(to_value(NamedColor::Moccasin).unwrap(), json!("moccasin"));
393        assert_eq!(to_value(NamedColor::NavajoWhite).unwrap(), json!("navajowhite"));
394        assert_eq!(to_value(NamedColor::Navy).unwrap(), json!("navy"));
395        assert_eq!(to_value(NamedColor::OldLace).unwrap(), json!("oldlace"));
396        assert_eq!(to_value(NamedColor::Olive).unwrap(), json!("olive"));
397        assert_eq!(to_value(NamedColor::OliveDrab).unwrap(), json!("olivedrab"));
398        assert_eq!(to_value(NamedColor::Orange).unwrap(), json!("orange"));
399        assert_eq!(to_value(NamedColor::OrangeRed).unwrap(), json!("orangered"));
400        assert_eq!(to_value(NamedColor::Orchid).unwrap(), json!("orchid"));
401        assert_eq!(to_value(NamedColor::PaleGoldenrod).unwrap(), json!("palegoldenrod"));
402        assert_eq!(to_value(NamedColor::PaleGreen).unwrap(), json!("palegreen"));
403        assert_eq!(to_value(NamedColor::PaleTurquoise).unwrap(), json!("paleturquoise"));
404        assert_eq!(to_value(NamedColor::PaleVioletRed).unwrap(), json!("palevioletred"));
405        assert_eq!(to_value(NamedColor::PapayaWhip).unwrap(), json!("papayawhip"));
406        assert_eq!(to_value(NamedColor::PeachPuff).unwrap(), json!("peachpuff"));
407        assert_eq!(to_value(NamedColor::Peru).unwrap(), json!("peru"));
408        assert_eq!(to_value(NamedColor::Pink).unwrap(), json!("pink"));
409        assert_eq!(to_value(NamedColor::Plum).unwrap(), json!("plum"));
410        assert_eq!(to_value(NamedColor::PowderBlue).unwrap(), json!("powderblue"));
411        assert_eq!(to_value(NamedColor::Purple).unwrap(), json!("purple"));
412        assert_eq!(to_value(NamedColor::RebeccaPurple).unwrap(), json!("rebeccapurple"));
413        assert_eq!(to_value(NamedColor::Red).unwrap(), json!("red"));
414        assert_eq!(to_value(NamedColor::RosyBrown).unwrap(), json!("rosybrown"));
415        assert_eq!(to_value(NamedColor::RoyalBlue).unwrap(), json!("royalblue"));
416        assert_eq!(to_value(NamedColor::SaddleBrown).unwrap(), json!("saddlebrown"));
417        assert_eq!(to_value(NamedColor::Salmon).unwrap(), json!("salmon"));
418        assert_eq!(to_value(NamedColor::SandyBrown).unwrap(), json!("sandybrown"));
419        assert_eq!(to_value(NamedColor::SeaGreen).unwrap(), json!("seagreen"));
420        assert_eq!(to_value(NamedColor::Seashell).unwrap(), json!("seashell"));
421        assert_eq!(to_value(NamedColor::Sienna).unwrap(), json!("sienna"));
422        assert_eq!(to_value(NamedColor::Silver).unwrap(), json!("silver"));
423        assert_eq!(to_value(NamedColor::SkyBlue).unwrap(), json!("skyblue"));
424        assert_eq!(to_value(NamedColor::SlateBlue).unwrap(), json!("slateblue"));
425        assert_eq!(to_value(NamedColor::SlateGray).unwrap(), json!("slategray"));
426        assert_eq!(to_value(NamedColor::SlateGrey).unwrap(), json!("slategrey"));
427        assert_eq!(to_value(NamedColor::Snow).unwrap(), json!("snow"));
428        assert_eq!(to_value(NamedColor::SpringGreen).unwrap(), json!("springgreen"));
429        assert_eq!(to_value(NamedColor::SteelBlue).unwrap(), json!("steelblue"));
430        assert_eq!(to_value(NamedColor::Tan).unwrap(), json!("tan"));
431        assert_eq!(to_value(NamedColor::Teal).unwrap(), json!("teal"));
432        assert_eq!(to_value(NamedColor::Thistle).unwrap(), json!("thistle"));
433        assert_eq!(to_value(NamedColor::Tomato).unwrap(), json!("tomato"));
434        assert_eq!(to_value(NamedColor::Turquoise).unwrap(), json!("turquoise"));
435        assert_eq!(to_value(NamedColor::Violet).unwrap(), json!("violet"));
436        assert_eq!(to_value(NamedColor::Wheat).unwrap(), json!("wheat"));
437        assert_eq!(to_value(NamedColor::White).unwrap(), json!("white"));
438        assert_eq!(to_value(NamedColor::WhiteSmoke).unwrap(), json!("whitesmoke"));
439        assert_eq!(to_value(NamedColor::Yellow).unwrap(), json!("yellow"));
440        assert_eq!(to_value(NamedColor::YellowGreen).unwrap(), json!("yellowgreen"));
441        assert_eq!(to_value(NamedColor::Transparent).unwrap(), json!("transparent"));
442    }
443}