pub(crate) mod cross_color;
pub(crate) mod palette;
pub(crate) mod predictor;
pub(crate) mod subtract_green;
#[must_use]
pub(crate) const fn add_pixels(a: u32, b: u32) -> u32 {
let alpha_green = (a & 0xff00_ff00).wrapping_add(b & 0xff00_ff00);
let red_blue = (a & 0x00ff_00ff).wrapping_add(b & 0x00ff_00ff);
(alpha_green & 0xff00_ff00) | (red_blue & 0x00ff_00ff)
}
#[must_use]
pub(crate) const fn sub_pixels(a: u32, b: u32) -> u32 {
let [a0, a1, a2, a3] = a.to_le_bytes();
let [b0, b1, b2, b3] = b.to_le_bytes();
u32::from_le_bytes([
a0.wrapping_sub(b0),
a1.wrapping_sub(b1),
a2.wrapping_sub(b2),
a3.wrapping_sub(b3),
])
}
#[cfg(test)]
mod tests {
use super::{add_pixels, sub_pixels};
use proptest::prelude::*;
#[test]
fn add_pixels_adds_each_lane() {
assert_eq!(add_pixels(0x0102_0304, 0x1020_3040), 0x1122_3344);
}
#[test]
fn add_pixels_wraps_per_lane() {
assert_eq!(add_pixels(0xff00_ff00, 0xff00_ff00), 0xfe00_fe00);
}
#[test]
fn sub_pixels_subtracts_each_lane() {
assert_eq!(sub_pixels(0x1122_3344, 0x1020_3040), 0x0102_0304);
}
#[test]
fn sub_pixels_wraps_per_lane_without_borrow_leak() {
let a = 0xff10_0220;
let b = 0x0000_0500;
let sub = sub_pixels(a, b);
assert_eq!(sub, 0xff10_fd20);
assert_eq!(sub >> 24, 0xff);
assert_eq!(add_pixels(sub, b), a);
}
#[test]
fn add_pixels_recovers_representative_vectors() {
let cases = [
(0x0000_0000_u32, 0x0000_0000_u32),
(0xffff_ffff, 0xffff_ffff),
(0x8040_2010, 0x0102_0408),
(0xff10_0220, 0x0000_0500), (0xff00_00ff, 0x00ff_ff00), ];
for (a, b) in cases {
assert_eq!(
add_pixels(sub_pixels(a, b), b),
a,
"a={a:#010x} b={b:#010x}"
);
}
}
proptest! {
#[test]
fn sub_pixels_is_inverse_of_add_pixels(a in any::<u32>(), b in any::<u32>()) {
prop_assert_eq!(add_pixels(sub_pixels(a, b), b), a);
}
}
}