prns-core 0.3.4

Pure Reticulum engine and wire contract for Personal Reticulum
use crate::crypto::{Ed25519PublicKey, X25519PublicKey};
use crate::identity::destination_identity::{DestinationIdentityRecord, DestinationIdentityTable};
use crate::identity::{
    DestinationIdentityRetentionState, IdentityEncryptionPublicKey, IdentityPublicKeys,
    IdentitySigningPublicKey,
};
use crate::routing::announce::stored::AppDataHandle;
use crate::storage::TablePushError;
use crate::units::InstantMillis;
use crate::wire::DestinationHash;

#[derive(Debug)]
pub struct FixedArrayDestinationIdentityTable<const CAPACITY: usize> {
    len: usize,
    destinations: [DestinationHash; CAPACITY],
    public_keys: [IdentityPublicKeys; CAPACITY],
    announced_at: [InstantMillis; CAPACITY],
    retention: [DestinationIdentityRetentionState; CAPACITY],
    app_data_handles: [AppDataHandle; CAPACITY],
}

impl<const CAPACITY: usize> Default for FixedArrayDestinationIdentityTable<CAPACITY> {
    fn default() -> Self {
        Self {
            len: 0,
            destinations: [DestinationHash::new([0; 16]); CAPACITY],
            public_keys: [IdentityPublicKeys {
                encryption: IdentityEncryptionPublicKey::new(X25519PublicKey([0; 32])),
                signing: IdentitySigningPublicKey::new(Ed25519PublicKey([0; 32])),
            }; CAPACITY],
            announced_at: [InstantMillis(0); CAPACITY],
            retention: [DestinationIdentityRetentionState::NeverUsed; CAPACITY],
            app_data_handles: [AppDataHandle::new(0); CAPACITY],
        }
    }
}

impl<const CAPACITY: usize> DestinationIdentityTable
    for FixedArrayDestinationIdentityTable<CAPACITY>
{
    fn capacity(&self) -> usize {
        CAPACITY
    }

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

    fn destinations(&self) -> &[DestinationHash] {
        &self.destinations[..self.len]
    }

    fn public_keys(&self) -> &[IdentityPublicKeys] {
        &self.public_keys[..self.len]
    }

    fn announced_at(&self) -> &[InstantMillis] {
        &self.announced_at[..self.len]
    }

    fn retention(&self) -> &[DestinationIdentityRetentionState] {
        &self.retention[..self.len]
    }

    fn app_data_handles(&self) -> &[AppDataHandle] {
        &self.app_data_handles[..self.len]
    }

    fn set_row(&mut self, index: usize, record: DestinationIdentityRecord) {
        self.public_keys[index] = record.public_keys;
        self.announced_at[index] = record.announced_at;
        self.retention[index] = record.retention;
        self.app_data_handles[index] = record.app_data_handle;
    }

    fn push(
        &mut self,
        destination: DestinationHash,
        record: DestinationIdentityRecord,
    ) -> Result<usize, TablePushError> {
        if self.len >= CAPACITY {
            return Err(TablePushError::TableFull);
        }
        let index = self.len;
        self.destinations[index] = destination;
        self.set_row(index, record);
        self.len += 1;
        Ok(index)
    }

    fn swap_remove(&mut self, index: usize) {
        let last = self.len - 1;
        if index != last {
            self.destinations[index] = self.destinations[last];
            self.public_keys[index] = self.public_keys[last];
            self.announced_at[index] = self.announced_at[last];
            self.retention[index] = self.retention[last];
            self.app_data_handles[index] = self.app_data_handles[last];
        }
        self.len = last;
    }
}