1use std::{fmt, ops};
2
3use crate::{EQ_GRANULARITY, Factor, FactorPercent, ParseIntCompositeError, about_eq, about_eq_hash, about_eq_ord};
4
5#[repr(C)]
13#[derive(Default, Copy, Clone, serde::Serialize, serde::Deserialize)]
14pub struct Rgba {
15 pub red: f32,
17 pub green: f32,
19 pub blue: f32,
21 pub alpha: f32,
23}
24impl PartialEq for Rgba {
25 fn eq(&self, other: &Self) -> bool {
26 about_eq(self.red, other.red, EQ_GRANULARITY)
27 && about_eq(self.green, other.green, EQ_GRANULARITY)
28 && about_eq(self.blue, other.blue, EQ_GRANULARITY)
29 && about_eq(self.alpha, other.alpha, EQ_GRANULARITY)
30 }
31}
32impl Eq for Rgba {}
33impl PartialOrd for Rgba {
34 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
35 Some(self.cmp(other))
36 }
37}
38impl Ord for Rgba {
39 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
40 about_eq_ord(self.red, other.red, EQ_GRANULARITY)
41 .cmp(&about_eq_ord(self.green, other.green, EQ_GRANULARITY))
42 .cmp(&about_eq_ord(self.blue, other.blue, EQ_GRANULARITY))
43 .cmp(&about_eq_ord(self.alpha, other.alpha, EQ_GRANULARITY))
44 }
45}
46impl std::hash::Hash for Rgba {
47 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
48 about_eq_hash(self.red, EQ_GRANULARITY, state);
49 about_eq_hash(self.green, EQ_GRANULARITY, state);
50 about_eq_hash(self.blue, EQ_GRANULARITY, state);
51 about_eq_hash(self.alpha, EQ_GRANULARITY, state);
52 }
53}
54impl Rgba {
55 pub fn new<C: Into<RgbaComponent>, A: Into<RgbaComponent>>(red: C, green: C, blue: C, alpha: A) -> Rgba {
57 Rgba {
58 red: red.into().0,
59 green: green.into().0,
60 blue: blue.into().0,
61 alpha: alpha.into().0,
62 }
63 }
64
65 pub fn set_red<R: Into<RgbaComponent>>(&mut self, red: R) {
67 self.red = red.into().0
68 }
69
70 pub fn set_green<G: Into<RgbaComponent>>(&mut self, green: G) {
72 self.green = green.into().0
73 }
74
75 pub fn set_blue<B: Into<RgbaComponent>>(&mut self, blue: B) {
77 self.blue = blue.into().0
78 }
79
80 pub fn set_alpha<A: Into<RgbaComponent>>(&mut self, alpha: A) {
82 self.alpha = alpha.into().0
83 }
84
85 pub fn with_red<R: Into<RgbaComponent>>(mut self, red: R) -> Self {
87 self.set_red(red);
88 self
89 }
90
91 pub fn with_green<R: Into<RgbaComponent>>(mut self, green: R) -> Self {
93 self.set_green(green);
94 self
95 }
96
97 pub fn with_blue<B: Into<RgbaComponent>>(mut self, blue: B) -> Self {
99 self.set_blue(blue);
100 self
101 }
102
103 pub fn with_alpha<A: Into<RgbaComponent>>(mut self, alpha: A) -> Self {
105 self.set_alpha(alpha);
106 self
107 }
108
109 pub fn transparent(self) -> Self {
111 self.with_alpha(0.0)
112 }
113
114 pub fn to_bytes(self) -> [u8; 4] {
116 [
117 (self.red * 255.0) as u8,
118 (self.green * 255.0) as u8,
119 (self.blue * 255.0) as u8,
120 (self.alpha * 255.0) as u8,
121 ]
122 }
123
124 pub fn to_bgra_bytes(self) -> [u8; 4] {
126 [
127 (self.blue * 255.0) as u8,
128 (self.green * 255.0) as u8,
129 (self.red * 255.0) as u8,
130 (self.alpha * 255.0) as u8,
131 ]
132 }
133
134 fn is_valid(self) -> bool {
136 self.red.is_finite() && self.blue.is_finite() && self.green.is_finite() && self.alpha.is_finite()
137 }
138}
139impl fmt::Debug for Rgba {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 if f.alternate() || !self.is_valid() {
142 f.debug_struct("Rgba")
143 .field("red", &self.red)
144 .field("green", &self.green)
145 .field("blue", &self.blue)
146 .field("alpha", &self.alpha)
147 .finish()
148 } else {
149 fn i(n: f32) -> u8 {
150 (clamp_normal(n) * 255.0).round() as u8
151 }
152 let a = i(self.alpha);
153 if a == 255 {
154 write!(f, "rgb({}, {}, {})", i(self.red), i(self.green), i(self.blue))
155 } else {
156 write!(f, "rgba({}, {}, {}, {})", i(self.red), i(self.green), i(self.blue), a)
157 }
158 }
159 }
160}
161impl fmt::Display for Rgba {
162 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163 fn i(n: f32) -> u32 {
164 (clamp_normal(n) * 255.0).round() as u32
165 }
166
167 let mut rgb: u32 = 0;
168 rgb |= i(self.red) << 16;
169 rgb |= i(self.green) << 8;
170 rgb |= i(self.blue);
171
172 let a = i(self.alpha);
173 if a == 255 {
174 write!(f, "#{rgb:0>6X}")
175 } else {
176 let rgba = (rgb << 8) | a;
177 write!(f, "#{rgba:0>8X}")
178 }
179 }
180}
181impl ops::Add<Self> for Rgba {
182 type Output = Self;
183
184 fn add(self, rhs: Self) -> Self::Output {
185 Rgba {
186 red: self.red + rhs.red,
187 green: self.green + rhs.green,
188 blue: self.blue + rhs.blue,
189 alpha: self.alpha + rhs.alpha,
190 }
191 }
192}
193impl ops::AddAssign<Self> for Rgba {
194 fn add_assign(&mut self, rhs: Self) {
195 *self = *self + rhs;
196 }
197}
198impl ops::Sub<Self> for Rgba {
199 type Output = Self;
200
201 fn sub(self, rhs: Self) -> Self::Output {
202 Rgba {
203 red: self.red - rhs.red,
204 green: self.green - rhs.green,
205 blue: self.blue - rhs.blue,
206 alpha: self.alpha - rhs.alpha,
207 }
208 }
209}
210impl ops::SubAssign<Self> for Rgba {
211 fn sub_assign(&mut self, rhs: Self) {
212 *self = *self - rhs;
213 }
214}
215
216fn clamp_normal(i: f32) -> f32 {
218 i.clamp(0.0, 1.0)
219}
220
221#[derive(Clone, Copy)]
233pub struct RgbaComponent(pub f32);
234impl From<f32> for RgbaComponent {
236 fn from(f: f32) -> Self {
237 if f.is_finite() {
238 RgbaComponent(f)
239 } else {
240 #[cfg(debug_assertions)]
241 panic!("rgba color component is not finite, {f}");
242
243 #[cfg(not(debug_assertions))]
244 if f.is_nan() {
245 RgbaComponent(0.0)
246 } else if f.is_infinite() {
247 if f.is_sign_positive() {
248 RgbaComponent(1.0)
249 } else {
250 RgbaComponent(0.0)
251 }
252 } else {
253 unreachable!()
254 }
255 }
256 }
257}
258impl From<f64> for RgbaComponent {
260 fn from(f: f64) -> Self {
261 RgbaComponent::from(f as f32)
262 }
263}
264impl From<u8> for RgbaComponent {
266 fn from(u: u8) -> Self {
267 RgbaComponent::from(f32::from(u) / 255.)
268 }
269}
270impl From<FactorPercent> for RgbaComponent {
272 fn from(p: FactorPercent) -> Self {
273 RgbaComponent::from(p.0 / 100.)
274 }
275}
276impl From<Factor> for RgbaComponent {
278 fn from(f: Factor) -> Self {
279 RgbaComponent::from(f.0)
280 }
281}
282
283impl std::str::FromStr for Rgba {
285 type Err = ParseIntCompositeError;
286
287 fn from_str(s: &str) -> Result<Self, Self::Err> {
288 if let Some(hex) = s.strip_prefix('#') {
289 let mut parser = HexComponentParser::new(hex);
290 let rgba = Rgba::new(parser.next()?, parser.next()?, parser.next()?, parser.next_or(255)?);
291 parser.end()?;
292 Ok(rgba)
293 } else if let Some(rgba) = s.strip_prefix("rgba(")
294 && let Some(rgba) = rgba.strip_suffix(')')
295 {
296 let mut parser = ComponentParser::new(rgba);
297 let rgba = Rgba::new(parser.next()?, parser.next()?, parser.next()?, parser.next()?);
298 parser.end()?;
299 Ok(rgba)
300 } else if let Some(rgb) = s.strip_prefix("rgb(")
301 && let Some(rgb) = rgb.strip_suffix(')')
302 {
303 let mut parser = ComponentParser::new(rgb);
304 let rgba = Rgba::new(parser.next()?, parser.next()?, parser.next()?, 255);
305 parser.end()?;
306 Ok(rgba)
307 } else {
308 Err(ParseIntCompositeError::UnknownFormat)
309 }
310 }
311}
312struct ComponentParser<'s> {
313 s: std::str::Split<'s, char>,
314}
315impl<'s> ComponentParser<'s> {
316 fn new(s: &'s str) -> Self {
317 Self { s: s.split(',') }
318 }
319
320 fn next(&mut self) -> Result<u8, ParseIntCompositeError> {
321 Ok(self.s.next().ok_or(ParseIntCompositeError::MissingComponent)?.trim().parse()?)
322 }
323
324 fn end(mut self) -> Result<(), ParseIntCompositeError> {
325 if self.s.next().is_some() {
326 Err(ParseIntCompositeError::ExtraComponent)
327 } else {
328 Ok(())
329 }
330 }
331}
332struct HexComponentParser<'s> {
333 s: &'s str,
334}
335impl<'s> HexComponentParser<'s> {
336 fn new(s: &'s str) -> Self {
337 Self { s }
338 }
339
340 fn next(&mut self) -> Result<u8, ParseIntCompositeError> {
341 if self.s.len() < 2 {
342 Err(ParseIntCompositeError::MissingComponent)
343 } else {
344 let c = &self.s[..2];
345 self.s = &self.s[2..];
346 Ok(u8::from_str_radix(c, 16)?)
347 }
348 }
349
350 fn next_or(&mut self, c: u8) -> Result<u8, ParseIntCompositeError> {
351 if self.s.is_empty() { Ok(c) } else { self.next() }
352 }
353
354 fn end(self) -> Result<(), ParseIntCompositeError> {
355 if self.s.is_empty() {
356 Ok(())
357 } else {
358 Err(ParseIntCompositeError::ExtraComponent)
359 }
360 }
361}