Skip to content

Commit e647027

Browse files
committed
Use Option<f32> for rgb components as well.
1 parent a2013cd commit e647027

File tree

2 files changed

+70
-85
lines changed

2 files changed

+70
-85
lines changed

src/color.rs

+67-82
Original file line numberDiff line numberDiff line change
@@ -63,101 +63,49 @@ fn normalize_hue(hue: f32) -> f32 {
6363
#[repr(C)]
6464
pub struct RGBA {
6565
/// The red component.
66-
pub red: u8,
66+
pub red: Option<u8>,
6767
/// The green component.
68-
pub green: u8,
68+
pub green: Option<u8>,
6969
/// The blue component.
70-
pub blue: u8,
70+
pub blue: Option<u8>,
7171
/// The alpha component.
72-
pub alpha: f32,
72+
pub alpha: Option<f32>,
7373
}
7474

7575
impl RGBA {
7676
/// Constructs a new RGBA value from float components. It expects the red,
7777
/// green, blue and alpha channels in that order, and all values will be
7878
/// clamped to the 0.0 ... 1.0 range.
7979
#[inline]
80-
pub fn from_floats(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
80+
pub fn from_floats(
81+
red: Option<f32>,
82+
green: Option<f32>,
83+
blue: Option<f32>,
84+
alpha: Option<f32>,
85+
) -> Self {
8186
Self::new(
82-
clamp_unit_f32(red),
83-
clamp_unit_f32(green),
84-
clamp_unit_f32(blue),
85-
alpha.max(0.0).min(1.0),
87+
red.map(|r| clamp_unit_f32(r)),
88+
green.map(|g| clamp_unit_f32(g)),
89+
blue.map(|b| clamp_unit_f32(b)),
90+
alpha.map(|a| a.clamp(0.0, OPAQUE)),
8691
)
8792
}
8893

89-
/// Returns a transparent color.
90-
#[inline]
91-
pub fn transparent() -> Self {
92-
Self::new(0, 0, 0, 0.0)
93-
}
94-
9594
/// Same thing, but with `u8` values instead of floats in the 0 to 1 range.
9695
#[inline]
97-
pub const fn new(red: u8, green: u8, blue: u8, alpha: f32) -> Self {
96+
pub const fn new(
97+
red: Option<u8>,
98+
green: Option<u8>,
99+
blue: Option<u8>,
100+
alpha: Option<f32>,
101+
) -> Self {
98102
Self {
99103
red,
100104
green,
101105
blue,
102106
alpha,
103107
}
104108
}
105-
106-
/// Returns the red channel in a floating point number form, from 0 to 1.
107-
#[inline]
108-
pub fn red_f32(&self) -> f32 {
109-
self.red as f32 / 255.0
110-
}
111-
112-
/// Returns the green channel in a floating point number form, from 0 to 1.
113-
#[inline]
114-
pub fn green_f32(&self) -> f32 {
115-
self.green as f32 / 255.0
116-
}
117-
118-
/// Returns the blue channel in a floating point number form, from 0 to 1.
119-
#[inline]
120-
pub fn blue_f32(&self) -> f32 {
121-
self.blue as f32 / 255.0
122-
}
123-
124-
/// Returns the alpha channel in a floating point number form, from 0 to 1.
125-
#[inline]
126-
pub fn alpha_f32(&self) -> f32 {
127-
self.alpha
128-
}
129-
130-
/// Parse a color hash, without the leading '#' character.
131-
#[inline]
132-
pub fn parse_hash(value: &[u8]) -> Result<Self, ()> {
133-
Ok(match value.len() {
134-
8 => Self::new(
135-
from_hex(value[0])? * 16 + from_hex(value[1])?,
136-
from_hex(value[2])? * 16 + from_hex(value[3])?,
137-
from_hex(value[4])? * 16 + from_hex(value[5])?,
138-
(from_hex(value[6])? * 16 + from_hex(value[7])?) as f32 / 255.0,
139-
),
140-
6 => Self::new(
141-
from_hex(value[0])? * 16 + from_hex(value[1])?,
142-
from_hex(value[2])? * 16 + from_hex(value[3])?,
143-
from_hex(value[4])? * 16 + from_hex(value[5])?,
144-
OPAQUE,
145-
),
146-
4 => Self::new(
147-
from_hex(value[0])? * 17,
148-
from_hex(value[1])? * 17,
149-
from_hex(value[2])? * 17,
150-
(from_hex(value[3])? * 17) as f32 / 255.0,
151-
),
152-
3 => Self::new(
153-
from_hex(value[0])? * 17,
154-
from_hex(value[1])? * 17,
155-
from_hex(value[2])? * 17,
156-
OPAQUE,
157-
),
158-
_ => return Err(()),
159-
})
160-
}
161109
}
162110

163111
#[cfg(feature = "serde")]
@@ -186,17 +134,17 @@ impl ToCss for RGBA {
186134
where
187135
W: fmt::Write,
188136
{
189-
let has_alpha = self.alpha != OPAQUE;
137+
let has_alpha = self.alpha.unwrap_or(0.0) != OPAQUE;
190138

191139
dest.write_str(if has_alpha { "rgba(" } else { "rgb(" })?;
192-
self.red.to_css(dest)?;
140+
self.red.unwrap_or(0).to_css(dest)?;
193141
dest.write_str(", ")?;
194-
self.green.to_css(dest)?;
142+
self.green.unwrap_or(0).to_css(dest)?;
195143
dest.write_str(", ")?;
196-
self.blue.to_css(dest)?;
144+
self.blue.unwrap_or(0).to_css(dest)?;
197145

198146
// Legacy syntax does not allow none components.
199-
serialize_alpha(dest, Some(self.alpha), true)?;
147+
serialize_alpha(dest, Some(self.alpha.unwrap_or(0.0)), true)?;
200148

201149
dest.write_char(')')
202150
}
@@ -242,7 +190,7 @@ impl ToCss for Hsl {
242190
self.lightness.unwrap_or(0.0),
243191
);
244192

245-
RGBA::from_floats(red, green, blue, self.alpha.unwrap_or(0.0)).to_css(dest)
193+
RGBA::from_floats(Some(red), Some(green), Some(blue), self.alpha).to_css(dest)
246194
}
247195
}
248196

@@ -307,7 +255,7 @@ impl ToCss for Hwb {
307255
self.blackness.unwrap_or(0.0),
308256
);
309257

310-
RGBA::from_floats(red, green, blue, self.alpha.unwrap_or(0.0)).to_css(dest)
258+
RGBA::from_floats(Some(red), Some(green), Some(blue), self.alpha).to_css(dest)
311259
}
312260
}
313261

