use std::collections::{BTreeMap, BTreeSet, VecDeque};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ContractInherit {
pub contract_id: i32,
pub inherited_id: i32,
}
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
pub struct InheritanceGraph {
pub inherits: Vec<ContractInherit>,
}
impl InheritanceGraph {
pub fn new(inherits: Vec<ContractInherit>) -> Self {
Self { inherits }
}
pub fn is_empty(&self) -> bool {
self.inherits.is_empty()
}
pub fn len(&self) -> usize {
self.inherits.len()
}
fn build_descendant_index(&self) -> BTreeMap<i32, Vec<i32>> {
let mut children: BTreeMap<i32, Vec<i32>> = BTreeMap::new();
for edge in &self.inherits {
children
.entry(edge.inherited_id)
.or_default()
.push(edge.contract_id);
}
children
}
fn build_ancestor_index(&self) -> BTreeMap<i32, Vec<i32>> {
let mut parents: BTreeMap<i32, Vec<i32>> = BTreeMap::new();
for edge in &self.inherits {
parents
.entry(edge.contract_id)
.or_default()
.push(edge.inherited_id);
}
parents
}
pub fn descendants_of(&self, ancestor_id: i32) -> BTreeSet<i32> {
let children = self.build_descendant_index();
Self::bfs_closure(&children, ancestor_id)
}
pub fn ancestors_of(&self, child_id: i32) -> BTreeSet<i32> {
let parents = self.build_ancestor_index();
Self::bfs_closure(&parents, child_id)
}
fn bfs_closure(index: &BTreeMap<i32, Vec<i32>>, start: i32) -> BTreeSet<i32> {
let mut out: BTreeSet<i32> = BTreeSet::new();
let mut queue: VecDeque<i32> = VecDeque::new();
queue.push_back(start);
while let Some(node) = queue.pop_front() {
if let Some(neighbours) = index.get(&node) {
for &next in neighbours {
if out.insert(next) {
queue.push_back(next);
}
}
}
}
out
}
}
#[cfg(test)]
mod tests {
use super::*;
fn edge(c: i32, i: i32) -> ContractInherit {
ContractInherit {
contract_id: c,
inherited_id: i,
}
}
#[test]
fn descendants_transitive() {
let g = InheritanceGraph::new(vec![edge(2, 1), edge(3, 2)]);
assert_eq!(g.descendants_of(1), BTreeSet::from([2, 3]));
assert_eq!(g.descendants_of(2), BTreeSet::from([3]));
assert_eq!(g.descendants_of(3), BTreeSet::new());
}
#[test]
fn ancestors_transitive() {
let g = InheritanceGraph::new(vec![edge(2, 1), edge(3, 2)]);
assert_eq!(g.ancestors_of(3), BTreeSet::from([1, 2]));
assert_eq!(g.ancestors_of(2), BTreeSet::from([1]));
assert_eq!(g.ancestors_of(1), BTreeSet::new());
}
#[test]
fn cycle_safe() {
let g = InheritanceGraph::new(vec![edge(1, 2), edge(2, 1)]);
let d = g.descendants_of(1);
assert!(d.contains(&2) && d.contains(&1));
}
}