use crate::bridge::render_thread::hash_planes;
use indicatrix::{
geometry::{girdle::girdle_facet_finishes, plane::GpuFacetPlane},
optics::raytracer::FacetFinish,
};
#[derive(Debug, Default)]
pub struct GirdleFinishCache {
key: Option<u64>,
finishes: Vec<FacetFinish>,
}
impl GirdleFinishCache {
#[must_use]
pub const fn new() -> Self {
Self {
key: None,
finishes: Vec::new(),
}
}
pub fn ensure(&mut self, planes: &[GpuFacetPlane]) -> &[FacetFinish] {
let key = hash_planes(planes);
if self.key != Some(key) {
self.finishes = girdle_facet_finishes(planes);
self.key = Some(key);
}
&self.finishes
}
}
#[cfg(test)]
mod tests {
use super::*;
use indicatrix::geometry::cuts::{STANDARD_ROUND_BRILLIANT_GIRDLE_FACETS, StandardGemCuts};
#[test]
fn ensure_matches_the_uncached_classification() {
let planes = StandardGemCuts::standard_round_brilliant();
let mut cache = GirdleFinishCache::new();
let cached = cache.ensure(&planes).to_vec();
let direct = girdle_facet_finishes(&planes);
assert_eq!(cached, direct);
for i in STANDARD_ROUND_BRILLIANT_GIRDLE_FACETS {
assert_eq!(cached[i], FacetFinish::Frosted, "index {i}");
}
}
#[test]
fn ensure_is_stable_across_repeated_calls_with_unchanged_planes() {
let planes = StandardGemCuts::standard_round_brilliant();
let mut cache = GirdleFinishCache::new();
let first = cache.ensure(&planes).to_vec();
let second = cache.ensure(&planes).to_vec();
assert_eq!(first, second);
}
#[test]
fn ensure_reclassifies_when_the_design_changes() {
let srb = StandardGemCuts::standard_round_brilliant();
let emerald = StandardGemCuts::emerald_cut();
let mut cache = GirdleFinishCache::new();
let srb_finishes = cache.ensure(&srb).to_vec();
let emerald_finishes = cache.ensure(&emerald).to_vec();
assert_eq!(emerald_finishes, girdle_facet_finishes(&emerald));
assert_ne!(
srb_finishes.len(),
emerald_finishes.len(),
"SRB and emerald_cut have different plane counts, so a stale (un-reclassified) \
result would show up as a length mismatch"
);
}
}