Skip to main content

sark_core/http/response/direct/
value.rs

1use o3::buffer::{Owned, Shared};
2
3use super::super::{HotTextInner, TextItemInner};
4use super::headers::HeaderNameToken;
5use crate::http::request::LocalFrameBytesRef;
6
7#[derive(Clone)]
8pub enum HeaderValueInner<'req> {
9    Static(&'static [u8]),
10    Inline(InlineHeaderValue),
11    Shared(Shared),
12    Local(LocalFrameBytesRef<'req>),
13}
14
15#[derive(Clone, Copy)]
16pub struct InlineHeaderValue {
17    bytes: [u8; 31],
18    len: u8,
19}
20
21impl InlineHeaderValue {
22    pub fn new(value: &[u8]) -> Self {
23        assert!(
24            value.len() <= 31,
25            "inline header value overflow: max 31, got {}",
26            value.len()
27        );
28        let mut bytes = [0u8; 31];
29        bytes[..value.len()].copy_from_slice(value);
30        Self {
31            bytes,
32            len: value.len() as u8,
33        }
34    }
35
36    pub fn from_decimal(value: usize) -> Self {
37        let mut raw = [0u8; 20];
38        let n = crate::http::codec::Wire::write_dec(value, &mut raw);
39        Self::new(&raw[..n])
40    }
41
42    pub fn as_bytes(&self) -> &[u8] {
43        &self.bytes[..usize::from(self.len)]
44    }
45}
46
47impl std::fmt::Debug for InlineHeaderValue {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        f.debug_struct("InlineHeaderValue")
50            .field("len", &self.len)
51            .finish()
52    }
53}
54
55impl<'req> std::fmt::Debug for HeaderValueInner<'req> {
56    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57        match self {
58            Self::Static(value) => f
59                .debug_struct("HeaderValue::Static")
60                .field("len", &value.len())
61                .finish(),
62            Self::Inline(value) => f
63                .debug_struct("HeaderValue::Inline")
64                .field("len", &value.as_bytes().len())
65                .finish(),
66            Self::Shared(value) => f
67                .debug_struct("HeaderValue::Shared")
68                .field("len", &value.len())
69                .finish(),
70            Self::Local(value) => f
71                .debug_struct("HeaderValue::Local")
72                .field("len", &value.len())
73                .finish(),
74        }
75    }
76}
77
78impl<'req> HeaderValueInner<'req> {
79    pub fn as_bytes(&self) -> &[u8] {
80        match self {
81            Self::Static(value) => value,
82            Self::Inline(value) => value.as_bytes(),
83            Self::Shared(value) => value.as_ref(),
84            Self::Local(value) => value.as_bytes(),
85        }
86    }
87
88    pub fn len(&self) -> usize {
89        self.as_bytes().len()
90    }
91
92    pub fn is_empty(&self) -> bool {
93        self.as_bytes().is_empty()
94    }
95}
96
97#[derive(Clone, Debug)]
98pub struct HeaderItemInner<'req> {
99    pub(super) name: HeaderNameToken,
100    pub(super) value: HeaderValueInner<'req>,
101}
102
103pub type HeaderItem = HeaderItemInner<'static>;
104
105impl<'req> HeaderItemInner<'req> {
106    pub fn from_value<V>(name: HeaderNameToken, value: V) -> Self
107    where
108        V: IntoHeaderValue<'req>,
109    {
110        Self {
111            name,
112            value: value.into_header_value(),
113        }
114    }
115
116    pub(crate) fn placeholder() -> Self {
117        Self {
118            name: HeaderNameToken::empty_placeholder(),
119            value: HeaderValueInner::Static(&[]),
120        }
121    }
122
123    pub fn wire_len(&self) -> usize {
124        self.name.as_bytes().len() + 2 + self.value.len() + 2
125    }
126
127    pub fn name_bytes(&self) -> &'static [u8] {
128        self.name.as_bytes()
129    }
130
131    pub fn value_bytes(&self) -> &[u8] {
132        self.value.as_bytes()
133    }
134}
135
136pub trait IntoHeaderValue<'req> {
137    fn into_header_value(self) -> HeaderValueInner<'req>;
138}
139
140impl<'req> IntoHeaderValue<'req> for HeaderValueInner<'req> {
141    fn into_header_value(self) -> Self {
142        self
143    }
144}
145
146impl<'req> IntoHeaderValue<'req> for InlineHeaderValue {
147    fn into_header_value(self) -> HeaderValueInner<'req> {
148        HeaderValueInner::Inline(self)
149    }
150}
151
152impl<'req> IntoHeaderValue<'req> for LocalFrameBytesRef<'req> {
153    fn into_header_value(self) -> HeaderValueInner<'req> {
154        HeaderValueInner::Local(self)
155    }
156}
157
158impl<'req> IntoHeaderValue<'req> for Shared {
159    fn into_header_value(self) -> HeaderValueInner<'req> {
160        HeaderValueInner::Shared(self)
161    }
162}
163
164impl<'req> IntoHeaderValue<'req> for Owned {
165    fn into_header_value(self) -> HeaderValueInner<'req> {
166        HeaderValueInner::Shared(self.freeze())
167    }
168}
169
170impl<'req> IntoHeaderValue<'req> for String {
171    fn into_header_value(self) -> HeaderValueInner<'req> {
172        HeaderValueInner::Shared(Shared::from(self.into_bytes()))
173    }
174}
175
176impl<'req> IntoHeaderValue<'req> for &'static str {
177    fn into_header_value(self) -> HeaderValueInner<'req> {
178        HeaderValueInner::Static(self.as_bytes())
179    }
180}
181
182pub trait TextSpec<'req> {
183    fn into_hot_text(self) -> HotTextInner<'req>;
184}
185
186impl<'req, const N: usize> TextSpec<'req> for [TextItemInner<'req>; N] {
187    fn into_hot_text(self) -> HotTextInner<'req> {
188        HotTextInner::from_items(self)
189    }
190}
191
192impl<'req> TextSpec<'req> for HotTextInner<'req> {
193    fn into_hot_text(self) -> Self {
194        self
195    }
196}