sark-core 0.10.0

the L7 layer for dope
Documentation
use o3::buffer::{Borrowed, Bytes, Owned, Retained, Shared};

use super::headers::HeaderNameToken;

#[derive(Clone)]
pub enum HeaderValueInner<'req> {
    Static(&'static [u8]),
    Inline(InlineHeaderValue),
    Shared(Shared),
    Borrowed(Bytes<Borrowed<'req>>),
    Retained(Bytes<Retained>),
}

#[derive(Clone, Copy)]
pub struct InlineHeaderValue {
    bytes: [u8; 31],
    len: u8,
}

impl InlineHeaderValue {
    pub fn new(value: &[u8]) -> Self {
        assert!(
            value.len() <= 31,
            "inline header value overflow: max 31, got {}",
            value.len()
        );
        let mut bytes = [0u8; 31];
        bytes[..value.len()].copy_from_slice(value);
        Self {
            bytes,
            len: value.len() as u8,
        }
    }

    pub fn as_bytes(&self) -> &[u8] {
        &self.bytes[..usize::from(self.len)]
    }
}

impl std::fmt::Debug for InlineHeaderValue {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("InlineHeaderValue")
            .field("len", &self.len)
            .finish()
    }
}

impl<'req> std::fmt::Debug for HeaderValueInner<'req> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Static(value) => f
                .debug_struct("HeaderValue::Static")
                .field("len", &value.len())
                .finish(),
            Self::Inline(value) => f
                .debug_struct("HeaderValue::Inline")
                .field("len", &value.as_bytes().len())
                .finish(),
            Self::Shared(value) => f
                .debug_struct("HeaderValue::Shared")
                .field("len", &value.len())
                .finish(),
            Self::Borrowed(value) => f
                .debug_struct("HeaderValue::Borrowed")
                .field("len", &value.len())
                .finish(),
            Self::Retained(value) => f
                .debug_struct("HeaderValue::Retained")
                .field("len", &value.len())
                .finish(),
        }
    }
}

impl<'req> HeaderValueInner<'req> {
    pub fn as_bytes(&self) -> &[u8] {
        match self {
            Self::Static(value) => value,
            Self::Inline(value) => value.as_bytes(),
            Self::Shared(value) => value.as_ref(),
            Self::Borrowed(value) => value.as_slice(),
            Self::Retained(value) => value.as_slice(),
        }
    }

    pub fn len(&self) -> usize {
        self.as_bytes().len()
    }

    pub fn is_empty(&self) -> bool {
        self.as_bytes().is_empty()
    }
}

#[derive(Clone, Debug)]
pub struct HeaderItem<'req> {
    pub(super) name: HeaderNameToken,
    pub(super) value: HeaderValueInner<'req>,
}

impl<'req> HeaderItem<'req> {
    pub fn from_value<V>(name: HeaderNameToken, value: V) -> Self
    where
        V: Into<HeaderValueInner<'req>>,
    {
        Self {
            name,
            value: value.into(),
        }
    }

    pub(crate) fn placeholder() -> Self {
        Self {
            name: HeaderNameToken::empty_placeholder(),
            value: HeaderValueInner::Static(&[]),
        }
    }

    pub fn wire_len(&self) -> usize {
        self.name.as_bytes().len() + 2 + self.value.len() + 2
    }

    pub fn name_bytes(&self) -> &'static [u8] {
        self.name.as_bytes()
    }

    pub fn value_bytes(&self) -> &[u8] {
        self.value.as_bytes()
    }
}

impl<'req> From<InlineHeaderValue> for HeaderValueInner<'req> {
    fn from(value: InlineHeaderValue) -> Self {
        Self::Inline(value)
    }
}

impl<'req> From<Bytes<Borrowed<'req>>> for HeaderValueInner<'req> {
    fn from(value: Bytes<Borrowed<'req>>) -> Self {
        Self::Borrowed(value)
    }
}

impl<'req> From<Bytes<Retained>> for HeaderValueInner<'req> {
    fn from(value: Bytes<Retained>) -> Self {
        Self::Retained(value)
    }
}

impl<'req> From<Shared> for HeaderValueInner<'req> {
    fn from(value: Shared) -> Self {
        Self::Shared(value)
    }
}

impl<'req> From<Owned> for HeaderValueInner<'req> {
    fn from(value: Owned) -> Self {
        Self::Shared(value.freeze())
    }
}

impl<'req> From<String> for HeaderValueInner<'req> {
    fn from(value: String) -> Self {
        Self::Shared(Shared::from(value.into_bytes()))
    }
}

impl<'req> From<&'static str> for HeaderValueInner<'req> {
    fn from(value: &'static str) -> Self {
        Self::Static(value.as_bytes())
    }
}