use crate::gui::solid_preview::preview_state::LateFindings;
use indicatrix_cut_core::ManufacturabilityWarning;
use std::{cell::RefCell, cmp::Ordering, sync::Arc};
struct Pushed {
generation: u64,
findings: Option<Arc<LateFindings>>,
rows_show_findings: bool,
}
#[derive(Default)]
pub(super) struct LateRows {
pushed: Option<Pushed>,
parked: Option<Arc<LateFindings>>,
}
impl LateRows {
pub(super) fn kept(&self, generation: u64) -> Option<Arc<LateFindings>> {
if let Some(parked) = &self.parked
&& parked.generation == generation
{
return Some(Arc::clone(parked));
}
self.pushed
.as_ref()
.filter(|pushed| pushed.generation == generation)
.and_then(|pushed| pushed.findings.clone())
}
pub(super) fn frame_pushed(
&mut self,
generation: u64,
carried_findings: bool,
) -> Option<Arc<LateFindings>> {
let mut findings = match self.pushed.take() {
Some(pushed) if pushed.generation == generation => pushed.findings,
_ => None,
};
if let Some(parked) = self.parked.take() {
match parked.generation.cmp(&generation) {
Ordering::Equal => findings = Some(parked),
Ordering::Greater => self.parked = Some(parked),
Ordering::Less => {}
}
}
let due = if carried_findings {
None
} else {
findings.clone()
};
self.pushed = Some(Pushed {
generation,
rows_show_findings: carried_findings || due.is_some(),
findings,
});
due
}
pub(super) fn findings_arrived(&mut self, late: LateFindings) -> Option<Arc<LateFindings>> {
let late = Arc::new(late);
match &mut self.pushed {
Some(pushed) if pushed.generation == late.generation => {
pushed.findings = Some(Arc::clone(&late));
let due = !pushed.rows_show_findings;
pushed.rows_show_findings = true;
due.then_some(late)
}
Some(pushed) if pushed.generation > late.generation => None,
_ => {
self.parked = Some(late);
None
}
}
}
pub(super) fn put_back(&mut self, late: &Arc<LateFindings>) {
if let Some(pushed) = &mut self.pushed
&& pushed.generation == late.generation
{
pushed.findings = Some(Arc::clone(late));
pushed.rows_show_findings = false;
}
}
pub(super) fn owed(&mut self) -> Option<Arc<LateFindings>> {
let pushed = self.pushed.as_mut()?;
if pushed.rows_show_findings {
return None;
}
let findings = pushed.findings.clone()?;
pushed.rows_show_findings = true;
Some(findings)
}
}
pub(super) fn land_committed_frame(
late_rows: &RefCell<LateRows>,
generation: u64,
carried: Option<&Arc<Vec<ManufacturabilityWarning>>>,
push_rows: impl FnOnce(Option<&[ManufacturabilityWarning]>) -> bool,
) -> Option<Arc<LateFindings>> {
let kept = if carried.is_none() {
late_rows.borrow().kept(generation)
} else {
None
};
let shown = carried.or_else(|| kept.as_ref().map(|late| &late.warnings));
if !push_rows(shown.map(|findings| findings.as_slice())) {
return None;
}
late_rows
.borrow_mut()
.frame_pushed(generation, shown.is_some())
}
#[cfg(test)]
mod tests {
use super::*;
use indicatrix_cut_core::Design;
fn findings_copy(generation: u64, copy: usize) -> LateFindings {
LateFindings {
generation,
design: Arc::new(Design::concave_fixture()),
masts: Vec::new(),
warnings: Arc::new(vec![
ManufacturabilityWarning::ToolEnclosed {
tier: 0,
placement: 0
};
copy
]),
}
}
fn findings_for(generation: u64) -> LateFindings {
findings_copy(generation, 0)
}
fn generations(applied: Option<Arc<LateFindings>>) -> Option<u64> {
let findings = applied?;
Some(findings.generation)
}
fn copies(applied: Option<Arc<LateFindings>>) -> Option<(u64, usize)> {
let findings = applied?;
Some((findings.generation, findings.warnings.len()))
}
#[test]
fn findings_after_a_frame_without_them_refresh_the_rows() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.frame_pushed(7, false)), None);
assert_eq!(generations(rows.findings_arrived(findings_for(7))), Some(7));
}
#[test]
fn findings_the_frame_already_carried_are_not_pushed_again() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.frame_pushed(7, true)), None);
assert_eq!(generations(rows.findings_arrived(findings_for(7))), None);
}
#[test]
fn findings_before_their_frame_wait_for_it() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.findings_arrived(findings_for(7))), None);
assert_eq!(generations(rows.frame_pushed(7, false)), Some(7));
}
#[test]
fn parked_findings_are_not_pushed_for_a_frame_that_carried_them() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.findings_arrived(findings_for(7))), None);
assert_eq!(generations(rows.frame_pushed(7, true)), None);
}
#[test]
fn findings_for_a_superseded_plan_are_dropped() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.frame_pushed(8, false)), None);
assert_eq!(generations(rows.findings_arrived(findings_for(7))), None);
assert_eq!(generations(rows.frame_pushed(9, false)), None);
let mut rows = LateRows::default();
assert_eq!(generations(rows.findings_arrived(findings_for(7))), None);
assert_eq!(generations(rows.frame_pushed(8, false)), None);
assert_eq!(generations(rows.frame_pushed(7, false)), None);
}
#[test]
fn findings_for_a_newer_plan_wait_through_an_older_frame() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.findings_arrived(findings_for(8))), None);
assert_eq!(generations(rows.frame_pushed(7, false)), None);
assert_eq!(generations(rows.frame_pushed(8, false)), Some(8));
}
#[test]
fn findings_are_applied_once() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.frame_pushed(7, false)), None);
assert_eq!(generations(rows.findings_arrived(findings_for(7))), Some(7));
assert_eq!(generations(rows.findings_arrived(findings_for(7))), None);
}
#[test]
fn a_same_generation_frame_without_findings_gets_the_ones_already_seen() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.frame_pushed(7, false)), None);
assert_eq!(generations(rows.findings_arrived(findings_for(7))), Some(7));
assert_eq!(generations(rows.findings_arrived(findings_for(7))), None);
assert_eq!(
generations(rows.frame_pushed(7, false)),
Some(7),
"the second plan's rows start without the findings"
);
assert_eq!(generations(rows.findings_arrived(findings_for(7))), None);
}
#[test]
fn the_second_plans_findings_before_its_frame_do_not_lose_the_findings() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.frame_pushed(7, false)), None);
assert_eq!(
copies(rows.findings_arrived(findings_copy(7, 1))),
Some((7, 1))
);
assert_eq!(copies(rows.findings_arrived(findings_copy(7, 2))), None);
assert_eq!(copies(rows.frame_pushed(7, false)), Some((7, 2)));
}
#[test]
fn the_second_plans_frame_before_its_findings_is_given_the_first_plans() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.frame_pushed(7, false)), None);
assert_eq!(
copies(rows.findings_arrived(findings_copy(7, 1))),
Some((7, 1))
);
assert_eq!(copies(rows.frame_pushed(7, false)), Some((7, 1)));
assert_eq!(copies(rows.findings_arrived(findings_copy(7, 2))), None);
assert_eq!(copies(rows.frame_pushed(7, false)), Some((7, 2)));
}
#[test]
fn findings_a_frame_carried_are_kept_for_the_next_frame_of_the_generation() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.frame_pushed(7, true)), None);
assert_eq!(generations(rows.findings_arrived(findings_for(7))), None);
assert_eq!(generations(rows.frame_pushed(7, false)), Some(7));
}
#[test]
fn a_newer_generation_does_not_reuse_older_findings() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.frame_pushed(7, false)), None);
assert_eq!(generations(rows.findings_arrived(findings_for(7))), Some(7));
assert_eq!(generations(rows.frame_pushed(8, false)), None);
assert_eq!(generations(rows.owed()), None);
assert_eq!(
generations(rows.findings_arrived(findings_for(8))),
Some(8),
"the new design's own findings are still pushed"
);
}
#[test]
fn findings_that_met_a_held_editor_are_retried_not_marked_applied() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.frame_pushed(7, false)), None);
let due = rows
.findings_arrived(findings_for(7))
.expect("the frame landed without them");
rows.put_back(&due);
assert_eq!(generations(rows.owed()), Some(7), "the retry gets them");
assert_eq!(generations(rows.owed()), None, "and only once");
}
#[test]
fn put_back_findings_are_applied_by_the_next_frame_of_their_generation() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.frame_pushed(7, false)), None);
let due = rows
.findings_arrived(findings_for(7))
.expect("the frame landed without them");
rows.put_back(&due);
assert_eq!(generations(rows.frame_pushed(7, false)), Some(7));
let mut rows = LateRows::default();
assert_eq!(generations(rows.frame_pushed(7, false)), None);
let due = rows
.findings_arrived(findings_for(7))
.expect("the frame landed without them");
rows.put_back(&due);
assert_eq!(
generations(rows.findings_arrived(findings_for(7))),
Some(7),
"a fresh copy is applied again"
);
}
#[test]
fn put_back_findings_of_a_replaced_frame_are_forgotten() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.frame_pushed(7, false)), None);
let due = rows
.findings_arrived(findings_for(7))
.expect("the frame landed without them");
assert_eq!(generations(rows.frame_pushed(8, false)), None);
rows.put_back(&due);
assert_eq!(generations(rows.owed()), None);
assert_eq!(generations(rows.frame_pushed(8, false)), None);
}
#[test]
fn nothing_is_owed_before_any_findings_arrive() {
let mut rows = LateRows::default();
assert_eq!(generations(rows.owed()), None);
assert_eq!(generations(rows.frame_pushed(7, false)), None);
assert_eq!(generations(rows.owed()), None);
}
#[test]
fn kept_names_the_copy_of_the_generation_and_changes_nothing() {
let mut rows = LateRows::default();
assert_eq!(copies(rows.kept(7)), None, "nothing seen yet");
assert_eq!(generations(rows.frame_pushed(7, false)), None);
assert_eq!(copies(rows.kept(7)), None, "no findings for the rows yet");
assert_eq!(
copies(rows.findings_arrived(findings_copy(7, 1))),
Some((7, 1))
);
assert_eq!(copies(rows.kept(7)), Some((7, 1)));
assert_eq!(copies(rows.kept(7)), Some((7, 1)), "reading is not taking");
assert_eq!(copies(rows.kept(8)), None, "another design's rows");
assert_eq!(copies(rows.findings_arrived(findings_copy(8, 2))), None);
assert_eq!(copies(rows.kept(7)), Some((7, 1)));
assert_eq!(copies(rows.kept(8)), Some((8, 2)));
assert_eq!(copies(rows.frame_pushed(8, false)), Some((8, 2)));
}
struct Landing {
rows_given: Vec<Option<usize>>,
due: Option<(u64, usize)>,
}
fn land(
rows: &RefCell<LateRows>,
generation: u64,
carried: Option<usize>,
pushes: bool,
) -> Landing {
let carried = carried.map(|copy| findings_copy(generation, copy).warnings);
let mut rows_given = Vec::new();
let due = land_committed_frame(rows, generation, carried.as_ref(), |shown| {
rows_given.push(shown.map(<[_]>::len));
pushes
});
Landing {
rows_given,
due: copies(due),
}
}
#[test]
fn a_frame_that_pushed_no_rows_does_not_hide_the_findings_from_the_rows() {
let rows = RefCell::new(LateRows::default());
let first = land(&rows, 7, None, true);
assert_eq!(first.rows_given, vec![None]);
assert_eq!(first.due, None);
let second = land(&rows, 7, Some(1), false);
assert_eq!(second.rows_given, vec![Some(1)], "it was offered them");
assert_eq!(second.due, None);
assert_eq!(
copies(rows.borrow_mut().findings_arrived(findings_copy(7, 1))),
Some((7, 1))
);
}
#[test]
fn a_frame_that_pushed_no_rows_leaves_the_record_alone() {
let rows = RefCell::new(LateRows::default());
assert_eq!(land(&rows, 7, None, true).due, None);
assert_eq!(
copies(rows.borrow_mut().findings_arrived(findings_copy(7, 2))),
Some((7, 2))
);
let skipped = land(&rows, 7, None, false);
assert_eq!(skipped.due, None, "no rows were pushed, so no refresh");
assert_eq!(copies(rows.borrow().kept(7)), Some((7, 2)), "still kept");
assert_eq!(copies(rows.borrow_mut().owed()), None, "nothing is owed");
}
#[test]
fn a_frame_of_a_known_generation_builds_its_rows_once_with_the_findings() {
let rows = RefCell::new(LateRows::default());
assert_eq!(land(&rows, 7, None, true).due, None);
assert_eq!(
copies(rows.borrow_mut().findings_arrived(findings_copy(7, 2))),
Some((7, 2))
);
for _ in 0..3 {
let frame = land(&rows, 7, None, true);
assert_eq!(frame.rows_given, vec![Some(2)], "built with the findings");
assert_eq!(frame.due, None, "and not rebuilt afterwards");
}
assert_eq!(
copies(rows.borrow_mut().findings_arrived(findings_copy(7, 2))),
None
);
}
#[test]
fn parked_findings_are_given_to_the_first_push_of_their_frame() {
let rows = RefCell::new(LateRows::default());
assert_eq!(
copies(rows.borrow_mut().findings_arrived(findings_copy(7, 1))),
None
);
let frame = land(&rows, 7, None, true);
assert_eq!(frame.rows_given, vec![Some(1)]);
assert_eq!(frame.due, None);
assert_eq!(
copies(rows.borrow_mut().findings_arrived(findings_copy(7, 1))),
None,
"the rows already show them"
);
}
#[test]
fn a_frame_shows_its_own_findings_and_never_another_designs() {
let rows = RefCell::new(LateRows::default());
assert_eq!(land(&rows, 7, None, true).due, None);
assert_eq!(
copies(rows.borrow_mut().findings_arrived(findings_copy(7, 2))),
Some((7, 2))
);
let own = land(&rows, 7, Some(3), true);
assert_eq!(own.rows_given, vec![Some(3)], "the frame's own pass wins");
assert_eq!(own.due, None);
let newer = land(&rows, 8, None, true);
assert_eq!(newer.rows_given, vec![None], "design 7's findings stay out");
assert_eq!(newer.due, None);
}
#[test]
fn the_record_is_free_while_the_rows_are_pushed() {
let rows = RefCell::new(LateRows::default());
let due = land_committed_frame(&rows, 7, None, |_| {
assert!(rows.try_borrow_mut().is_ok());
true
});
assert!(due.is_none());
}
}