use serde::{Deserialize, Serialize};
use crate::object::sheaf::{Cover, SectionTable};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum InferenceAttempt {
InferredMissingSection { open: String, source_open: String },
ResolvedOverlap { open_a: String, open_b: String },
FailedRecovery { open: String, reason: String },
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CoverGlueInferenceReport {
pub attempts: Vec<InferenceAttempt>,
}
impl CoverGlueInferenceReport {
pub fn empty() -> Self {
Self { attempts: vec![] }
}
pub fn all_succeeded(&self) -> bool {
self.attempts
.iter()
.all(|a| !matches!(a, InferenceAttempt::FailedRecovery { .. }))
}
}
pub fn infer_missing_sections<T: Clone + PartialEq>(
cover: &Cover,
sections: &SectionTable<T>,
) -> Vec<(String, String)> {
let mut inferred: Vec<(String, String)> = vec![];
let present: Vec<&str> = sections.sections.keys().map(|k| k.0.as_str()).collect();
for open in &cover.opens {
if sections.sections.contains_key(open) {
continue;
}
if let Some(source) = present.first() {
inferred.push((open.0.clone(), (*source).to_string()));
}
}
inferred
}
pub fn resolve_overlap_attempt<T: Clone + PartialEq>(
sections: &SectionTable<T>,
open_a: &str,
open_b: &str,
) -> InferenceAttempt {
let has_a = sections.sections.keys().any(|k| k.0 == open_a);
let has_b = sections.sections.keys().any(|k| k.0 == open_b);
if has_a && has_b {
InferenceAttempt::ResolvedOverlap {
open_a: open_a.to_string(),
open_b: open_b.to_string(),
}
} else {
InferenceAttempt::FailedRecovery {
open: if !has_a {
open_a.to_string()
} else {
open_b.to_string()
},
reason: "missing section for one of the overlap opens".to_string(),
}
}
}
pub fn cover_glue_inference_report<T: Clone + PartialEq>(
cover: &Cover,
sections: &SectionTable<T>,
) -> CoverGlueInferenceReport {
let mut report = CoverGlueInferenceReport::empty();
for (open, source) in infer_missing_sections(cover, sections) {
report
.attempts
.push(InferenceAttempt::InferredMissingSection {
open,
source_open: source,
});
}
let present: Vec<&str> = sections.sections.keys().map(|k| k.0.as_str()).collect();
if present.len() >= 2 {
report
.attempts
.push(resolve_overlap_attempt(sections, present[0], present[1]));
}
report
}