Skip to content

Commit 6ed9e77

Browse files
Rely on defined saturation behavior for f32 to u8 casts
This is a backport of a change from Raph made in the CPU sparse strips experiment. When converting from `f32` to `u8`, the code was clamping to be sure that the values were within range. This was necessary in the past, but hasn't been needed for some years now, since <rust-lang/rust#10184>. This clamping is not necessary and the compiler is not optimizing it away as of Rust 1.83 on Apple Silicon.
1 parent f82649b commit 6ed9e77

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

color/src/color.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -512,11 +512,13 @@ impl<CS: ColorSpace> AlphaColor<CS> {
512512
/// Pack into 8 bit per component encoding.
513513
#[must_use]
514514
pub fn to_rgba8(self) -> Rgba8 {
515+
// This does not need clamping as the behavior of a `f32` to `u8`
516+
// cast in Rust is to saturate.
515517
#[expect(clippy::cast_possible_truncation, reason = "deliberate quantization")]
516518
let [r, g, b, a] = self
517519
.convert::<Srgb>()
518520
.components
519-
.map(|x| (x.clamp(0., 1.) * 255.0).round() as u8);
521+
.map(|x| (x * 255.0).round() as u8);
520522
Rgba8 { r, g, b, a }
521523
}
522524
}
@@ -628,11 +630,13 @@ impl<CS: ColorSpace> PremulColor<CS> {
628630
/// Pack into 8 bit per component encoding.
629631
#[must_use]
630632
pub fn to_rgba8(self) -> PremulRgba8 {
633+
// This does not need clamping as the behavior of a `f32` to `u8`
634+
// cast in Rust is to saturate.
631635
#[expect(clippy::cast_possible_truncation, reason = "deliberate quantization")]
632636
let [r, g, b, a] = self
633637
.convert::<Srgb>()
634638
.components
635-
.map(|x| (x.clamp(0., 1.) * 255.0).round() as u8);
639+
.map(|x| (x * 255.0).round() as u8);
636640
PremulRgba8 { r, g, b, a }
637641
}
638642
}
@@ -828,7 +832,20 @@ impl<CS: ColorSpace> core::ops::Sub for PremulColor<CS> {
828832

829833
#[cfg(test)]
830834
mod tests {
831-
use super::{fixup_hue, HueDirection};
835+
use super::{fixup_hue, AlphaColor, HueDirection, PremulColor, PremulRgba8, Rgba8, Srgb};
836+
837+
#[test]
838+
fn to_rgba8_saturation() {
839+
// This is just testing the Rust compiler behavior described in
840+
// <https://github.com/rust-lang/rust/issues/10184>.
841+
let (r, g, b, a) = (0, 0, 255, 255);
842+
843+
let ac = AlphaColor::<Srgb>::new([-1.01, -0.5, 1.01, 2.0]);
844+
assert_eq!(ac.to_rgba8(), Rgba8 { r, g, b, a });
845+
846+
let pc = PremulColor::<Srgb>::new([-1.01, -0.5, 1.01, 2.0]);
847+
assert_eq!(pc.to_rgba8(), PremulRgba8 { r, g, b, a });
848+
}
832849

833850
#[test]
834851
fn hue_fixup() {

0 commit comments

Comments
 (0)