@@ -892,6 +840,42 @@ pub trait FromParsedColor {
892840
) -> Self;
893841
}
894842

843+
/// Parse a color hash, without the leading '#' character.
844+
#[inline]
845+
846+
pub fn parse_hash_color<'i, 't, P>(value: &[u8]) -> Result<P::Output, ()>
847+
where
848+
P: ColorParser<'i>,
849+
{
850+
Ok(match value.len() {
851+
8 => P::Output::from_rgba(
852+
from_hex(value[0])? * 16 + from_hex(value[1])?,
853+
from_hex(value[2])? * 16 + from_hex(value[3])?,
854+
from_hex(value[4])? * 16 + from_hex(value[5])?,
855+
(from_hex(value[6])? * 16 + from_hex(value[7])?) as f32 / 255.0,
856+
),
857+
6 => P::Output::from_rgba(
858+
from_hex(value[0])? * 16 + from_hex(value[1])?,
859+
from_hex(value[2])? * 16 + from_hex(value[3])?,
860+
from_hex(value[4])? * 16 + from_hex(value[5])?,
861+
OPAQUE,
862+
),
863+
4 => P::Output::from_rgba(
864+
from_hex(value[0])? * 17,
865+
from_hex(value[1])? * 17,
866+
from_hex(value[2])? * 17,
867+
(from_hex(value[3])? * 17) as f32 / 255.0,
868+
),
869+
3 => P::Output::from_rgba(
870+
from_hex(value[0])? * 17,
871+
from_hex(value[1])? * 17,
872+
from_hex(value[2])? * 17,
873+
OPAQUE,
874+
),
875+
_ => return Err(()),
876+
})
877+
}
878+
895879
/// Parse a CSS color with the specified [`ColorComponentParser`] and return a
896880
/// new color value on success.
897881
pub fn parse_color_with<'i, 't, P>(
@@ -904,8 +888,9 @@ where
904888
let location = input.current_source_location();
905889
let token = input.next()?;
906890
match *token {
907-
Token::Hash(ref value) | Token::IDHash(ref value) => RGBA::parse_hash(value.as_bytes())
908-
.map(|rgba| P::Output::from_rgba(rgba.red, rgba.green, rgba.blue, rgba.alpha)),
891+
Token::Hash(ref value) | Token::IDHash(ref value) => {
892+
parse_hash_color::<P>(value.as_bytes())
893+
}
909894
Token::Ident(ref value) => parse_color_keyword(&*value),
910895
Token::Function(ref name) => {
911896
let name = name.clone();
@@ -926,7 +911,7 @@ impl FromParsedColor for Color {
926911

927912
#[inline]
928913
fn from_rgba(red: u8, green: u8, blue: u8, alpha: f32) -> Self {
929-
Color::Rgba(RGBA::new(red, green, blue, alpha))
914+
Color::Rgba(RGBA::new(Some(red), Some(green), Some(blue), Some(alpha)))
930915
}
931916

932917
fn from_hsl(

src/tests.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -592,19 +592,19 @@ fn serialize_current_color() {
592592

593593
#[test]
594594
fn serialize_rgb_full_alpha() {
595-
let c = Color::Rgba(RGBA::new(255, 230, 204, 1.0));
595+
let c = Color::Rgba(RGBA::new(Some(255), Some(230), Some(204), Some(1.0)));
596596
assert_eq!(c.to_css_string(), "rgb(255, 230, 204)");
597597
}
598598

599599
#[test]
600600
fn serialize_rgba() {
601-
let c = Color::Rgba(RGBA::new(26, 51, 77, 0.125));
601+
let c = Color::Rgba(RGBA::new(Some(26), Some(51), Some(77), Some(0.125)));
602602
assert_eq!(c.to_css_string(), "rgba(26, 51, 77, 0.125)");
603603
}
604604

605605
#[test]
606606
fn serialize_rgba_two_digit_float_if_roundtrips() {
607-
let c = Color::Rgba(RGBA::from_floats(0., 0., 0., 0.5));
607+
let c = Color::Rgba(RGBA::from_floats(Some(0.), Some(0.), Some(0.), Some(0.5)));
608608
assert_eq!(c.to_css_string(), "rgba(0, 0, 0, 0.5)");
609609
}
610610

0 commit comments

Comments
 (0)