prns-core 0.3.4

Pure Reticulum engine and wire contract for Personal Reticulum
use crate::engine::InstantMillis;
use crate::routing::links::table::{LinkPhase, LinkTable, TrackLinkError};
use crate::routing::links::LinkId;

#[derive(Debug)]
pub struct FixedLinkTable<const MAX_LINKS: usize> {
    len: usize,
    link_ids: [LinkId; MAX_LINKS],
    timeout_ats: [Option<InstantMillis>; MAX_LINKS],
    phases: [LinkPhase; MAX_LINKS],
}

impl<const MAX_LINKS: usize> Default for FixedLinkTable<MAX_LINKS> {
    fn default() -> Self {
        Self {
            len: 0,
            link_ids: [LinkId::new([0u8; 16]); MAX_LINKS],
            timeout_ats: [None; MAX_LINKS],
            phases: core::array::from_fn(|_| LinkPhase::vacant()),
        }
    }
}

impl<const MAX_LINKS: usize> LinkTable for FixedLinkTable<MAX_LINKS> {
    fn capacity(&self) -> usize {
        MAX_LINKS
    }
    fn len(&self) -> usize {
        self.len
    }

    fn link_ids(&self) -> &[LinkId] {
        &self.link_ids[..self.len]
    }
    fn timeout_ats(&self) -> &[Option<InstantMillis>] {
        &self.timeout_ats[..self.len]
    }
    fn phases(&self) -> &[LinkPhase] {
        &self.phases[..self.len]
    }

    fn phase_mut(&mut self, index: usize) -> &mut LinkPhase {
        &mut self.phases[index]
    }

    fn set_timeout_at(&mut self, index: usize, timeout_at: Option<InstantMillis>) {
        self.timeout_ats[index] = timeout_at;
    }

    fn push(
        &mut self,
        link_id: LinkId,
        phase: LinkPhase,
        timeout_at: Option<InstantMillis>,
    ) -> Result<usize, TrackLinkError> {
        if self.len >= MAX_LINKS {
            return Err(TrackLinkError::TableFull);
        }
        let i = self.len;
        self.link_ids[i] = link_id;
        self.timeout_ats[i] = timeout_at;
        self.phases[i] = phase;
        self.len += 1;
        Ok(i)
    }

    fn swap_remove(&mut self, index: usize) {
        let last = self.len - 1;
        self.link_ids.swap(index, last);
        self.timeout_ats.swap(index, last);
        self.phases.swap(index, last);
        self.phases[last] = LinkPhase::vacant();
        self.len = last;
    }
}