//! Deterministic mapping from origin label to palette index.
//!
//! FxHash-style shuffled multiplier. The point is stability across process
//! restarts, not cryptographic strength.
use crate::render::ansi::sgr::palette::{Color, PALETTE};
const MIX: u64 = 0x517c_c1b7_2722_0a95;
pub fn pick_color(origin: &str) -> Color {
let h = hash(origin.as_bytes());
PALETTE[(h as usize) % PALETTE.len()]
}
fn hash(bytes: &[u8]) -> u64 {
let mut acc: u64 = 0xcbf2_9ce4_8422_2325;
for &b in bytes {
acc = acc.wrapping_add(b as u64);
acc = acc.wrapping_mul(MIX);
acc ^= acc >> 27;
}
acc
}
/// Attempt to pick a distinct color for each source in `origins`. Falls back
/// to [`pick_color`] as soon as the palette is exhausted.
pub fn distinct_colors(origins: &[String]) -> Vec<Color> {
let mut out = Vec::with_capacity(origins.len());
let mut used = std::collections::HashSet::new();
for o in origins {
let primary = pick_color(o);
if used.insert(primary) {
out.push(primary);
continue;
}
let mut chosen = primary;
for offset in 1..PALETTE.len() {
let h = hash(o.as_bytes()).wrapping_add(offset as u64);
let alt = PALETTE[(h as usize) % PALETTE.len()];
if used.insert(alt) {
chosen = alt;
break;
}
}
out.push(chosen);
}
out
}