a2lfile/cleanup/
groups.rs1use std::collections::HashSet;
2
3use crate::specification::{Group, Module};
4
5pub(crate) fn cleanup(module: &mut Module) {
6 remove_invalid_object_references(module);
8
9 delete_empty_groups(module);
11}
12
13fn remove_invalid_object_references(module: &mut Module) {
14 let refnames = build_refname_set(module);
16
17 for grp in &mut module.group {
18 if let Some(ref_characteristic) = &mut grp.ref_characteristic {
19 ref_characteristic
21 .identifier_list
22 .retain(|item| refnames.contains(item));
23 if ref_characteristic.identifier_list.is_empty() {
24 grp.ref_characteristic = None;
25 }
26 }
27 if let Some(ref_measurement) = &mut grp.ref_measurement {
28 ref_measurement
30 .identifier_list
31 .retain(|item| refnames.contains(item));
32 if ref_measurement.identifier_list.is_empty() {
33 grp.ref_measurement = None;
34 }
35 }
36 }
37}
38
39fn build_refname_set(module: &Module) -> HashSet<String> {
40 let mut refnames = HashSet::new();
41 for name in module.characteristic.keys() {
42 refnames.insert(name.clone());
43 }
44 for name in module.measurement.keys() {
45 refnames.insert(name.clone());
46 }
47 for name in module.blob.keys() {
48 refnames.insert(name.clone());
49 }
50 for name in module.instance.keys() {
51 refnames.insert(name.clone());
52 }
53
54 refnames
55}
56
57fn delete_empty_groups(module: &mut Module) {
58 let used_groups = get_used_groups(module);
59 let mut user_of = vec![Vec::<usize>::new(); module.group.len()];
60 let mut delete_queue: Vec<usize> = vec![];
61 for (idx, grp) in module.group.iter().enumerate() {
62 if let Some(sub_group) = &grp.sub_group {
64 for name in &sub_group.identifier_list {
65 if let Some(subidx) = module.group.index(name) {
66 user_of[subidx].push(idx);
67 }
68 }
69 }
70
71 if !used_groups.contains(&grp.name) && is_group_empty(grp) {
73 delete_queue.push(idx);
74 }
75 }
76 let mut to_delete = vec![false; module.group.len()];
77 while let Some(del_idx) = delete_queue.pop() {
79 let name = module.group[del_idx].name.clone();
80 to_delete[del_idx] = true;
81
82 for refidx in &user_of[del_idx] {
84 if let Some(sg) = &mut module.group[*refidx].sub_group {
85 sg.identifier_list.retain(|item| *item != name);
87 if sg.identifier_list.is_empty() {
88 module.group[*refidx].sub_group = None;
89 }
90 }
91 if !used_groups.contains(&module.group[*refidx].name)
94 && is_group_empty(&module.group[*refidx])
95 {
96 delete_queue.push(*refidx);
97 }
98 }
99 }
100
101 let mut del_iter = to_delete.iter();
102 module.group.retain(|_| !del_iter.next().unwrap());
103}
104
105fn get_used_groups(module: &Module) -> HashSet<String> {
106 let mut used_groups = HashSet::<String>::new();
107 for user_rights in &module.user_rights {
108 for ref_group in &user_rights.ref_group {
109 for groupname in &ref_group.identifier_list {
110 used_groups.insert(groupname.to_owned());
111 }
112 }
113 }
114
115 used_groups
116}
117
118fn is_group_empty(group: &Group) -> bool {
119 let sub_group_empty = if let Some(sg) = &group.sub_group {
120 sg.identifier_list.is_empty()
121 } else {
122 true
123 };
124
125 let ref_measurement_empty = if let Some(rm) = &group.ref_measurement {
126 rm.identifier_list.is_empty()
127 } else {
128 true
129 };
130
131 let ref_characteristic_empty = if let Some(rc) = &group.ref_characteristic {
132 rc.identifier_list.is_empty()
133 } else {
134 true
135 };
136
137 sub_group_empty && ref_characteristic_empty && ref_measurement_empty
141}