#![allow(dead_code)]
use core::ops::Range;
pub const N_CELLS: usize = 6;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct CellSpec {
pub method: u8,
pub segments: u8,
}
pub const CELLS: [CellSpec; N_CELLS] = [
CellSpec {
method: 4,
segments: 1,
},
CellSpec {
method: 4,
segments: 4,
},
CellSpec {
method: 5,
segments: 1,
},
CellSpec {
method: 5,
segments: 4,
},
CellSpec {
method: 6,
segments: 1,
},
CellSpec {
method: 6,
segments: 4,
},
];
pub const RANGE_BYTES_LOG: Range<usize> = 0..N_CELLS;
pub const RANGE_SNS: Range<usize> = N_CELLS..(2 * N_CELLS);
pub const RANGE_FILTER_STRENGTH: Range<usize> = (2 * N_CELLS)..(3 * N_CELLS);
pub const RANGE_FILTER_SHARPNESS: Range<usize> = (3 * N_CELLS)..(4 * N_CELLS);
pub const N_OUTPUTS: usize = 4 * N_CELLS;
#[derive(Clone, Copy, Debug, Default)]
pub struct PickerConstraints {
pub allowed_methods: Option<&'static [u8]>,
pub allowed_segments: Option<&'static [u8]>,
}
impl PickerConstraints {
pub fn allowed_mask(&self) -> [bool; N_CELLS] {
core::array::from_fn(|i| {
let cell = &CELLS[i];
let m_ok = self
.allowed_methods
.is_none_or(|s| s.contains(&cell.method));
let s_ok = self
.allowed_segments
.is_none_or(|s| s.contains(&cell.segments));
m_ok && s_ok
})
}
}
pub const FEAT_COLS: &[&str] = &[
"feat_laplacian_variance_p50",
"feat_laplacian_variance_p75",
"feat_laplacian_variance",
"feat_quant_survival_y",
"feat_cb_sharpness",
"feat_pixel_count",
"feat_uniformity",
"feat_distinct_color_bins",
"feat_cr_sharpness",
"feat_edge_density",
"feat_noise_floor_y_p50",
"feat_luma_histogram_entropy",
"feat_natural_likelihood",
"feat_quant_survival_y_p50",
"feat_noise_floor_uv_p50",
"feat_aq_map_mean",
"feat_cr_horiz_sharpness",
"feat_min_dim",
"feat_edge_slope_stdev",
"feat_laplacian_variance_p90",
"feat_patch_fraction",
"feat_max_dim",
"feat_aspect_min_over_max",
"feat_aq_map_p75",
"feat_cb_horiz_sharpness",
"feat_noise_floor_y_p25",
"feat_noise_floor_uv",
"feat_chroma_complexity",
"feat_quant_survival_y_p75",
"feat_aq_map_std",
"feat_gradient_fraction",
"feat_noise_floor_y_p75",
"feat_screen_content_likelihood",
"feat_high_freq_energy_ratio",
"feat_colourfulness",
"feat_quant_survival_uv",
];
pub const N_FEAT_COLS: usize = FEAT_COLS.len();
pub const SCHEMA_VERSION_TAG: &str = "zenwebp.picker.v0.1";
pub const SCHEMA_HASH: u64 = 0xb2aca28a2d7a34ec;
pub const fn cell_to_method_segments(idx: usize) -> (u8, u8) {
let cell = CELLS[idx];
(cell.method, cell.segments)
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec::Vec;
#[test]
fn cells_are_unique() {
for i in 0..N_CELLS {
for j in (i + 1)..N_CELLS {
assert_ne!(CELLS[i], CELLS[j], "cell {i} == cell {j}");
}
}
}
#[test]
fn cells_match_lex_sort_of_method_segments() {
let methods: [u8; 3] = [4, 5, 6];
let segments: [u8; 2] = [1, 4];
let mut expected = Vec::with_capacity(N_CELLS);
for &m in &methods {
for &s in &segments {
expected.push(CellSpec {
method: m,
segments: s,
});
}
}
for (i, cell) in CELLS.iter().enumerate() {
assert_eq!(*cell, expected[i], "cell {i} mismatch");
}
}
#[test]
fn output_layout_partitions_correctly() {
assert_eq!(RANGE_BYTES_LOG.end - RANGE_BYTES_LOG.start, N_CELLS);
assert_eq!(RANGE_SNS.end - RANGE_SNS.start, N_CELLS);
assert_eq!(
RANGE_FILTER_STRENGTH.end - RANGE_FILTER_STRENGTH.start,
N_CELLS
);
assert_eq!(
RANGE_FILTER_SHARPNESS.end - RANGE_FILTER_SHARPNESS.start,
N_CELLS
);
assert_eq!(RANGE_FILTER_SHARPNESS.end, N_OUTPUTS);
}
#[test]
fn constraints_default_allows_all() {
let mask = PickerConstraints::default().allowed_mask();
assert_eq!(mask, [true; N_CELLS]);
}
#[test]
fn constraints_method_only_4() {
let c = PickerConstraints {
allowed_methods: Some(&[4]),
..Default::default()
};
let mask = c.allowed_mask();
assert_eq!(mask, [true, true, false, false, false, false]);
}
#[test]
fn constraints_method_4_or_5_segments_1() {
let c = PickerConstraints {
allowed_methods: Some(&[4, 5]),
allowed_segments: Some(&[1]),
};
let mask = c.allowed_mask();
assert_eq!(mask, [true, false, true, false, false, false]);
}
}