sark_core/http/response/direct/
value.rs1use 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}