use sim_kernel::{Cx, Expr, Result, Symbol};
use crate::contract::LensKind;
use crate::dispatch::{DispatchContext, DispatchReason, LensRegistry, best_shape_score};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LensStackEntry {
pub lens_id: Symbol,
pub reason: DispatchReason,
}
impl LensRegistry {
pub fn lens_stack(
&self,
cx: &mut Cx,
kind: LensKind,
target: &Expr,
ctx: &DispatchContext,
) -> Result<Vec<LensStackEntry>> {
let mut ranked: Vec<(i32, i32, i32, i32, Symbol, DispatchReason)> = Vec::new();
for lens in self.lenses() {
if lens.meta.kind != kind || !self.allowed(lens, ctx) {
continue;
}
let meta = &lens.meta;
if meta.universal_default {
ranked.push((
0,
0,
meta.quality,
-meta.cost,
meta.id.clone(),
DispatchReason::UniversalDefault,
));
} else if let Some(score) = best_shape_score(cx, lens, target)? {
ranked.push((
2,
score,
meta.quality,
-meta.cost,
meta.id.clone(),
DispatchReason::ShapeMatch(score),
));
} else if class_matches(meta, ctx) {
ranked.push((
1,
0,
meta.quality,
-meta.cost,
meta.id.clone(),
DispatchReason::ClassMatch,
));
}
}
ranked.sort_by_key(|entry| std::cmp::Reverse((entry.0, entry.1, entry.2, entry.3)));
Ok(ranked
.into_iter()
.map(|(_, _, _, _, lens_id, reason)| LensStackEntry { lens_id, reason })
.collect())
}
}
fn class_matches(meta: &crate::contract::LensMeta, ctx: &DispatchContext) -> bool {
match &ctx.value_class {
Some(class) => meta.claimed_classes.contains(class),
None => false,
}
}