use serde_reflection::{ContainerFormat, Format, FormatHolder, Registry, Result};
use std::collections::{BTreeMap, BTreeSet, HashSet};
fn get_dependencies<'a>(
format: &'a ContainerFormat,
external: &BTreeSet<String>,
) -> Result<BTreeSet<&'a str>> {
let mut result = BTreeSet::new();
format.visit(&mut |format| {
if let Format::TypeName(x) = format {
if !external.contains(x) {
result.insert(x.as_str());
}
}
Ok(())
})?;
Ok(result)
}
pub fn get_dependency_map(registry: &Registry) -> Result<BTreeMap<&str, BTreeSet<&str>>> {
get_dependency_map_with_external_dependencies(registry, &BTreeSet::new())
}
pub fn get_dependency_map_with_external_dependencies<'a>(
registry: &'a Registry,
external: &BTreeSet<String>,
) -> Result<BTreeMap<&'a str, BTreeSet<&'a str>>> {
let mut children = BTreeMap::new();
for (name, format) in registry {
children.insert(name.as_str(), get_dependencies(format, external)?);
}
Ok(children)
}
pub fn best_effort_topological_sort<T>(children: &BTreeMap<T, BTreeSet<T>>) -> Vec<T>
where
T: Clone + std::fmt::Debug + std::cmp::Ord + std::cmp::Eq + std::hash::Hash,
{
let mut queue: Vec<_> = children.keys().rev().cloned().collect();
queue.sort_by(|node1, node2| children[node1].len().cmp(&children[node2].len()));
let mut result = Vec::new();
let mut sorted = HashSet::new();
let mut seen = HashSet::new();
while let Some(node) = queue.pop() {
if sorted.contains(&node) {
continue;
}
if seen.contains(&node) {
sorted.insert(node.clone());
result.push(node);
continue;
}
seen.insert(node.clone());
queue.push(node.clone());
if !children.contains_key(&node) {
panic!("The node {node:?} is missing");
}
for child in children[&node].iter().rev() {
if !seen.contains(child) {
queue.push(child.clone());
}
}
}
result
}