use std::collections::HashSet;
use super::config::{SelfMerge, Style};
use super::model::{LeafItem, StmtInfo, TopKind, has_bare_item_dual, has_self_dual};
pub(super) fn is_compliant(
style: Style,
self_merge: Option<SelfMerge>,
stmts: &[&StmtInfo],
) -> bool {
match style {
Style::Item => stmts.iter().all(|stmt| is_item_shaped(stmt)),
Style::Module => module_compliant(stmts),
Style::Crate => crate_compliant(self_merge, stmts),
}
}
fn is_item_shaped(stmt: &StmtInfo) -> bool {
match stmt.top_kind {
TopKind::Simple | TopKind::Glob => true,
TopKind::Nested => {
matches!(stmt.leaves.as_slice(), [leaf] if matches!(leaf.item, LeafItem::SelfMod))
}
}
}
fn module_compliant(stmts: &[&StmtInfo]) -> bool {
if !stmts.iter().all(|stmt| is_module_shaped(stmt)) {
return false;
}
let mut seen: HashSet<&[String]> = HashSet::new();
for stmt in stmts {
if stmt.is_crate_item() {
continue;
}
let module = stmt.common_module().expect("shaped ⇒ single module");
if !seen.insert(module) {
return false;
}
}
true
}
fn is_module_shaped(stmt: &StmtInfo) -> bool {
match stmt.top_kind {
TopKind::Simple | TopKind::Glob => true,
TopKind::Nested => {
!stmt.prefix.is_empty()
&& stmt
.common_module()
.is_some_and(|module| module == stmt.prefix.as_slice())
}
}
}
fn crate_compliant(self_merge: Option<SelfMerge>, stmts: &[&StmtInfo]) -> bool {
let off_shape = match self_merge {
Some(SelfMerge::Fold) => stmts.iter().any(|stmt| has_bare_item_dual(&stmt.leaves)),
Some(SelfMerge::Split) => stmts.iter().any(|stmt| has_self_dual(&stmt.leaves)),
None => false,
};
if off_shape {
return false;
}
if !stmts.iter().all(|stmt| stmt.collapsed) {
return false;
}
let bare_item_roots: HashSet<&str> = stmts
.iter()
.filter(|stmt| stmt.is_crate_item())
.filter_map(|stmt| stmt.crate_root())
.collect();
let mut seen: HashSet<&str> = HashSet::new();
for stmt in stmts {
let Some(root) = stmt.crate_root() else {
return false;
};
if bare_item_roots.contains(root) {
continue;
}
if !seen.insert(root) {
return false;
}
}
true
}