Sort some values in a topological order. Cycles can be allowed, in which case it will do its best to order the items with the least amount of dependencies first. This is so we can support nodes mutually be seeded by each other.
(
items: &BTreeMap<K, V>,
allow_cycles: bool,
f: F,
)
| 659 | /// with the least amount of dependencies first. This is so we can support nodes |
| 660 | /// mutually be seeded by each other. |
| 661 | fn topo_sort<K, V, F, I>( |
| 662 | items: &BTreeMap<K, V>, |
| 663 | allow_cycles: bool, |
| 664 | f: F, |
| 665 | ) -> anyhow::Result<Vec<(&K, &V)>> |
| 666 | where |
| 667 | F: Fn(&V) -> I, |
| 668 | K: Ord + Display + Clone, |
| 669 | I: IntoIterator<Item = K>, |
| 670 | { |
| 671 | let mut deps = items |
| 672 | .iter() |
| 673 | .map(|(k, v)| (k, BTreeSet::from_iter(f(v)))) |
| 674 | .collect::<BTreeMap<_, _>>(); |
| 675 | |
| 676 | for (k, ds) in deps.iter() { |
| 677 | for d in ds { |
| 678 | if !deps.contains_key(d) { |
| 679 | bail!("non-existing dependency: {d} <- {k}") |
| 680 | } |
| 681 | } |
| 682 | } |
| 683 | |
| 684 | let mut sorted = Vec::new(); |
| 685 | |
| 686 | while !deps.is_empty() { |
| 687 | let leaf: K = match deps.iter().find(|(_, ds)| ds.is_empty()) { |
| 688 | Some((leaf, _)) => (*leaf).clone(), |
| 689 | None if allow_cycles => { |
| 690 | let mut dcs = deps.iter().map(|(k, ds)| (k, ds.len())).collect::<Vec<_>>(); |
| 691 | dcs.sort_by_key(|(_, c)| *c); |
| 692 | let leaf = dcs.first().unwrap().0; |
| 693 | (*leaf).clone() |
| 694 | } |
| 695 | None => bail!("circular reference in dependencies"), |
| 696 | }; |
| 697 | |
| 698 | deps.remove(&leaf); |
| 699 | |
| 700 | for (_, ds) in deps.iter_mut() { |
| 701 | ds.remove(&leaf); |
| 702 | } |
| 703 | |
| 704 | if let Some(kv) = items.get_key_value(&leaf) { |
| 705 | sorted.push(kv); |
| 706 | } |
| 707 | } |
| 708 | |
| 709 | Ok(sorted) |
| 710 | } |
| 711 | |
| 712 | /// Sort nodes in a subnet in topological order, so we strive to first |
| 713 | /// start the ones others use as a seed node. However, do allow cycles |