prns-runtime 0.3.4

Runtime-neutral Personal Reticulum node contracts and manifold kernel
Documentation
use core::num::NonZeroUsize;

use alloc::vec::Vec;
use prns_core::lemire_index::HeapLemireIndex;

use crate::interfaces::{RssiDbm, SignalQualityTenthsPercent, SnrQuarterDb};
use crate::routing::dedup::PacketHash;

use super::{PacketMetricStorage, PacketPhyRetention};

pub const RNS_1_4_2_PACKET_PHY_CAPACITY: usize = 512;

pub struct HeapPacketMetricStorage<Metric, const CAPACITY: usize> {
    packet_hashes: Vec<PacketHash>,
    metrics: Vec<Metric>,
    index: HeapLemireIndex,
}

impl<Metric, const CAPACITY: usize> Default for HeapPacketMetricStorage<Metric, CAPACITY> {
    fn default() -> Self {
        const {
            assert!(
                CAPACITY > 0,
                "packet PHY retention capacity must be non-zero"
            );
            assert!(
                CAPACITY < u32::MAX as usize,
                "heap packet PHY retention exceeds its index slot range"
            );
        }
        Self {
            packet_hashes: Vec::with_capacity(CAPACITY),
            metrics: Vec::with_capacity(CAPACITY),
            index: HeapLemireIndex::default(),
        }
    }
}

impl<Metric: Copy, const CAPACITY: usize> PacketMetricStorage
    for HeapPacketMetricStorage<Metric, CAPACITY>
{
    type Metric = Metric;

    fn capacity(&self) -> NonZeroUsize {
        match NonZeroUsize::new(CAPACITY) {
            Some(capacity) => capacity,
            None => unreachable!("packet PHY retention capacity is non-zero"),
        }
    }

    fn len(&self) -> usize {
        self.packet_hashes.len()
    }

    fn append(&mut self, packet_hash: PacketHash, metric: Metric) {
        self.packet_hashes.push(packet_hash);
        self.metrics.push(metric);
        self.index
            .insert(self.packet_hashes.len() - 1, &self.packet_hashes);
    }

    fn replace(&mut self, slot: usize, packet_hash: PacketHash, metric: Metric) {
        self.index.remove_slot(slot, &self.packet_hashes);
        self.packet_hashes[slot] = packet_hash;
        self.metrics[slot] = metric;
        self.index.insert(slot, &self.packet_hashes);
    }

    fn get(&self, packet_hash: PacketHash) -> Option<Metric> {
        self.index
            .get(&packet_hash, &self.packet_hashes)
            .map(|slot| self.metrics[slot])
    }
}

pub type HeapPacketPhyRetention = PacketPhyRetention<
    HeapPacketMetricStorage<RssiDbm, RNS_1_4_2_PACKET_PHY_CAPACITY>,
    HeapPacketMetricStorage<SnrQuarterDb, RNS_1_4_2_PACKET_PHY_CAPACITY>,
    HeapPacketMetricStorage<SignalQualityTenthsPercent, RNS_1_4_2_PACKET_PHY_CAPACITY>,
>;