use bytes::Bytes;
use std::collections::VecDeque;
use std::fmt;
pub(crate) struct DynamicTable {
table: VecDeque<(Bytes, Bytes)>,
size: usize,
max_size: usize,
}
impl DynamicTable {
pub fn new() -> DynamicTable {
DynamicTable::with_size(4096)
}
fn with_size(max_size: usize) -> DynamicTable {
DynamicTable {
table: VecDeque::new(),
size: 0,
max_size: max_size,
}
}
pub fn get_size(&self) -> usize {
self.size
}
pub fn iter(&self) -> impl Iterator<Item = (&[u8], &[u8])> {
self.table.iter().map(|(k, v)| (&k[..], &v[..]))
}
pub fn set_max_table_size(&mut self, new_max_size: usize) {
self.max_size = new_max_size;
self.consolidate_table();
}
#[cfg(test)]
pub fn get_max_table_size(&self) -> usize {
self.max_size
}
pub fn add_header(&mut self, name: Bytes, value: Bytes) {
self.size += name.len() + value.len() + 32;
debug!("New dynamic table size {}", self.size);
self.table.push_front((name, value));
self.consolidate_table();
debug!("After consolidation dynamic table size {}", self.size);
}
#[cfg(test)]
fn add_header_for_test(&mut self, k: impl Into<Bytes>, v: impl Into<Bytes>) {
self.add_header(k.into(), v.into());
}
fn consolidate_table(&mut self) {
while self.size > self.max_size {
{
let last_header = match self.table.back() {
Some(x) => x,
None => {
panic!("Size of table != 0, but no headers left!");
}
};
self.size -= last_header.0.len() + last_header.1.len() + 32;
}
self.table.pop_back();
}
}
#[cfg(test)]
fn to_vec_of_bytes(&self) -> Vec<(Bytes, Bytes)> {
let mut ret = Vec::new();
for elem in &self.table {
ret.push(elem.clone());
}
ret
}
#[cfg(test)]
pub fn to_vec_of_vec(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
self.to_vec_of_bytes()
.into_iter()
.map(|(k, v)| (k.to_vec(), v.to_vec()))
.collect()
}
#[cfg(test)]
pub fn len(&self) -> usize {
self.table.len()
}
pub fn get(&self, index: usize) -> Option<&(Bytes, Bytes)> {
self.table.get(index)
}
}
impl fmt::Debug for DynamicTable {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "{:?}", self.table)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_dynamic_table_size_calculation_simple() {
let mut table = DynamicTable::new();
assert_eq!(0, table.get_size());
table.add_header_for_test(b"a".to_vec(), b"b".to_vec());
assert_eq!(32 + 2, table.get_size());
}
#[test]
fn test_dynamic_table_size_calculation() {
let mut table = DynamicTable::new();
table.add_header_for_test(b"a".to_vec(), b"b".to_vec());
table.add_header_for_test(b"123".to_vec(), b"456".to_vec());
table.add_header_for_test(b"a".to_vec(), b"b".to_vec());
assert_eq!(3 * 32 + 2 + 6 + 2, table.get_size());
}
#[test]
fn test_dynamic_table_auto_resize() {
let mut table = DynamicTable::with_size(38);
table.add_header_for_test(b"a".to_vec(), b"b".to_vec());
assert_eq!(32 + 2, table.get_size());
table.add_header_for_test(b"123".to_vec(), b"456".to_vec());
assert_eq!(32 + 6, table.get_size());
assert_eq!(
table.to_vec_of_vec(),
vec![(b"123".to_vec(), b"456".to_vec())]
);
}
#[test]
fn test_dynamic_table_auto_resize_into_empty() {
let mut table = DynamicTable::with_size(38);
table.add_header_for_test(b"a".to_vec(), b"b".to_vec());
assert_eq!(32 + 2, table.get_size());
table.add_header_for_test(b"123".to_vec(), b"4567".to_vec());
assert_eq!(0, table.get_size());
assert_eq!(0, table.to_vec_of_bytes().len());
}
#[test]
fn test_dynamic_table_change_max_size() {
let mut table = DynamicTable::new();
table.add_header_for_test(b"a".to_vec(), b"b".to_vec());
table.add_header_for_test(b"123".to_vec(), b"456".to_vec());
table.add_header_for_test(b"c".to_vec(), b"d".to_vec());
assert_eq!(3 * 32 + 2 + 6 + 2, table.get_size());
table.set_max_table_size(38);
assert_eq!(32 + 2, table.get_size());
assert_eq!(table.to_vec_of_vec(), vec![(b"c".to_vec(), b"d".to_vec())]);
}
#[test]
fn test_dynamic_table_clear() {
let mut table = DynamicTable::new();
table.add_header_for_test(b"a".to_vec(), b"b".to_vec());
table.add_header_for_test(b"123".to_vec(), b"456".to_vec());
table.add_header_for_test(b"c".to_vec(), b"d".to_vec());
assert_eq!(3 * 32 + 2 + 6 + 2, table.get_size());
table.set_max_table_size(0);
assert_eq!(0, table.len());
assert_eq!(0, table.to_vec_of_bytes().len());
assert_eq!(0, table.get_size());
assert_eq!(0, table.get_max_table_size());
}
#[test]
fn test_dynamic_table_max_size_zero() {
let mut table = DynamicTable::with_size(0);
table.add_header_for_test(b"a".to_vec(), b"b".to_vec());
assert_eq!(0, table.len());
assert_eq!(0, table.to_vec_of_bytes().len());
assert_eq!(0, table.get_size());
assert_eq!(0, table.get_max_table_size());
}
#[test]
fn test_dynamic_table_iter_with_elems() {
let mut table = DynamicTable::new();
table.add_header_for_test(b"a".to_vec(), b"b".to_vec());
table.add_header_for_test(b"123".to_vec(), b"456".to_vec());
table.add_header_for_test(b"c".to_vec(), b"d".to_vec());
let iter_res: Vec<(&[u8], &[u8])> = table.iter().collect();
let expected: Vec<(&[u8], &[u8])> = vec![(b"c", b"d"), (b"123", b"456"), (b"a", b"b")];
assert_eq!(iter_res, expected);
}
#[test]
fn test_dynamic_table_iter_no_elems() {
let table = DynamicTable::new();
let iter_res: Vec<(&[u8], &[u8])> = table.iter().collect();
let expected = vec![];
assert_eq!(iter_res, expected);
}
}