use crate::core::RiResult;
use std::collections::HashMap as FxHashMap;
use super::module_types::ModuleSlot;
pub(crate) fn sort_modules(modules: Vec<ModuleSlot>) -> RiResult<Vec<ModuleSlot>> {
let mut modules = modules;
let mut result: Vec<ModuleSlot> = Vec::with_capacity(modules.len());
while !modules.is_empty() {
let name_to_index: FxHashMap<&str, usize> = modules
.iter()
.enumerate()
.map(|(i, slot)| (slot.module.name(), i))
.collect();
let mut in_degree: Vec<usize> = vec![0; modules.len()];
for (i, slot) in modules.iter().enumerate() {
let dependencies = slot.module.dependencies();
for dep_name in dependencies {
if let Some(_dep_index) = name_to_index.get(dep_name) {
in_degree[i] += 1;
} else {
let dep_in_result = result.iter().any(|slot| slot.module.name() == dep_name);
if !dep_in_result {
return Err(crate::core::RiError::MissingDependency {
module_name: slot.module.name().to_string(),
dependency: dep_name.to_string()
});
}
}
}
}
let mut zero_in_degree: Vec<(i32, usize)> = in_degree
.iter()
.enumerate()
.filter(|&(_, °ree)| degree == 0)
.map(|(i, _)| (modules[i].module.priority(), i))
.collect();
if zero_in_degree.is_empty() {
return Err(crate::core::RiError::CircularDependency {
modules: modules.iter().map(|slot| slot.module.name().to_string()).collect()
});
}
zero_in_degree.sort_by(|a, b| {
a.0.cmp(&b.0).reverse().then_with(|| a.1.cmp(&b.1))
});
let mut indices_to_remove: Vec<usize> = zero_in_degree
.iter()
.map(|&(_, i)| i)
.collect();
indices_to_remove.sort_by(|a, b| b.cmp(a));
let mut added_modules: Vec<ModuleSlot> = Vec::with_capacity(indices_to_remove.len());
for &i in &indices_to_remove {
let module = modules.swap_remove(i);
added_modules.push(module);
}
added_modules.reverse();
result.extend(added_modules);
}
Ok(result)
}