Add loop protection

This commit is contained in:
2023-08-05 12:10:23 +02:00
parent eaf09135f4
commit 5506149efc
3 changed files with 98 additions and 1 deletions

View File

@ -106,3 +106,86 @@ pub async fn delete_all_family(family_id: FamilyID) -> anyhow::Result<()> {
}
Ok(())
}
pub mod loop_detection {
use crate::models::{Member, MemberID};
use std::collections::HashMap;
#[derive(Debug)]
struct LoopStack<'a> {
curr: MemberID,
prev: Option<&'a LoopStack<'a>>,
}
impl<'a> LoopStack<'a> {
pub fn contains(&self, id: MemberID) -> bool {
if let Some(ls) = &self.prev {
if ls.contains(id) {
return true;
}
}
self.curr == id
}
}
fn detect_loop_control(
members: &HashMap<MemberID, &&Member>,
curr_stack: &LoopStack,
next: Option<MemberID>,
) -> bool {
match next {
None => false,
Some(id) => {
if curr_stack.contains(id) {
log::debug!("Loop detected! {:?}", curr_stack);
return true;
}
detect_loop_recurse(
members,
&LoopStack {
curr: id,
prev: Some(curr_stack),
},
)
}
}
}
/// Recurse loop detection
fn detect_loop_recurse(members: &HashMap<MemberID, &&Member>, curr_stack: &LoopStack) -> bool {
let member = match members.get(&curr_stack.curr) {
Some(m) => m,
None => {
log::warn!("Member {:?} not found in the tree for loop detection, this should never happen!", curr_stack.curr);
return false;
}
};
detect_loop_control(members, curr_stack, member.mother())
|| detect_loop_control(members, curr_stack, member.father())
}
/// Detect loops in members hierarchy
pub fn detect_loop(members: &[&Member]) -> bool {
let mut map = HashMap::new();
for m in members {
map.insert(m.id(), m);
}
for m in members {
if detect_loop_recurse(
&map,
&LoopStack {
curr: m.id(),
prev: None,
},
) {
return true;
}
}
false
}
}