Skip to main content

sark_core/http/response/direct/
value.rs

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