robotrt-middleware-core 0.1.0-beta.2

RobotRT modular robotics runtime and middleware components.
Documentation
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BridgeTrafficKind {
    Topic,
    Service,
    Mission,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BridgeDropReason {
    KindNotAllowed,
    LabelMismatch,
}

#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct BridgeStats {
    pub forwarded: u64,
    pub dropped_kind: u64,
    pub dropped_label: u64,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BridgePolicy {
    pub allow_topic: bool,
    pub allow_service: bool,
    pub allow_mission: bool,
    pub include_labels: Vec<String>,
}

impl Default for BridgePolicy {
    fn default() -> Self {
        Self {
            allow_topic: true,
            allow_service: true,
            allow_mission: true,
            include_labels: Vec::new(),
        }
    }
}

impl BridgePolicy {
    pub fn should_forward(&self, kind: BridgeTrafficKind, labels: &[String]) -> bool {
        let kind_allowed = match kind {
            BridgeTrafficKind::Topic => self.allow_topic,
            BridgeTrafficKind::Service => self.allow_service,
            BridgeTrafficKind::Mission => self.allow_mission,
        };

        if !kind_allowed {
            return false;
        }

        if self.include_labels.is_empty() {
            return true;
        }

        self.include_labels
            .iter()
            .all(|label| labels.iter().any(|candidate| candidate == label))
    }

    pub fn evaluate_with_stats(
        &self,
        kind: BridgeTrafficKind,
        labels: &[String],
        stats: &mut BridgeStats,
    ) -> bool {
        let kind_allowed = match kind {
            BridgeTrafficKind::Topic => self.allow_topic,
            BridgeTrafficKind::Service => self.allow_service,
            BridgeTrafficKind::Mission => self.allow_mission,
        };

        if !kind_allowed {
            stats.dropped_kind += 1;
            return false;
        }

        if !self.include_labels.is_empty() {
            let labels_match = self
                .include_labels
                .iter()
                .all(|label| labels.iter().any(|candidate| candidate == label));
            if !labels_match {
                stats.dropped_label += 1;
                return false;
            }
        }

        stats.forwarded += 1;
        true
    }
}