sark-core 0.13.0

the L7 layer for dope
Documentation
use std::slice;

use o3::buffer::{ByteSink, Owned, Shared};

use super::headers::{DEFAULT_HEADER_CAPACITY, Headers};
use crate::http::Field;
use crate::http::response::wire_emit::{HeaderSection, ProvenWireWriter};

#[derive(Clone, Debug)]
pub struct HeadInner<'req, const N: usize = DEFAULT_HEADER_CAPACITY, S = StaticHeaderBytes> {
    static_headers: S,
    headers: Headers<'req, N>,
}

#[derive(Clone, Copy, Debug)]
pub struct StaticHeaderBytes(&'static [u8]);

impl StaticHeaderBytes {
    pub const fn new(wire: &'static [u8]) -> Self {
        Self(wire)
    }
}

#[derive(Debug)]
pub struct HeaderTemplate {
    wire: &'static [u8],
    fields: &'static [Field<'static>],
}

impl HeaderTemplate {
    pub const fn new(wire: &'static [u8], fields: &'static [Field<'static>]) -> Self {
        Self { wire, fields }
    }
}

#[derive(Clone, Copy, Debug)]
pub struct StaticHeaderFields(&'static HeaderTemplate);

impl StaticHeaderFields {
    pub const fn new(template: &'static HeaderTemplate) -> Self {
        Self(template)
    }
}

#[doc(hidden)]
pub trait StaticHeaders {
    type Fields<'a>: Iterator<Item = Field<'a>>
    where
        Self: 'a;

    fn wire(&self) -> &'static [u8];

    fn fields(&self) -> Self::Fields<'_>;
}

pub struct WireHeaderFields<'a> {
    remaining: &'a [u8],
}

impl<'a> WireHeaderFields<'a> {
    pub fn new(wire: &'a [u8]) -> Self {
        Self { remaining: wire }
    }
}

impl<'a> Iterator for WireHeaderFields<'a> {
    type Item = Field<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            let (line, remaining) = match self.remaining.iter().position(|&b| b == b'\n') {
                Some(end) => (&self.remaining[..end], &self.remaining[end + 1..]),
                None => (self.remaining, &[][..]),
            };
            self.remaining = remaining;
            let line = line.strip_suffix(b"\r").unwrap_or(line);
            if line.is_empty() {
                if self.remaining.is_empty() {
                    return None;
                }
                continue;
            }
            let Some(colon) = line.iter().position(|&b| b == b':') else {
                if self.remaining.is_empty() {
                    return None;
                }
                continue;
            };
            let name = &line[..colon];
            let mut value = &line[colon + 1..];
            while let Some((&b' ', rest)) = value.split_first() {
                value = rest;
            }
            return Some(Field::new(name, value));
        }
    }
}

pub struct TemplateHeaderFields<'a> {
    fields: slice::Iter<'a, Field<'static>>,
}

impl<'a> Iterator for TemplateHeaderFields<'a> {
    type Item = Field<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        self.fields
            .next()
            .map(|field| Field::new(field.name, field.value))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.fields.size_hint()
    }
}

impl ExactSizeIterator for TemplateHeaderFields<'_> {}

impl StaticHeaders for StaticHeaderBytes {
    type Fields<'a> = WireHeaderFields<'a>;

    fn wire(&self) -> &'static [u8] {
        self.0
    }

    fn fields(&self) -> Self::Fields<'_> {
        WireHeaderFields::new(self.0)
    }
}

impl StaticHeaders for StaticHeaderFields {
    type Fields<'a> = TemplateHeaderFields<'a>;

    fn wire(&self) -> &'static [u8] {
        self.0.wire
    }

    fn fields(&self) -> Self::Fields<'_> {
        TemplateHeaderFields {
            fields: self.0.fields.iter(),
        }
    }
}

impl<'req, const N: usize> HeadInner<'req, N> {
    pub fn new(static_headers: &'static [u8], headers: Headers<'req, N>) -> Self {
        Self {
            static_headers: StaticHeaderBytes::new(static_headers),
            headers,
        }
    }
}

impl<'req, const N: usize> HeadInner<'req, N, StaticHeaderFields> {
    pub fn structured(static_headers: &'static HeaderTemplate, headers: Headers<'req, N>) -> Self {
        Self {
            static_headers: StaticHeaderFields::new(static_headers),
            headers,
        }
    }
}

impl<'req, const N: usize, S> HeadInner<'req, N, S>
where
    S: StaticHeaders,
{
    pub fn static_headers(&self) -> &'static [u8] {
        self.static_headers.wire()
    }

    pub fn headers(&self) -> &Headers<'req, N> {
        &self.headers
    }

    pub(super) fn headers_mut(&mut self) -> &mut Headers<'req, N> {
        &mut self.headers
    }

    pub fn wire_len(&self) -> usize {
        self.static_headers
            .wire()
            .len()
            .saturating_add(self.headers.wire_len())
    }

    pub(crate) fn wire_headers(&self) -> Shared {
        if self.headers.is_empty() {
            return Shared::from_static(self.static_headers.wire());
        }
        let capacity = self.wire_len();
        match Owned::try_build_exact(capacity, |out| self.write_into(out)) {
            Ok(out) => out.freeze(),
            Err(_) => {
                let mut out = Vec::with_capacity(capacity);
                match self.write_into(&mut out) {
                    Ok(()) => Shared::from(out),
                    Err(error) => match error {},
                }
            }
        }
    }

    fn write_into<W: ByteSink>(&self, out: &mut W) -> Result<(), W::Error> {
        out.write_slice(self.static_headers.wire())?;
        self.headers.write_into(out)
    }

    pub(crate) fn fields(&self) -> impl Iterator<Item = Field<'_>> + '_ {
        self.static_headers.fields().chain(self.headers.fields())
    }

    pub fn write_slice(&self, out: &mut [u8]) -> Option<usize> {
        let total = self.wire_len();
        if out.len() < total {
            return None;
        }
        let static_headers = self.static_headers.wire();
        let n = static_headers.len();
        out[..n].copy_from_slice(static_headers);
        let m = self.headers.write(&mut out[n..]);
        Some(n + m)
    }
}

impl<const N: usize, S> HeaderSection for HeadInner<'_, N, S>
where
    S: StaticHeaders,
{
    fn wire_len(&self) -> usize {
        Self::wire_len(self)
    }
    fn write_headers(&self, out: &mut ProvenWireWriter<'_>) {
        out.put(self.static_headers.wire());
        self.headers.write_wire(out);
    }
}