diff --git a/crates/ecolor/src/color32.rs b/crates/ecolor/src/color32.rs index e7372070..b9de323e 100644 --- a/crates/ecolor/src/color32.rs +++ b/crates/ecolor/src/color32.rs @@ -157,6 +157,27 @@ impl Color32 { } } + /// Same as [`Self::from_rgba_unmultiplied`], but can be used in a const context. + /// + /// It is slightly slower when operating on non-const data. + #[inline] + pub const fn from_rgba_unmultiplied_const(r: u8, g: u8, b: u8, a: u8) -> Self { + match a { + // common-case optimization: + 0 => Self::TRANSPARENT, + + // common-case optimization: + 255 => Self::from_rgb(r, g, b), + + a => { + let r = fast_round(r as f32 * linear_f32_from_linear_u8(a)); + let g = fast_round(g as f32 * linear_f32_from_linear_u8(a)); + let b = fast_round(b as f32 * linear_f32_from_linear_u8(a)); + Self::from_rgba_premultiplied(r, g, b, a) + } + } + } + /// Opaque gray. #[doc(alias = "from_grey")] #[inline] @@ -502,9 +523,11 @@ mod test { fn to_from_rgba() { for [r, g, b, a] in test_rgba() { let original = Color32::from_rgba_unmultiplied(r, g, b, a); + let constfn = Color32::from_rgba_unmultiplied_const(r, g, b, a); let rgba = Rgba::from(original); let back = Color32::from(rgba); assert_eq!(back, original); + assert_eq!(constfn, original); } assert_eq!( diff --git a/crates/ecolor/src/hex_color_macro.rs b/crates/ecolor/src/hex_color_macro.rs index e95bbc46..cda00a51 100644 --- a/crates/ecolor/src/hex_color_macro.rs +++ b/crates/ecolor/src/hex_color_macro.rs @@ -31,10 +31,11 @@ /// let _ = ecolor::hex_color!("#20212x"); /// ``` /// -/// The macro cannot be used in a `const` context. +/// The macro can be used in a `const` context. /// -/// ```compile_fail +/// ``` /// const COLOR: ecolor::Color32 = ecolor::hex_color!("#202122"); +/// assert_eq!(COLOR, ecolor::Color32::from_rgb(0x20, 0x21, 0x22)); /// ``` #[macro_export] macro_rules! hex_color { @@ -42,7 +43,7 @@ macro_rules! hex_color { let array = $crate::color_hex::color_from_hex!($s); match array.as_slice() { [r, g, b] => $crate::Color32::from_rgb(*r, *g, *b), - [r, g, b, a] => $crate::Color32::from_rgba_unmultiplied(*r, *g, *b, *a), + [r, g, b, a] => $crate::Color32::from_rgba_unmultiplied_const(*r, *g, *b, *a), _ => panic!("Invalid hex color length: expected 3 (RGB) or 4 (RGBA) bytes"), } }}; diff --git a/crates/ecolor/src/lib.rs b/crates/ecolor/src/lib.rs index 9c4ac9b6..f4cdf4d7 100644 --- a/crates/ecolor/src/lib.rs +++ b/crates/ecolor/src/lib.rs @@ -105,7 +105,7 @@ pub fn linear_f32_from_gamma_u8(s: u8) -> f32 { /// linear [0, 255] -> linear [0, 1]. /// Useful for alpha-channel. #[inline(always)] -pub fn linear_f32_from_linear_u8(a: u8) -> f32 { +pub const fn linear_f32_from_linear_u8(a: u8) -> f32 { a as f32 / 255.0 } @@ -130,7 +130,7 @@ pub fn linear_u8_from_linear_f32(a: f32) -> u8 { fast_round(a * 255.0) } -fn fast_round(r: f32) -> u8 { +const fn fast_round(r: f32) -> u8 { (r + 0.5) as _ // rust does a saturating cast since 1.45 }