use core::{mem, net::SocketAddr};
use crate::http::{Extensions, header::HeaderMap};
pub struct Context<'a, D, const HEADER_LIMIT: usize> {
addr: SocketAddr,
state: ContextState,
header: Option<HeaderMap>,
exts: Extensions,
date: &'a D,
}
struct ContextState(u8);
impl ContextState {
const EXPECT: u8 = 0b_0001;
const CONNECT: u8 = 0b_0010;
const HEAD: u8 = 0b_0100;
const CLOSE: u8 = 0b_1000;
const HTTP_10: u8 = 0b1_0000;
const fn new() -> Self {
Self(0)
}
fn insert(&mut self, other: u8) {
self.0 |= other;
}
fn remove(&mut self, other: u8) {
self.0 &= !other;
}
const fn contains(&self, other: u8) -> bool {
(self.0 & other) == other
}
}
impl<'a, D, const HEADER_LIMIT: usize> Context<'a, D, HEADER_LIMIT> {
#[inline]
pub fn new(date: &'a D) -> Self {
Self::with_addr(crate::unspecified_socket_addr(), date)
}
#[inline]
pub fn with_addr(addr: SocketAddr, date: &'a D) -> Self {
Self {
addr,
state: ContextState::new(),
header: None,
exts: Extensions::new(),
date,
}
}
#[inline]
pub fn date(&self) -> &D {
self.date
}
#[inline]
pub fn take_headers(&mut self) -> HeaderMap {
self.header.take().unwrap_or_default()
}
#[inline]
pub fn take_extensions(&mut self) -> Extensions {
mem::take(&mut self.exts)
}
#[inline]
pub fn replace_headers(&mut self, headers: HeaderMap) {
debug_assert!(headers.is_empty());
self.header = Some(headers);
}
#[inline]
pub fn replace_extensions(&mut self, extensions: Extensions) {
debug_assert!(extensions.is_empty());
self.exts = extensions;
}
#[inline]
pub fn reset(&mut self) {
self.state = ContextState::new();
}
#[inline]
pub fn set_expect_header(&mut self) {
self.state.insert(ContextState::EXPECT)
}
#[inline]
pub fn set_connect_method(&mut self) {
self.state.insert(ContextState::CONNECT)
}
#[inline]
pub fn set_head_method(&mut self) {
self.state.insert(ContextState::HEAD)
}
#[inline]
pub fn set_http10(&mut self) {
self.state.insert(ContextState::HTTP_10)
}
#[inline]
pub fn set_close(&mut self) {
self.state.insert(ContextState::CLOSE)
}
#[inline]
pub fn remove_close(&mut self) {
self.state.remove(ContextState::CLOSE)
}
#[inline]
pub const fn is_expect_header(&self) -> bool {
self.state.contains(ContextState::EXPECT)
}
#[inline]
pub const fn is_connect_method(&self) -> bool {
self.state.contains(ContextState::CONNECT)
}
#[inline]
pub const fn is_head_method(&self) -> bool {
self.state.contains(ContextState::HEAD)
}
#[inline]
pub const fn is_http10(&self) -> bool {
self.state.contains(ContextState::HTTP_10)
}
#[inline]
pub const fn is_connection_closed(&self) -> bool {
self.state.contains(ContextState::CLOSE)
}
#[inline]
pub fn socket_addr(&self) -> &SocketAddr {
&self.addr
}
}