prns-core 0.3.4

Pure Reticulum engine and wire contract for Personal Reticulum
use heapless::Vec as HeaplessVec;

use crate::engine::CommandId;
use crate::engine::InstantMillis;
use crate::identity::IdentitySigningPublicKey;
use crate::routing::dedup::PacketHash;
use crate::routing::delivery::receipts::{
    OutstandingReceipt, ReceiptDeadline, ReceiptKind, ReceiptTable, TrackReceiptError,
};

#[derive(Debug, Default)]
pub struct FixedReceiptTable<const MAX_OUTSTANDING_RECEIPTS: usize> {
    packet_hashes: HeaplessVec<PacketHash, MAX_OUTSTANDING_RECEIPTS>,
    command_ids: HeaplessVec<CommandId, MAX_OUTSTANDING_RECEIPTS>,
    kinds: HeaplessVec<ReceiptKind, MAX_OUTSTANDING_RECEIPTS>,
    signing_keys: HeaplessVec<IdentitySigningPublicKey, MAX_OUTSTANDING_RECEIPTS>,
    sent_ats: HeaplessVec<InstantMillis, MAX_OUTSTANDING_RECEIPTS>,
    deadlines: HeaplessVec<ReceiptDeadline, MAX_OUTSTANDING_RECEIPTS>,
}

impl<const MAX_OUTSTANDING_RECEIPTS: usize> ReceiptTable
    for FixedReceiptTable<MAX_OUTSTANDING_RECEIPTS>
{
    fn capacity(&self) -> usize {
        MAX_OUTSTANDING_RECEIPTS
    }
    fn len(&self) -> usize {
        self.packet_hashes.len()
    }

    fn packet_hashes(&self) -> &[PacketHash] {
        &self.packet_hashes
    }
    fn command_ids(&self) -> &[CommandId] {
        &self.command_ids
    }
    fn kinds(&self) -> &[ReceiptKind] {
        &self.kinds
    }
    fn signing_keys(&self) -> &[IdentitySigningPublicKey] {
        &self.signing_keys
    }
    fn sent_ats(&self) -> &[InstantMillis] {
        &self.sent_ats
    }
    fn deadlines(&self) -> &[ReceiptDeadline] {
        &self.deadlines
    }
    fn set_deadline(&mut self, index: usize, deadline: ReceiptDeadline) {
        if let Some(slot) = self.deadlines.get_mut(index) {
            *slot = deadline;
        }
    }

    fn push(&mut self, receipt: OutstandingReceipt) -> Result<usize, TrackReceiptError> {
        if self.packet_hashes.is_full() {
            return Err(TrackReceiptError::TableFull);
        }
        let index = self.packet_hashes.len();
        let _ = self.packet_hashes.push(receipt.packet_hash);
        let _ = self.command_ids.push(receipt.command_id);
        let _ = self.kinds.push(receipt.kind);
        let _ = self.signing_keys.push(receipt.peer_signing_key);
        let _ = self.sent_ats.push(receipt.sent_at);
        let _ = self
            .deadlines
            .push(ReceiptDeadline::Due(receipt.timeout_at));
        Ok(index)
    }

    fn remove(&mut self, index: usize) {
        if index >= self.packet_hashes.len() {
            return;
        }
        self.packet_hashes.remove(index);
        self.command_ids.remove(index);
        self.kinds.remove(index);
        self.signing_keys.remove(index);
        self.sent_ats.remove(index);
        self.deadlines.remove(index);
    }
}