crate::ix!();
#[derive(Debug, Clone)]
pub enum CoreSkeletalNode {
Dispatch(CoreSkeletalDispatchNode),
Aggregate(CoreSkeletalAggregateNode),
LeafHolder(CoreSkeletalLeafHolderNode),
}
impl CoreSkeletalNode {
pub fn name(&self) -> &String {
match self {
CoreSkeletalNode::Dispatch(n) => n.name(),
CoreSkeletalNode::Aggregate(n) => n.name(),
CoreSkeletalNode::LeafHolder(n) => n.name(),
}
}
}
impl CoreStringSkeleton {
#[instrument(level = "trace", skip_all)]
pub fn top_down_nodes(&self) -> Vec<CoreSkeletalNode> {
use std::collections::{HashMap, HashSet, VecDeque};
let mut child_set = HashSet::<String>::new();
let mut adj: HashMap<String, Vec<String>> = HashMap::new();
for n in self.dispatch_nodes() {
let entry = adj.entry(n.name().clone()).or_default();
for ch in n.children() {
child_set.insert(ch.name().clone());
entry.push(ch.name().clone());
}
}
for n in self.aggregate_nodes() {
let entry = adj.entry(n.name().clone()).or_default();
for ch in n.children() {
child_set.insert(ch.name().clone());
entry.push(ch.name().clone());
}
}
let mut all_names = HashSet::<String>::new();
for n in self.dispatch_nodes() { all_names.insert(n.name().clone()); }
for n in self.aggregate_nodes() { all_names.insert(n.name().clone()); }
for n in self.leaf_holder_nodes() { all_names.insert(n.name().clone()); }
let roots: Vec<String> = all_names.iter()
.filter(|n| !child_set.contains(*n))
.cloned()
.collect();
trace!(?roots, "identified root nodes for `top_down_nodes`");
let mut depth: HashMap<String, usize> = HashMap::new();
let mut q: VecDeque<(String, usize)> = roots.into_iter().map(|r| (r, 0)).collect();
while let Some((name, d)) = q.pop_front() {
if depth.contains_key(&name) { continue; }
depth.insert(name.clone(), d);
for ch in adj.get(&name).unwrap_or(&Vec::new()) {
q.push_back((ch.clone(), d + 1));
}
}
let fallback = depth.values().copied().max().unwrap_or(0) + 1;
for n in &all_names { depth.entry(n.clone()).or_insert(fallback); }
let mut combined: Vec<CoreSkeletalNode> = Vec::with_capacity(all_names.len());
combined.extend(self.dispatch_nodes().iter().cloned().map(CoreSkeletalNode::Dispatch));
combined.extend(self.aggregate_nodes().iter().cloned().map(CoreSkeletalNode::Aggregate));
combined.extend(self.leaf_holder_nodes().iter().cloned().map(CoreSkeletalNode::LeafHolder));
combined.sort_by(|a, b| {
depth[a.name()]
.cmp(&depth[b.name()])
.then(a.name().cmp(b.name()))
});
combined
}
}