Skip to content

Commit

Permalink
Merge #347
Browse files Browse the repository at this point in the history
347: Implements Rgba::from_str() r=Ogeon a=rafaelbeckel

This change implements the from_str() trait for the Rgba type, adding support for parsing a RGBA hex string with the format `#rrggbbaa`.

No related issue, no breaking changes.

Co-authored-by: Rafael Beckel <rgb@pupil-labs.com>
Co-authored-by: Rafael Beckel <rafaelbeckel@gmail.com>
  • Loading branch information
3 people authored Aug 25, 2023
2 parents c70d8a6 + 1cd6ba1 commit 9ce4a63
Showing 1 changed file with 69 additions and 1 deletion.
70 changes: 69 additions & 1 deletion palette/src/rgb/rgb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,8 @@ pub enum FromHexError {
ParseIntError(ParseIntError),
/// The hex value was not in a valid 3 or 6 character format.
HexFormatError(&'static str),
/// The hex value was not in a valid 4 or 8 character format.
RgbaHexFormatError(&'static str),
}

impl From<ParseIntError> for FromHexError {
Expand All @@ -949,6 +951,7 @@ impl From<&'static str> for FromHexError {
FromHexError::HexFormatError(err)
}
}

impl core::fmt::Display for FromHexError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &*self {
Expand All @@ -958,6 +961,11 @@ impl core::fmt::Display for FromHexError {
"{}, please use format '#fff', 'fff', '#ffffff' or 'ffffff'.",
s
),
FromHexError::RgbaHexFormatError(s) => write!(
f,
"{}, please use format '#ffff', 'ffff', '#ffffffff' or 'ffffffff'.",
s
),
}
}
}
Expand All @@ -967,6 +975,7 @@ impl std::error::Error for FromHexError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &*self {
FromHexError::HexFormatError(_s) => None,
FromHexError::RgbaHexFormatError(_s) => None,
FromHexError::ParseIntError(e) => Some(e),
}
}
Expand Down Expand Up @@ -994,7 +1003,36 @@ impl<S> FromStr for Rgb<S, u8> {
let col: Rgb<S, u8> = Rgb::new(red, green, blue);
Ok(col)
}
_ => Err("invalid hex code format".into()),
_ => Err(FromHexError::HexFormatError("invalid hex code format")),
}
}
}

impl<S> FromStr for Rgba<S, u8> {
type Err = FromHexError;

/// Parses a color hex code of format '#ff00bbff' or '#abcd' (with or without the leading '#') into a
/// [`Rgba<S, u8>`] instance.
fn from_str(hex: &str) -> Result<Self, Self::Err> {
let hex_code = hex.strip_prefix('#').map_or(hex, |stripped| stripped);
match hex_code.len() {
4 => {
let red = u8::from_str_radix(&hex_code[..1], 16)?;
let green = u8::from_str_radix(&hex_code[1..2], 16)?;
let blue = u8::from_str_radix(&hex_code[2..3], 16)?;
let alpha = u8::from_str_radix(&hex_code[3..4], 16)?;
let col: Rgba<S, u8> = Rgba::new(red * 17, green * 17, blue * 17, alpha * 17);
Ok(col)
}
8 => {
let red = u8::from_str_radix(&hex_code[..2], 16)?;
let green = u8::from_str_radix(&hex_code[2..4], 16)?;
let blue = u8::from_str_radix(&hex_code[4..6], 16)?;
let alpha = u8::from_str_radix(&hex_code[6..8], 16)?;
let col: Rgba<S, u8> = Rgba::new(red, green, blue, alpha);
Ok(col)
}
_ => Err(FromHexError::RgbaHexFormatError("invalid hex code format")),
}
}
}
Expand Down Expand Up @@ -1392,6 +1430,36 @@ mod test {
assert_eq!(c.unwrap(), Rgb::<Srgb, u8>::new(240, 52, 230));
let c = Rgb::<Srgb, u8>::from_str("abc");
assert_eq!(c.unwrap(), Rgb::<Srgb, u8>::new(170, 187, 204));
let c = Rgba::<Srgb, u8>::from_str("#08ff");
assert_eq!(c.unwrap(), Rgba::<Srgb, u8>::new(0, 136, 255, 255));
let c = Rgba::<Srgb, u8>::from_str("08f0");
assert_eq!(c.unwrap(), Rgba::<Srgb, u8>::new(0, 136, 255, 0));
let c = Rgba::<Srgb, u8>::from_str("#da0bce80");
assert_eq!(c.unwrap(), Rgba::<Srgb, u8>::new(218, 11, 206, 128));
let c = Rgba::<Srgb, u8>::from_str("f034e680");
assert_eq!(c.unwrap(), Rgba::<Srgb, u8>::new(240, 52, 230, 128));
let c = Rgba::<Srgb, u8>::from_str("#ffffffff");
assert_eq!(c.unwrap(), Rgba::<Srgb, u8>::new(255, 255, 255, 255));
let c = Rgba::<Srgb, u8>::from_str("#ffff");
assert_eq!(c.unwrap(), Rgba::<Srgb, u8>::new(255, 255, 255, 255));
let c = Rgba::<Srgb, u8>::from_str("#gggggggg");
assert!(c.is_err());
assert_eq!(
format!("{}", c.err().unwrap()),
"invalid digit found in string"
);
let c = Rgba::<Srgb, u8>::from_str("#fff");
assert_eq!(
format!("{}", c.err().unwrap()),
"invalid hex code format, \
please use format '#ffff', 'ffff', '#ffffffff' or 'ffffffff'."
);
let c = Rgba::<Srgb, u8>::from_str("#ffffff");
assert_eq!(
format!("{}", c.err().unwrap()),
"invalid hex code format, \
please use format '#ffff', 'ffff', '#ffffffff' or 'ffffffff'."
);
}

#[test]
Expand Down

0 comments on commit 9ce4a63

Please sign in to comment.