use crate::engine::InstantMillis;
use crate::routing::links::resources::table::{
ResourceBuffers, ResourceRowState, ResourceTable, ResourceTablePushError,
};
use crate::routing::links::resources::{max_part_count, ResourceHash, MAP_HASH_LEN};
use crate::routing::links::LinkId;
#[derive(Debug)]
pub struct FixedResourceTable<
State: ResourceRowState,
const SLOTS: usize,
const TRANSFER_BYTES: usize,
const MAX_PARTS: usize,
> {
len: usize,
link_ids: [LinkId; SLOTS],
hashes: [ResourceHash; SLOTS],
timeout_ats: [Option<InstantMillis>; SLOTS],
states: [State; SLOTS],
transfers: [[u8; TRANSFER_BYTES]; SLOTS],
part_names: [[[u8; MAP_HASH_LEN]; MAX_PARTS]; SLOTS],
part_flags: [[bool; MAX_PARTS]; SLOTS],
streamed_opens: [State::StreamedOpenSlot; SLOTS],
}
impl<
State: ResourceRowState + Default,
const SLOTS: usize,
const TRANSFER_BYTES: usize,
const MAX_PARTS: usize,
> Default for FixedResourceTable<State, SLOTS, TRANSFER_BYTES, MAX_PARTS>
{
fn default() -> Self {
const {
assert!(
MAX_PARTS >= max_part_count(TRANSFER_BYTES),
"MAX_PARTS must cover TRANSFER_BYTES at the broadcast-MTU sdu",
);
}
Self {
len: 0,
link_ids: [LinkId::new([0u8; 16]); SLOTS],
hashes: [ResourceHash::new([0u8; 32]); SLOTS],
timeout_ats: [None; SLOTS],
states: core::array::from_fn(|_| State::default()),
transfers: [[0u8; TRANSFER_BYTES]; SLOTS],
part_names: [[[0u8; MAP_HASH_LEN]; MAX_PARTS]; SLOTS],
part_flags: [[false; MAX_PARTS]; SLOTS],
streamed_opens: core::array::from_fn(|_| Default::default()),
}
}
}
impl<
State: ResourceRowState + Default,
const SLOTS: usize,
const TRANSFER_BYTES: usize,
const MAX_PARTS: usize,
> ResourceTable<State> for FixedResourceTable<State, SLOTS, TRANSFER_BYTES, MAX_PARTS>
{
fn capacity(&self) -> usize {
SLOTS
}
fn transfer_capacity(&self) -> usize {
TRANSFER_BYTES
}
fn part_capacity(&self) -> usize {
MAX_PARTS
}
fn len(&self) -> usize {
self.len
}
fn link_ids(&self) -> &[LinkId] {
&self.link_ids[..self.len]
}
fn hashes(&self) -> &[ResourceHash] {
&self.hashes[..self.len]
}
fn timeout_ats(&self) -> &[Option<InstantMillis>] {
&self.timeout_ats[..self.len]
}
fn states(&self) -> &[State] {
&self.states[..self.len]
}
fn set_hash(&mut self, index: usize, hash: ResourceHash) {
self.hashes[index] = hash;
}
fn set_timeout_at(&mut self, index: usize, timeout_at: Option<InstantMillis>) {
self.timeout_ats[index] = timeout_at;
}
fn state_mut(&mut self, index: usize) -> &mut State {
&mut self.states[index]
}
fn transfer(&self, index: usize) -> &[u8] {
&self.transfers[index]
}
fn part_names(&self, index: usize) -> &[[u8; MAP_HASH_LEN]] {
&self.part_names[index]
}
fn part_flags(&self, index: usize) -> &[bool] {
&self.part_flags[index]
}
fn streamed_open(&self, index: usize) -> &State::StreamedOpenSlot {
&self.streamed_opens[index]
}
fn buffers_mut(&mut self, index: usize) -> ResourceBuffers<'_> {
ResourceBuffers {
transfer: &mut self.transfers[index],
part_names: &mut self.part_names[index],
part_flags: &mut self.part_flags[index],
}
}
fn transfer_and_streamed_open_mut(
&mut self,
index: usize,
) -> (&mut [u8], &mut State::StreamedOpenSlot) {
(&mut self.transfers[index], &mut self.streamed_opens[index])
}
fn push(
&mut self,
link_id: LinkId,
hash: ResourceHash,
state: State,
) -> Result<usize, ResourceTablePushError> {
if self.len >= SLOTS {
return Err(ResourceTablePushError::TableFull);
}
let index = self.len;
self.link_ids[index] = link_id;
self.hashes[index] = hash;
self.timeout_ats[index] = None;
self.states[index] = state;
self.part_flags[index] = [false; MAX_PARTS];
self.len += 1;
Ok(index)
}
fn swap_remove(&mut self, index: usize) {
let last = self.len - 1;
self.link_ids.swap(index, last);
self.hashes.swap(index, last);
self.timeout_ats.swap(index, last);
self.states.swap(index, last);
self.transfers.swap(index, last);
self.part_names.swap(index, last);
self.part_flags.swap(index, last);
self.streamed_opens.swap(index, last);
self.states[last] = State::default();
self.streamed_opens[last] = Default::default();
self.len = last;
}
}