use archmage::testing::{CompileTimePolicy, for_each_token_permutation};
use linear_srgb::default::{
linear_to_srgb_slice, linear_to_srgb_u8_slice, srgb_to_linear_slice, srgb_u8_to_linear_slice,
};
fn hash_bytes(data: &[u8]) -> u64 {
let mut h: u64 = 0xcbf29ce484222325;
for &b in data {
h ^= b as u64;
h = h.wrapping_mul(0x100000001b3);
}
h
}
fn hash_f32(data: &[f32]) -> u64 {
hash_bytes(bytemuck::cast_slice(data))
}
fn generate_u8_input(repeats: usize) -> Vec<u8> {
(0..repeats).flat_map(|_| 0..=255u8).collect()
}
fn generate_f32_input(count: usize) -> Vec<f32> {
(0..count).map(|i| i as f32 / (count - 1) as f32).collect()
}
#[test]
fn srgb_u8_to_linear_all_tiers_match() {
let input = generate_u8_input(4); let mut reference_hash = None;
let _ = for_each_token_permutation(CompileTimePolicy::Warn, |perm| {
let mut output = vec![0.0f32; input.len()];
srgb_u8_to_linear_slice(&input, &mut output);
let h = hash_f32(&output);
if let Some(ref_h) = reference_hash {
assert_eq!(
h, ref_h,
"srgb_u8_to_linear output differs under '{}'",
perm.label,
);
} else {
reference_hash = Some(h);
}
});
}
#[test]
fn linear_to_srgb_u8_all_tiers_match() {
let input = generate_f32_input(4096);
let mut reference_hash = None;
let _ = for_each_token_permutation(CompileTimePolicy::Warn, |perm| {
let mut output = vec![0u8; input.len()];
linear_to_srgb_u8_slice(&input, &mut output);
let h = hash_bytes(&output);
if let Some(ref_h) = reference_hash {
assert_eq!(
h, ref_h,
"linear_to_srgb_u8 output differs under '{}'",
perm.label,
);
} else {
reference_hash = Some(h);
}
});
}
fn max_abs_diff(a: &[f32], b: &[f32]) -> f32 {
a.iter()
.zip(b.iter())
.map(|(x, y)| (x - y).abs())
.fold(0.0f32, f32::max)
}
#[test]
fn srgb_to_linear_f32_all_tiers_within_ulp() {
let input = generate_f32_input(8192);
let mut reference: Option<Vec<f32>> = None;
let _ = for_each_token_permutation(CompileTimePolicy::Warn, |perm| {
let mut data = input.clone();
srgb_to_linear_slice(&mut data);
if let Some(ref ref_data) = reference {
let max_diff = max_abs_diff(ref_data, &data);
assert!(
max_diff < 1e-6,
"srgb_to_linear_f32 under '{}': max_diff={max_diff} (expected <1e-6)",
perm.label,
);
} else {
reference = Some(data);
}
});
}
#[test]
fn linear_to_srgb_f32_all_tiers_within_ulp() {
let input = generate_f32_input(8192);
let mut reference: Option<Vec<f32>> = None;
let _ = for_each_token_permutation(CompileTimePolicy::Warn, |perm| {
let mut data = input.clone();
linear_to_srgb_slice(&mut data);
if let Some(ref ref_data) = reference {
let max_diff = max_abs_diff(ref_data, &data);
assert!(
max_diff < 1e-6,
"linear_to_srgb_f32 under '{}': max_diff={max_diff} (expected <1e-6)",
perm.label,
);
} else {
reference = Some(data);
}
});
}
#[test]
fn roundtrip_u8_all_tiers_match() {
let input = generate_u8_input(4);
let mut reference_hash = None;
let _ = for_each_token_permutation(CompileTimePolicy::Warn, |perm| {
let mut linear = vec![0.0f32; input.len()];
srgb_u8_to_linear_slice(&input, &mut linear);
let mut roundtripped = vec![0u8; input.len()];
linear_to_srgb_u8_slice(&linear, &mut roundtripped);
let h = hash_bytes(&roundtripped);
if let Some(ref_h) = reference_hash {
assert_eq!(
h, ref_h,
"roundtrip u8 output differs under '{}'",
perm.label,
);
} else {
reference_hash = Some(h);
}
});
}