use crate::MainWindow;
use indicatrix::geometry::meet_solver::SolvedTier;
use indicatrix_cut_core::Design;
use slint::ComponentHandle;
use std::{cell::RefCell, sync::Arc};
use crate::gui::editor::solve_service::{SolveKind, SolveOutcome, SolveRequest, SolveService};
#[must_use]
pub(super) fn solve_matches_design(
cached: Option<&[SolvedTier]>,
design: &Design,
) -> Option<Vec<SolvedTier>> {
let cached = cached?;
(cached.len() == design.tiers.len()).then(|| cached.to_vec())
}
fn cached_solve_matching(design: &Design) -> Option<Vec<SolvedTier>> {
let cache = crate::gui::editor::auto_solve::solid_last_solved()?;
let guard = cache
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
solve_matches_design(guard.as_deref(), design)
}
type SolveContinuation = Box<dyn FnOnce(&MainWindow, Result<Vec<SolvedTier>, String>)>;
thread_local! {
static SOLVE_SERVICE: RefCell<Option<SolveService>> = const { RefCell::new(None) };
static PENDING_SOLVES: RefCell<std::collections::HashMap<u64, SolveContinuation>> =
RefCell::new(std::collections::HashMap::new());
static NEXT_SOLVE_KEY: std::cell::Cell<u64> = const { std::cell::Cell::new(0) };
}
fn ensure_solve_service(ui: &MainWindow) {
SOLVE_SERVICE.with(|cell| {
if cell.borrow().is_some() {
return;
}
let service = SolveService::new(
ui.as_weak(),
|_ui, _progress| {},
|ui, result| {
let Some(on_done) =
PENDING_SOLVES.with(|c| c.borrow_mut().remove(&result.generation))
else {
return;
};
let outcome = match result.outcome {
SolveOutcome::Solved(Ok(solved)) => Ok(solved),
SolveOutcome::Solved(Err(e)) => Err(e.to_string()),
SolveOutcome::Verified(_) => Err("unexpected solve result kind".to_string()),
};
on_done(ui, outcome);
},
);
*cell.borrow_mut() = Some(service);
});
}
fn submit_full_solve(
ui: &MainWindow,
design: Arc<Design>,
on_done: impl FnOnce(&MainWindow, Result<Vec<SolvedTier>, String>) + 'static,
) {
ensure_solve_service(ui);
let key = NEXT_SOLVE_KEY.with(|c| {
let key = c.get();
c.set(key + 1);
key
});
PENDING_SOLVES.with(|cell| {
cell.borrow_mut().insert(key, Box::new(on_done));
});
SOLVE_SERVICE.with(|cell| {
if let Some(service) = cell.borrow().as_ref() {
service.submit(SolveRequest {
design,
generation: key,
kind: SolveKind::Full,
});
}
});
}
pub(in crate::gui::editor) fn resolve_solved_then(
ui: &MainWindow,
design: Arc<Design>,
then: impl FnOnce(&MainWindow, Arc<Design>, Result<Vec<SolvedTier>, String>) + 'static,
) {
if let Some(solved) = cached_solve_matching(&design) {
then(ui, design, Ok(solved));
return;
}
let for_submit = Arc::clone(&design);
submit_full_solve(ui, for_submit, move |ui, result| {
then(ui, design, result);
});
}