1use std::collections::{HashMap, HashSet};
2
3use petgraph::{Graph, algo, visit::Dfs};
4
5pub fn expand_features<'a>(
7 features: &Vec<String>,
8 table: &'a HashMap<String, Vec<String>>,
9) -> anyhow::Result<HashSet<&'a String>> {
10 let mut graph = Graph::new();
11 let mut indeies = HashMap::new();
12
13 for (feature, deps) in table {
15 let index = if indeies.contains_key(feature) {
16 indeies[feature]
17 } else {
18 let i = graph.add_node(feature);
19 indeies.insert(feature.to_string(), i);
20 i
21 };
22 for dep in deps {
23 let dep_index = if indeies.contains_key(dep) {
24 indeies[dep]
25 } else {
26 let i = graph.add_node(dep);
27 indeies.insert(dep.to_string(), i);
28 i
29 };
30 graph.add_edge(index, dep_index, ());
31 }
32 }
33
34 if algo::is_cyclic_directed(&graph) {
36 return Err(anyhow::anyhow!(
37 "There is a cyclic dependency between features."
38 ));
39 }
40
41 let mut result = HashSet::new();
43 for feature in features {
44 if !indeies.contains_key(feature) {
45 return Err(anyhow::anyhow!("Feature {} is not defined.", feature));
46 }
47 let index = indeies[feature];
48 result.insert(graph[index]);
49 let mut visited = Dfs::new(&graph, index);
50 while let Some(node) = visited.next(&graph) {
51 result.insert(graph[node]);
52 }
53 }
54
55 Ok(result)
56}