sark-h2 0.12.0

HTTP/2 protocol primitives + client/server bootstrap for sark stack
Documentation
const METHOD: u8 = 1 << 0;
const SCHEME: u8 = 1 << 1;
const PATH: u8 = 1 << 2;
const STATUS: u8 = 1 << 3;
const REQUEST_REQUIRED: u8 = METHOD | SCHEME | PATH;

pub(super) trait HeaderKind {
    const REQUEST: bool;
}

pub(super) struct RequestHeaders;

impl HeaderKind for RequestHeaders {
    const REQUEST: bool = true;
}

pub(super) struct ResponseHeaders;

impl HeaderKind for ResponseHeaders {
    const REQUEST: bool = false;
}

pub(super) struct Validate {
    seen: u8,
    empty: u8,
    request: bool,
    saw_regular: bool,
    trailing: bool,
    invalid: bool,
}

impl Validate {
    pub(super) const fn new<K: HeaderKind>(trailing: bool) -> Self {
        Self {
            seen: 0,
            empty: 0,
            request: K::REQUEST,
            saw_regular: false,
            trailing,
            invalid: false,
        }
    }

    pub(super) fn field(&mut self, name: &[u8], value: &[u8]) -> bool {
        if self.invalid {
            return false;
        }
        if name.is_empty() {
            return self.reject();
        }
        if name[0] == b':' {
            if self.saw_regular || self.trailing {
                return self.reject();
            }
            return if self.request {
                match name {
                    b":method" => self.mark(METHOD, value.is_empty()),
                    b":scheme" => self.mark(SCHEME, value.is_empty()),
                    b":path" => self.mark(PATH, value.is_empty()),
                    b":authority" | b":protocol" => true,
                    _ => self.reject(),
                }
            } else {
                match name {
                    b":status" => self.mark(STATUS, false),
                    _ => self.reject(),
                }
            };
        }
        if name.iter().any(u8::is_ascii_uppercase) {
            return self.reject();
        }
        self.saw_regular = true;
        match name {
            b"connection" | b"keep-alive" | b"proxy-connection" | b"transfer-encoding"
            | b"upgrade" => self.reject(),
            b"te" if value != b"trailers" => self.reject(),
            _ => true,
        }
    }

    pub(super) fn finish(self) -> bool {
        if self.invalid {
            return false;
        }
        if self.trailing {
            return true;
        }
        if self.request {
            self.seen & REQUEST_REQUIRED == REQUEST_REQUIRED && self.empty & REQUEST_REQUIRED == 0
        } else {
            self.seen & STATUS != 0
        }
    }

    fn mark(&mut self, bit: u8, empty: bool) -> bool {
        if self.seen & bit != 0 {
            return self.reject();
        }
        self.seen |= bit;
        if empty {
            self.empty |= bit;
        }
        true
    }

    fn reject(&mut self) -> bool {
        self.invalid = true;
        false
    }
}