use std::collections::BTreeMap;
use crate::model::join::BeadKey;
use crate::model::snapshot::{Counts, Snapshot, Tree};
use crate::model::tree::Link;
use crate::view::lines::{facts_of, root_key, run_size, split, split_by, BeadFacts};
pub(super) struct Facts {
trees: BTreeMap<BeadKey, TreeFacts>,
projects: BTreeMap<String, Counts>,
}
impl Facts {
pub(super) fn of(snapshot: &Snapshot) -> Self {
let mut trees = BTreeMap::new();
for tree in snapshot.trees.iter().chain(&snapshot.collected) {
trees
.entry(root_key(tree))
.or_insert_with(|| TreeFacts::of(tree));
}
Facts {
trees,
projects: snapshot
.collected
.chunk_by(|a, b| a.project == b.project)
.map(|trees| {
(
trees[0].project.clone(),
Counts::over(trees.iter().flat_map(|tree| &tree.beads)),
)
})
.collect(),
}
}
pub(super) fn tree(&self, root: &BeadKey) -> &TreeFacts {
self.trees
.get(root)
.expect("every tree the snapshot holds was answered when it was taken")
}
pub(super) fn project(&self, project: &str) -> Counts {
self.projects.get(project).cloned().unwrap_or_default()
}
}
pub(super) struct TreeFacts {
beads: Option<Vec<Answered>>,
}
struct Answered {
facts: BeadFacts,
run: usize,
}
impl TreeFacts {
pub(super) fn of(tree: &Tree) -> Self {
if !tree.cycles.is_empty() {
return TreeFacts { beads: None };
}
let facts: Vec<BeadFacts> = (0..tree.beads.len())
.map(|at| facts_of(tree, at, &[]))
.collect();
let beads = facts
.iter()
.enumerate()
.map(|(at, bead)| {
let (_, elided) = split_by(tree, at, &[], |bead| facts[bead].finished);
Answered {
facts: bead.clone(),
run: run_size(tree, &elided, &[at]),
}
})
.collect();
TreeFacts { beads: Some(beads) }
}
pub(super) fn bead(&self, tree: &Tree, at: usize, above: &[usize]) -> BeadFacts {
match &self.beads {
Some(beads) => beads[at].facts.clone(),
None => facts_of(tree, at, above),
}
}
pub(super) fn split<'a>(
&self,
tree: &'a Tree,
at: usize,
above: &[usize],
) -> (Vec<&'a Link>, Vec<&'a Link>) {
match &self.beads {
Some(beads) => split_by(tree, at, above, |bead| beads[bead].facts.finished),
None => split(tree, at, above),
}
}
pub(super) fn run_size(&self, tree: &Tree, members: &[&Link], above: &[usize]) -> usize {
match &self.beads {
Some(beads) => {
let under = *above.last().expect("a run hangs under a bead");
beads[under].run
}
None => run_size(tree, members, above),
}
}
}