prns-core 0.3.4

Pure Reticulum engine and wire contract for Personal Reticulum
use alloc::vec::Vec;

use crate::identity::IdentityHash;
use crate::routing::request_handlers::{RequestHandlerTable, RequestPathHash, RequestPolicy};
use crate::storage::TablePushError;
use crate::wire::DestinationHash;

#[derive(Debug, Default)]
pub struct HeapRequestHandlerTable {
    destinations: Vec<DestinationHash>,
    path_hashes: Vec<RequestPathHash>,
    policies: Vec<RequestPolicy>,
    allowed: Vec<Vec<IdentityHash>>,
}

impl RequestHandlerTable for HeapRequestHandlerTable {
    fn capacity(&self) -> usize {
        usize::MAX
    }
    fn len(&self) -> usize {
        self.destinations.len()
    }

    fn destinations(&self) -> &[DestinationHash] {
        &self.destinations
    }
    fn path_hashes(&self) -> &[RequestPathHash] {
        &self.path_hashes
    }
    fn policies(&self) -> &[RequestPolicy] {
        &self.policies
    }

    fn push(
        &mut self,
        destination: DestinationHash,
        path_hash: RequestPathHash,
        policy: RequestPolicy,
    ) -> Result<(), TablePushError> {
        self.destinations.push(destination);
        self.path_hashes.push(path_hash);
        self.policies.push(policy);
        self.allowed.push(Vec::new());
        Ok(())
    }

    fn remove_at(&mut self, slot: usize) {
        if slot < self.destinations.len() {
            self.destinations.remove(slot);
            self.path_hashes.remove(slot);
            self.policies.remove(slot);
            self.allowed.remove(slot);
        }
    }

    fn set_policy_at(&mut self, slot: usize, policy: RequestPolicy) {
        if let Some(existing) = self.policies.get_mut(slot) {
            *existing = policy;
        }
    }

    fn clear_allowed_at(&mut self, slot: usize) {
        if let Some(list) = self.allowed.get_mut(slot) {
            list.clear();
        }
    }

    fn allowed_contains_at(&self, slot: usize, identity: &IdentityHash) -> bool {
        self.allowed
            .get(slot)
            .is_some_and(|list| list.contains(identity))
    }

    fn allow_at(&mut self, slot: usize, identity: IdentityHash) -> Result<(), TablePushError> {
        let Some(list) = self.allowed.get_mut(slot) else {
            return Err(TablePushError::TableFull);
        };
        list.push(identity);
        Ok(())
    }

    fn disallow_at(&mut self, slot: usize, identity: &IdentityHash) {
        if let Some(list) = self.allowed.get_mut(slot) {
            list.retain(|candidate| candidate != identity);
        }
    }
}