1#[derive(Debug, thiserror::Error)]
5pub enum ColorCreationError {
6 #[error("parse error: {0}")]
8 ParseError(String),
9}
10
11#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
25pub struct RGBAColor {
26 pub r: u8,
28 pub g: u8,
30 pub b: u8,
32 pub a: u8,
34}
35
36impl RGBAColor {
37 pub fn new(c: impl Into<RGBAColor>) -> Self {
39 c.into()
40 }
41
42 pub fn try_new(
45 c: impl TryInto<RGBAColor, Error = ColorCreationError>,
46 ) -> Result<Self, ColorCreationError> {
47 c.try_into()
48 }
49
50 pub const fn add(&self, other: &Self) -> Self {
52 Self {
53 r: self.r.saturating_add(other.r),
54 g: self.g.saturating_add(other.g),
55 b: self.b.saturating_add(other.b),
56 a: self.a.saturating_add(other.a),
57 }
58 }
59
60 pub const fn sub(&self, other: &Self) -> Self {
62 Self {
63 r: self.r.saturating_sub(other.r),
64 g: self.g.saturating_sub(other.g),
65 b: self.b.saturating_sub(other.b),
66 a: self.a.saturating_sub(other.a),
67 }
68 }
69
70 pub const fn mul(&self, other: &Self) -> Self {
72 Self {
73 r: self.r.saturating_mul(other.r),
74 g: self.g.saturating_mul(other.g),
75 b: self.b.saturating_mul(other.b),
76 a: self.a.saturating_mul(other.a),
77 }
78 }
79
80 pub const fn colorize(&self, other: &Self) -> Self {
82 let red = 255u8.wrapping_sub(other.r);
83 let green = 255u8.wrapping_sub(other.g);
84 let blue = 255u8.wrapping_sub(other.b);
85
86 Self {
87 r: self.r.saturating_sub(red),
88 g: self.r.saturating_sub(green),
89 b: self.r.saturating_sub(blue),
90 a: self.a,
91 }
92 }
93}
94
95impl Default for RGBAColor {
96 fn default() -> Self {
97 Self {
98 r: 0,
99 g: 0,
100 b: 0,
101 a: 255,
102 }
103 }
104}
105
106impl From<u32> for RGBAColor {
107 fn from(value: u32) -> Self {
108 if value > 0xFFFFFF {
112 Self {
113 r: ((value >> 24) & 0xFF) as u8,
114 g: ((value >> 16) & 0xFF) as u8,
115 b: ((value >> 8) & 0xFF) as u8,
116 a: (value & 0xFF) as u8,
117 }
118 } else {
119 Self {
120 r: ((value >> 16) & 0xFF) as u8,
121 g: ((value >> 8) & 0xFF) as u8,
122 b: (value & 0xFF) as u8,
123 a: 255,
124 }
125 }
126 }
127}
128
129impl TryFrom<&str> for RGBAColor {
130 type Error = ColorCreationError;
131
132 fn try_from(value: &str) -> Result<Self, Self::Error> {
133 let s = value.strip_prefix('#').unwrap_or(value);
134
135 u32::from_str_radix(s, 16)
136 .map_err(|e| ColorCreationError::ParseError(e.to_string()))
137 .map(|v| v.into())
138 }
139}
140
141impl TryFrom<String> for RGBAColor {
142 type Error = ColorCreationError;
143
144 fn try_from(value: String) -> Result<Self, Self::Error> {
145 Self::try_new(&*value)
146 }
147}
148
149impl From<[u8; 3]> for RGBAColor {
150 fn from(value: [u8; 3]) -> Self {
151 Self {
152 r: value[0],
153 g: value[1],
154 b: value[2],
155 a: 255,
156 }
157 }
158}
159
160impl From<[u8; 4]> for RGBAColor {
161 fn from(value: [u8; 4]) -> Self {
162 Self {
163 r: value[0],
164 g: value[1],
165 b: value[2],
166 a: value[3],
167 }
168 }
169}
170
171impl From<(u8, u8, u8)> for RGBAColor {
172 fn from(value: (u8, u8, u8)) -> Self {
173 Self {
174 r: value.0,
175 g: value.1,
176 b: value.2,
177 a: 255,
178 }
179 }
180}
181
182impl From<(u8, u8, u8, u8)> for RGBAColor {
183 fn from(value: (u8, u8, u8, u8)) -> Self {
184 Self {
185 r: value.0,
186 g: value.1,
187 b: value.2,
188 a: value.3,
189 }
190 }
191}