use super::{GeometryRouter, ReasonCount};
use ifc_lite_core::DecodedEntity;
use rustc_hash::{FxHashMap, FxHashSet};
#[derive(Default)]
pub(crate) struct UnsupportedItemState {
counts: FxHashMap<String, u64>,
sources_recorded: FxHashSet<u32>,
scope: Vec<bool>,
}
impl UnsupportedItemState {
pub(crate) fn forget_sources(&mut self) {
self.sources_recorded.clear();
}
}
impl GeometryRouter {
pub(crate) fn enter_unsupported_source(
&self,
source_id: u32,
mapped_repr: &DecodedEntity,
) -> UnsupportedSourceScope<'_> {
let is_body = crate::router::effective_rep_type(mapped_repr)
.is_none_or(crate::router::is_body_representation);
let mut state = self.unsupported.borrow_mut();
let record = is_body && state.sources_recorded.insert(source_id);
state.scope.push(record);
UnsupportedSourceScope { router: self }
}
pub(crate) fn record_unsupported_item(&self, ifc_type: ifc_lite_core::IfcType) {
let mut state = self.unsupported.borrow_mut();
if state.scope.last() == Some(&false) {
return;
}
let name = ifc_type.name();
match state.counts.get_mut(name) {
Some(count) => *count += 1,
None => {
state.counts.insert(name.to_string(), 1);
}
}
}
pub fn take_unsupported_items(&self) -> FxHashMap<String, u64> {
std::mem::take(&mut self.unsupported.borrow_mut().counts)
}
}
pub(crate) struct UnsupportedSourceScope<'a> {
router: &'a GeometryRouter,
}
impl Drop for UnsupportedSourceScope<'_> {
fn drop(&mut self) {
self.router.unsupported.borrow_mut().scope.pop();
}
}
pub fn format_unsupported_breakdown(items: &FxHashMap<String, u64>) -> String {
let (_total, by_type) = summarize(items);
by_type
.iter()
.map(|rc| format!("{}={}", rc.reason, rc.count))
.collect::<Vec<_>>()
.join(", ")
}
pub fn summarize(items: &FxHashMap<String, u64>) -> (u64, Vec<ReasonCount>) {
let total = items.values().sum();
let mut by_type: Vec<ReasonCount> = items
.iter()
.map(|(ifc_type, count)| ReasonCount { reason: ifc_type.clone(), count: *count })
.collect();
by_type.sort_by(|a, b| b.count.cmp(&a.count).then_with(|| a.reason.cmp(&b.reason)));
(total, by_type)
}