use crate::{Grid, Token};
pub(crate) fn assign_cell_indices(
tokens: &[Token],
grid: &Grid,
median: &Option<Token>,
sort_keys: &[Token],
) -> Vec<usize> {
let token_count = tokens.len();
let cell_count = grid.cols * grid.rows;
let mut ci: Vec<usize> = (0..token_count).collect(); if token_count >= cell_count || tokens.is_empty() {
return ci;
}
let shift = |ci: &mut Vec<usize>, start: usize| {
for (t, c) in ci.iter_mut().enumerate() {
if t >= start {
*c += 1;
}
}
};
if let Some(m) = median {
shift(&mut ci, m.index);
}
let mut sorted: Vec<&Token> = sort_keys.iter().collect();
sorted.sort_by(|a, b| a.text.cmp(&b.text).then(a.index.cmp(&b.index)));
if token_count + 1 < cell_count {
shift(&mut ci, sorted[sorted.len() - 1].index);
}
if token_count + 2 < cell_count {
shift(&mut ci, sorted[0].index);
}
ci
}
pub(crate) fn two_bit_counts(digest: &[u8; 64]) -> [usize; 4] {
let mut counts = [0usize; 4];
for &byte in digest.iter() {
for shift in [0u32, 2, 4, 6] {
counts[((byte >> shift) & 0x03) as usize] += 1;
}
}
counts
}
pub(crate) fn band_letter(color: &str) -> Option<&'static str> {
match color {
"#ffffff" => Some("W"),
"#e7be00" => Some("G"),
"#ff3f2f" => Some("R"),
"#2f3fbf" => Some("B"),
"#000000" => Some("K"),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn band_letter_palette_and_unknown() {
assert_eq!(band_letter("#ffffff"), Some("W"));
assert_eq!(band_letter("#e7be00"), Some("G"));
assert_eq!(band_letter("#ff3f2f"), Some("R"));
assert_eq!(band_letter("#2f3fbf"), Some("B"));
assert_eq!(band_letter("#000000"), Some("K"));
assert_eq!(band_letter("#123456"), None);
}
#[test]
fn two_bit_counts_sum_to_256_and_uniform_inputs() {
let z = two_bit_counts(&[0u8; 64]);
assert_eq!(z, [256, 0, 0, 0]);
let f = two_bit_counts(&[0xFFu8; 64]);
assert_eq!(f, [0, 0, 0, 256]);
let mut d = [0u8; 64];
for (i, b) in d.iter_mut().enumerate() {
*b = i as u8;
}
let c = two_bit_counts(&d);
assert_eq!(c.iter().sum::<usize>(), 256);
}
}