noatun 0.1.3

Noatun is an in-process, distributed database with materialized view support.
Documentation
#![cfg(test)]
use indexmap::{IndexMap, IndexSet};

#[derive(Debug)]
pub struct MiniPather {
    whoami: u16,
    nodes: IndexMap<u16, Vec<u16>>,
}

impl MiniPather {
    pub fn new(whoami: u16) -> Self {
        Self {
            whoami,
            nodes: Default::default(),
        }
    }

    pub fn report_neighbors(&mut self, node: u16, hears_neighbors: impl IntoIterator<Item = u16>) {
        self.nodes
            .insert(node, hears_neighbors.into_iter().collect());
    }

    pub fn who_can_hear(&self, node: u16) -> Vec<u16> {
        let mut ret = vec![];
        for (other_node, other_hears) in &self.nodes {
            if other_hears.contains(&node) {
                ret.push(*other_node);
            }
        }
        ret
    }
    fn ranking(&self, of: u16) -> (isize, u16) {
        let neighbors = self
            .nodes
            .get(&of)
            .map(|x| {
                let mut x = x.clone();
                x.sort();
                x.dedup();
                x.len()
            })
            .unwrap_or(0);
        (-(neighbors as isize), of)
    }

    pub fn should_i_forward(&self, origin: u16, received_from: u16) -> bool {
        if origin == self.whoami || received_from == self.whoami {
            return false;
        }

        let mut recipients_solved = IndexSet::new();
        recipients_solved.insert(origin);
        recipients_solved.insert(received_from);
        recipients_solved.extend(self.who_can_hear(origin));
        recipients_solved.extend(self.who_can_hear(received_from));

        for (other_forwarder, other_forwarder_hears) in self
            .nodes
            .iter()
            .filter(|(x, _)| self.ranking(**x) < self.ranking(self.whoami))
        {
            if other_forwarder_hears.contains(&origin)
                || other_forwarder_hears.contains(&received_from)
            {
                recipients_solved.extend(self.who_can_hear(*other_forwarder));
            }
        }

        for (other_node, other_hears) in &self.nodes {
            if !other_hears.contains(&self.whoami) {
                continue;
            }
            if !recipients_solved.contains(other_node) {
                return true;
            }
        }

        false
    }
}