sark-http 0.29.1

HTTP wire types, semantics, codecs, and ownership invariants for Sark
pub(in crate::payload::compress::dynamic::table) mod input;
mod raw;
pub(in crate::payload::compress::dynamic::table) mod remove;
use mode::records;
use table::{Table, ring::Cursor, slot::Slot, state};

use crate::payload::compress::dynamic::{
    ENTRY_OVERHEAD,
    insert::{self, Name},
    mode, table,
};

#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Error {
    Length { name: usize, value: usize },
    Name { actual: usize, limit: usize },
    Capacity { required: usize, limit: usize },
}

#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Change {
    Inserted,
    Cleared(Error),
}

pub struct Edit<'a, M: mode::Kind> {
    table: &'a mut Table<M>,
}

impl<'a, M: mode::Kind> Edit<'a, M> {
    pub(in crate::payload::compress::dynamic) const fn new(table: &'a mut Table<M>) -> Self {
        Self { table }
    }
    fn limit(&mut self, limit: usize) {
        let state = self.table.storage.state_mut();
        let capacity = state.layout.capacity();
        state.entries.set_limit(limit, capacity);
    }
}

impl Edit<'_, mode::Direct> {
    pub fn set_limit(&mut self, limit: usize) {
        self.limit(limit);
        self.trim();
    }

    pub fn insert(&mut self, name: &[u8], value: &[u8]) -> Change {
        match table::Input::try_new(self.table, name, value) {
            Ok(input) => {
                input.insert();
                Change::Inserted
            }
            Err(error) => Change::Cleared(error),
        }
    }

    fn trim(&mut self) {
        while let Some(oldest) = state::raw::Pop::oldest(self.table.storage.parts_mut()) {
            table::Remove::new(oldest).remove();
        }
    }
}

impl Edit<'_, mode::Staged> {
    pub fn set_limit(&mut self, limit: usize) {
        self.limit(limit);
        self.invalidate();
        self.trim();
    }

    pub fn reject(&mut self) {
        self.invalidate();
        self.table.storage.state_mut().clear();
    }

    pub fn duplicate(&mut self, index: usize) -> Result<(), insert::Error> {
        let limit = self.table.max_size();
        if limit < ENTRY_OVERHEAD {
            return Err(insert::Error::Capacity {
                required: ENTRY_OVERHEAD,
                limit,
            });
        }
        let len = self.table.entry_count();
        let view = self.table.view();
        let entry = match view.try_entry(index) {
            Some(entry) => entry,
            None => return Err(insert::Error::Index { index, len }),
        };
        let slot = entry.record().slot();
        let size = entry.size();
        let state = self.table.storage.state_mut();
        state.insert.begin(state.entries.tail());
        Name::new(self.table).duplicate(slot, size);
        Ok(())
    }

    pub(in crate::payload::compress::dynamic) fn publish(
        &mut self,
        slot: Slot,
        size: state::Size,
        tail: Cursor,
    ) {
        self.invalidate();
        let ready = self.evict(size);
        ready.finish(records::Staged::new(slot), tail).commit();
    }

    fn evict(&mut self, incoming: state::Size) -> state::raw::Ready<'_, mode::Staged> {
        let mut parts = self.table.storage.parts_mut();
        loop {
            match state::raw::Ready::admit(parts, incoming) {
                state::Admission::Evict(oldest) => {
                    parts = oldest.commit();
                }
                state::Admission::Ready(ready) => return ready,
            }
        }
    }

    fn trim(&mut self) {
        let mut parts = self.table.storage.parts_mut();
        while let Some(oldest) = state::raw::Pop::oldest(parts) {
            parts = oldest.commit();
        }
    }

    fn invalidate(&mut self) {
        let state = self.table.storage.state_mut();
        state.insert.invalidate(state.entries.tail());
    }
}

const _: () = {
    assert!(core::mem::size_of::<Error>() <= 3 * core::mem::size_of::<usize>());
    assert!(core::mem::size_of::<Change>() <= 3 * core::mem::size_of::<usize>());
    assert!(core::mem::size_of::<Edit<'static, mode::Direct>>() == core::mem::size_of::<usize>());
    assert!(core::mem::size_of::<Edit<'static, mode::Staged>>() == core::mem::size_of::<usize>());
};