use std::collections::{HashMap, HashSet};
use petgraph::{Graph, algo, visit::Dfs};
pub fn expand_features<'a>(
features: &Vec<String>,
table: &'a HashMap<String, Vec<String>>,
) -> anyhow::Result<HashSet<&'a String>> {
let mut graph = Graph::new();
let mut indeies = HashMap::new();
for (feature, deps) in table {
let index = if indeies.contains_key(feature) {
indeies[feature]
} else {
let i = graph.add_node(feature);
indeies.insert(feature.to_string(), i);
i
};
for dep in deps {
let dep_index = if indeies.contains_key(dep) {
indeies[dep]
} else {
let i = graph.add_node(dep);
indeies.insert(dep.to_string(), i);
i
};
graph.add_edge(index, dep_index, ());
}
}
if algo::is_cyclic_directed(&graph) {
return Err(anyhow::anyhow!(
"There is a cyclic dependency between features."
));
}
let mut result = HashSet::new();
for feature in features {
if !indeies.contains_key(feature) {
return Err(anyhow::anyhow!("Feature {} is not defined.", feature));
}
let index = indeies[feature];
result.insert(graph[index]);
let mut visited = Dfs::new(&graph, index);
while let Some(node) = visited.next(&graph) {
result.insert(graph[node]);
}
}
Ok(result)
}