1use std::{
2 borrow::Cow,
3 fmt,
4 ops::{Deref, DerefMut},
5};
6
7use crate::json::ToJson;
8use pathfinder_color::ColorU;
9use serde::{
10 de::{self, Unexpected},
11 Deserialize, Deserializer,
12};
13use serde_json::json;
14
15#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
16#[repr(transparent)]
17pub struct Color(ColorU);
18
19impl Color {
20 pub fn transparent_black() -> Self {
21 Self(ColorU::transparent_black())
22 }
23
24 pub fn black() -> Self {
25 Self(ColorU::black())
26 }
27
28 pub fn white() -> Self {
29 Self(ColorU::white())
30 }
31
32 pub fn red() -> Self {
33 Self(ColorU::from_u32(0xff0000ff))
34 }
35
36 pub fn green() -> Self {
37 Self(ColorU::from_u32(0x00ff00ff))
38 }
39
40 pub fn blue() -> Self {
41 Self(ColorU::from_u32(0x0000ffff))
42 }
43
44 pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
45 Self(ColorU::new(r, g, b, a))
46 }
47
48 pub fn from_u32(rgba: u32) -> Self {
49 Self(ColorU::from_u32(rgba))
50 }
51}
52
53impl<'de> Deserialize<'de> for Color {
54 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
55 where
56 D: Deserializer<'de>,
57 {
58 let literal: Cow<str> = Deserialize::deserialize(deserializer)?;
59 if let Some(digits) = literal.strip_prefix('#') {
60 if let Ok(value) = u32::from_str_radix(digits, 16) {
61 if digits.len() == 6 {
62 return Ok(Color::from_u32((value << 8) | 0xFF));
63 } else if digits.len() == 8 {
64 return Ok(Color::from_u32(value));
65 }
66 }
67 }
68 Err(de::Error::invalid_value(
69 Unexpected::Str(literal.as_ref()),
70 &"#RRGGBB[AA]",
71 ))
72 }
73}
74
75impl ToJson for Color {
76 fn to_json(&self) -> serde_json::Value {
77 json!(format!(
78 "0x{:x}{:x}{:x}{:x}",
79 self.0.r, self.0.g, self.0.b, self.0.a
80 ))
81 }
82}
83
84impl Deref for Color {
85 type Target = ColorU;
86 fn deref(&self) -> &Self::Target {
87 &self.0
88 }
89}
90
91impl DerefMut for Color {
92 fn deref_mut(&mut self) -> &mut Self::Target {
93 &mut self.0
94 }
95}
96
97impl fmt::Debug for Color {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 self.0.fmt(f)
100 }
101}