Use checked str slices in Rgba::TryFrom<str> (#12097)

Release Notes:

- N/A

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
This commit is contained in:
bbb651 2024-05-24 12:32:46 +03:00 committed by GitHub
parent 70e8737918
commit d116f3c292
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,4 +1,4 @@
use anyhow::bail; use anyhow::{bail, Context};
use serde::de::{self, Deserialize, Deserializer, Visitor}; use serde::de::{self, Deserialize, Deserializer, Visitor};
use std::fmt; use std::fmt;
@ -126,6 +126,7 @@ impl TryFrom<&'_ str> for Rgba {
const RRGGBBAA: usize = "rrggbbaa".len(); const RRGGBBAA: usize = "rrggbbaa".len();
const EXPECTED_FORMATS: &str = "Expected #rgb, #rgba, #rrggbb, or #rrggbbaa"; const EXPECTED_FORMATS: &str = "Expected #rgb, #rgba, #rrggbb, or #rrggbbaa";
const INVALID_UNICODE: &str = "invalid unicode characters in color";
let Some(("", hex)) = value.trim().split_once('#') else { let Some(("", hex)) = value.trim().split_once('#') else {
bail!("invalid RGBA hex color: '{value}'. {EXPECTED_FORMATS}"); bail!("invalid RGBA hex color: '{value}'. {EXPECTED_FORMATS}");
@ -133,11 +134,31 @@ impl TryFrom<&'_ str> for Rgba {
let (r, g, b, a) = match hex.len() { let (r, g, b, a) = match hex.len() {
RGB | RGBA => { RGB | RGBA => {
let r = u8::from_str_radix(&hex[0..1], 16)?; let r = u8::from_str_radix(
let g = u8::from_str_radix(&hex[1..2], 16)?; hex.get(0..1).with_context(|| {
let b = u8::from_str_radix(&hex[2..3], 16)?; format!("{INVALID_UNICODE}: r component of #rgb/#rgba for value: '{value}'")
})?,
16,
)?;
let g = u8::from_str_radix(
hex.get(1..2).with_context(|| {
format!("{INVALID_UNICODE}: g component of #rgb/#rgba for value: '{value}'")
})?,
16,
)?;
let b = u8::from_str_radix(
hex.get(2..3).with_context(|| {
format!("{INVALID_UNICODE}: b component of #rgb/#rgba for value: '{value}'")
})?,
16,
)?;
let a = if hex.len() == RGBA { let a = if hex.len() == RGBA {
u8::from_str_radix(&hex[3..4], 16)? u8::from_str_radix(
hex.get(3..4).with_context(|| {
format!("{INVALID_UNICODE}: a component of #rgba for value: '{value}'")
})?,
16,
)?
} else { } else {
0xf 0xf
}; };
@ -151,11 +172,40 @@ impl TryFrom<&'_ str> for Rgba {
(duplicate(r), duplicate(g), duplicate(b), duplicate(a)) (duplicate(r), duplicate(g), duplicate(b), duplicate(a))
} }
RRGGBB | RRGGBBAA => { RRGGBB | RRGGBBAA => {
let r = u8::from_str_radix(&hex[0..2], 16)?; let r = u8::from_str_radix(
let g = u8::from_str_radix(&hex[2..4], 16)?; hex.get(0..2).with_context(|| {
let b = u8::from_str_radix(&hex[4..6], 16)?; format!(
"{}: r component of #rrggbb/#rrggbbaa for value: '{}'",
INVALID_UNICODE, value
)
})?,
16,
)?;
let g = u8::from_str_radix(
hex.get(2..4).with_context(|| {
format!(
"{INVALID_UNICODE}: g component of #rrggbb/#rrggbbaa for value: '{value}'"
)
})?,
16,
)?;
let b = u8::from_str_radix(
hex.get(4..6).with_context(|| {
format!(
"{INVALID_UNICODE}: b component of #rrggbb/#rrggbbaa for value: '{value}'"
)
})?,
16,
)?;
let a = if hex.len() == RRGGBBAA { let a = if hex.len() == RRGGBBAA {
u8::from_str_radix(&hex[6..8], 16)? u8::from_str_radix(
hex.get(6..8).with_context(|| {
format!(
"{INVALID_UNICODE}: a component of #rrggbbaa for value: '{value}'"
)
})?,
16,
)?
} else { } else {
0xff 0xff
}; };