reqrio 0.3.0-alpha4

A lightweight, high-performance, fingerprint-based HTTP request library.
Documentation
use std::ops;
use super::item::HPackItem;
use crate::hpack::index::Index;
use dynamic::DynamicTable;
use r#static::STATIC_TABLE;
use std::slice::Iter;

mod r#static;
mod dynamic;

pub struct Table {
    static_table: &'static [HPackItem],
    pub(crate) dynamic_table: DynamicTable,
}

impl Default for Table {
    fn default() -> Self {
        Table {
            static_table: STATIC_TABLE.as_ref(),
            dynamic_table: DynamicTable::default(),
        }
    }
}

impl Table {
    pub fn new(max_table_size: usize) -> Self {
        Table {
            static_table: STATIC_TABLE.as_ref(),
            dynamic_table: DynamicTable::new_size(max_table_size),
        }
    }

    pub fn get(&self, index: usize) -> Option<&HPackItem> {
        match index {
            ..61 => self.static_table.get(index),
            _ => self.dynamic_table.get(index),
        }
    }

    pub fn insert(&mut self, item: HPackItem) {
        self.dynamic_table.insert(item);
    }

    pub fn iter(&self) -> TableIterator<'_> {
        TableIterator {
            static_inner: self.static_table.iter(),
            dynamic_inner: self.dynamic_table.iter(),
        }
    }

    pub fn get_by_name_value(&self, name: &str, value: &str) -> Option<Index> {
        self.iter().enumerate().find_map(|(index, item)| if item.name() == name && item.value() == value {
            Some(Index::Indexed(index + 1))
        } else { None })
    }

    pub fn get_by_name(&self, name: &str) -> Option<Index> {
        self.iter().enumerate().find_map(|(index, item)| if item.name() == name {
            Some(Index::NameIndexedAdd(index + 1))
        } else { None })
    }

    pub fn update_table_size(&mut self, max_size: usize) {
        self.dynamic_table.update_table_size(max_size);
    }
}

pub struct TableIterator<'a> {
    static_inner: Iter<'a, HPackItem>,
    dynamic_inner: Iter<'a, HPackItem>,
}

impl<'a> Iterator for TableIterator<'a> {
    type Item = &'a HPackItem;
    fn next(&mut self) -> Option<Self::Item> {
        match self.static_inner.next() {
            None => self.dynamic_inner.next(),
            Some(item) => Some(item),
        }
    }
}

impl ops::Index<usize> for Table {
    type Output = HPackItem;
    fn index(&self, index: usize) -> &Self::Output {
        match index {
            ..61 => &self.static_table[index],
            _ => &self.dynamic_table[index - 61],
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::hpack::table::Table;

    #[test]
    fn test_hpack_table() {
        let mut table = Table::default();
        let item = table.get(44).unwrap();
        assert_eq!(item.name(), "link");
        let mut item = table.get(57).unwrap().clone();
        assert_eq!(item.name(), "user-agent");
        item.set_value("test value");
        table.insert(item);
        let mut item = table.get(53).unwrap().clone();
        assert_eq!(item.name(), "server");
        item.set_value("test server");
        table.insert(item);
        let item = table.get(62).unwrap();
        assert_eq!(item.value(), "test value");
        let item = table.get(61).unwrap();
        assert_eq!(item.value(), "test server");
        assert_eq!(table.dynamic_table.size(), 101)
    }
}