extern crate alloc;
use alloc::collections::VecDeque;
use alloc::vec::Vec;
pub(crate) const ENTRY_OVERHEAD: usize = 32;
#[derive(Debug, Default)]
pub(crate) struct DynamicTable {
entries: VecDeque<(Vec<u8>, Vec<u8>)>,
size: usize,
capacity: usize,
insert_count: usize,
dropped: usize,
}
impl DynamicTable {
pub(crate) fn new() -> Self {
DynamicTable::default()
}
pub(crate) fn entry_size(name: &[u8], value: &[u8]) -> usize {
name.len() + value.len() + ENTRY_OVERHEAD
}
pub(crate) fn insert_count(&self) -> usize {
self.insert_count
}
#[cfg(test)]
pub(crate) fn size(&self) -> usize {
self.size
}
#[cfg(test)]
pub(crate) fn capacity(&self) -> usize {
self.capacity
}
#[cfg(test)]
pub(crate) fn len(&self) -> usize {
self.entries.len()
}
pub(crate) fn set_capacity(&mut self, new_capacity: usize, max: usize) -> bool {
if new_capacity > max {
return false;
}
self.capacity = new_capacity;
self.evict_to_fit(0);
true
}
fn evict_to_fit(&mut self, incoming: usize) {
while self.size + incoming > self.capacity {
match self.entries.pop_front() {
Some((n, v)) => {
self.size -= Self::entry_size(&n, &v);
self.dropped += 1;
}
None => break,
}
}
}
pub(crate) fn can_insert(&self, name: &[u8], value: &[u8]) -> bool {
Self::entry_size(name, value) <= self.capacity
}
pub(crate) fn insert(&mut self, name: &[u8], value: &[u8]) -> Option<usize> {
let need = Self::entry_size(name, value);
if need > self.capacity {
return None;
}
self.evict_to_fit(need);
let abs = self.insert_count;
self.entries.push_back((name.to_vec(), value.to_vec()));
self.size += need;
self.insert_count += 1;
Some(abs)
}
pub(crate) fn get_absolute(&self, abs: usize) -> Option<(&[u8], &[u8])> {
if abs < self.dropped || abs >= self.insert_count {
return None;
}
self.entries
.get(abs - self.dropped)
.map(|(n, v)| (n.as_slice(), v.as_slice()))
}
pub(crate) fn relative_to_absolute_encoder(&self, rel: usize) -> Option<usize> {
let top = self.insert_count.checked_sub(1)?;
top.checked_sub(rel)
}
pub(crate) fn field_relative_to_absolute(base: usize, rel: usize) -> Option<usize> {
base.checked_sub(rel)?.checked_sub(1)
}
pub(crate) fn post_base_to_absolute(base: usize, idx: usize) -> Option<usize> {
base.checked_add(idx)
}
}