Determine the order to insert a set of changes respecting dependencies. This performs a topological sort of the changes based on their dependency relationships. # Arguments `changes` - Map of change hash to change # Returns Ordered list of hashes to insert (dependencies first).
(
changes: &std::collections::HashMap<Hash, Change>,
)
| 155 | /// |
| 156 | /// Ordered list of hashes to insert (dependencies first). |
| 157 | pub fn compute_insert_order( |
| 158 | changes: &std::collections::HashMap<Hash, Change>, |
| 159 | ) -> InsertResult<Vec<Hash>> { |
| 160 | let mut order = Vec::new(); |
| 161 | let mut visited = HashSet::new(); |
| 162 | let mut in_progress = HashSet::new(); |
| 163 | |
| 164 | fn visit( |
| 165 | hash: &Hash, |
| 166 | changes: &std::collections::HashMap<Hash, Change>, |
| 167 | visited: &mut HashSet<Hash>, |
| 168 | in_progress: &mut HashSet<Hash>, |
| 169 | order: &mut Vec<Hash>, |
| 170 | ) -> InsertResult<()> { |
| 171 | if visited.contains(hash) { |
| 172 | return Ok(()); |
| 173 | } |
| 174 | if in_progress.contains(hash) { |
| 175 | return Err(InsertError::CyclicDependency { |
| 176 | message: format!("Cycle detected involving {}", hash.to_base32()), |
| 177 | }); |
| 178 | } |
| 179 | |
| 180 | in_progress.insert(*hash); |
| 181 | |
| 182 | if let Some(change) = changes.get(hash) { |
| 183 | for dep in change.dependencies() { |
| 184 | if changes.contains_key(dep) { |
| 185 | visit(dep, changes, visited, in_progress, order)?; |
| 186 | } |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | in_progress.remove(hash); |
| 191 | visited.insert(*hash); |
| 192 | order.push(*hash); |
| 193 | |
| 194 | Ok(()) |
| 195 | } |
| 196 | |
| 197 | for hash in changes.keys() { |
| 198 | visit(hash, changes, &mut visited, &mut in_progress, &mut order)?; |
| 199 | } |
| 200 | |
| 201 | Ok(order) |
| 202 | } |
| 203 | |
| 204 | /// Write a change to the graph and add it to a view's change log. |
| 205 | /// |