use std::collections::{HashMap, HashSet};
#[derive(Debug, Default)]
pub struct PidLineage {
parent_map: HashMap<u32, u32>,
}
impl PidLineage {
pub fn new() -> Self {
Self::default()
}
pub fn register(&mut self, child_pid: u32, parent_pid: u32) {
self.parent_map.insert(child_pid, parent_pid);
}
pub fn is_same_family(&self, pid_a: u32, pid_b: u32) -> bool {
if pid_a == pid_b {
return true;
}
const MAX_DEPTH: usize = 64;
let mut ancestors_a = HashSet::new();
ancestors_a.insert(pid_a);
let mut current = pid_a;
for _ in 0..MAX_DEPTH {
match self.parent_map.get(¤t) {
Some(&parent) if !ancestors_a.contains(&parent) => {
ancestors_a.insert(parent);
current = parent;
}
_ => break,
}
}
if ancestors_a.contains(&pid_b) {
return true;
}
current = pid_b;
for _ in 0..MAX_DEPTH {
match self.parent_map.get(¤t) {
Some(&parent) => {
if ancestors_a.contains(&parent) {
return true;
}
current = parent;
}
None => break,
}
}
false
}
pub fn remove(&mut self, pid: u32) {
self.parent_map.remove(&pid);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_lineage_is_empty() {
let lineage = PidLineage::new();
assert!(lineage.parent_map.is_empty());
}
#[test]
fn register_adds_entry() {
let mut lineage = PidLineage::new();
lineage.register(100, 1);
assert_eq!(lineage.parent_map.get(&100), Some(&1));
}
#[test]
fn remove_deletes_entry() {
let mut lineage = PidLineage::new();
lineage.register(100, 1);
lineage.remove(100);
assert!(!lineage.parent_map.contains_key(&100));
}
#[test]
fn same_pid_is_same_family() {
let lineage = PidLineage::new();
assert!(lineage.is_same_family(42, 42));
}
#[test]
fn parent_child_is_same_family() {
let mut lineage = PidLineage::new();
lineage.register(100, 1);
assert!(lineage.is_same_family(1, 100));
assert!(lineage.is_same_family(100, 1));
}
#[test]
fn grandparent_grandchild_is_same_family() {
let mut lineage = PidLineage::new();
lineage.register(100, 1);
lineage.register(200, 100);
assert!(lineage.is_same_family(1, 200));
assert!(lineage.is_same_family(200, 1));
}
#[test]
fn shared_ancestor_is_same_family() {
let mut lineage = PidLineage::new();
lineage.register(100, 1);
lineage.register(200, 1);
assert!(lineage.is_same_family(100, 200));
assert!(lineage.is_same_family(200, 100));
}
#[test]
fn unrelated_pids_are_not_same_family() {
let mut lineage = PidLineage::new();
lineage.register(100, 1);
lineage.register(200, 2);
assert!(!lineage.is_same_family(100, 200));
}
#[test]
fn unknown_pids_are_not_same_family() {
let lineage = PidLineage::new();
assert!(!lineage.is_same_family(1, 2));
}
}