1use o3::buffer::{Borrowed, Bytes, Owned, Retained, Shared};
2
3use super::direct::INLINE_HOT_TEXT_PARTS;
4use super::{BodyInner, DEFAULT_HEADER_CAPACITY, HeadInner};
5
6#[derive(Clone)]
7pub enum TextItemInner<'req> {
8 Static(&'static [u8]),
9 Shared(Shared),
10 Borrowed(Bytes<Borrowed<'req>>),
11 Retained(Bytes<Retained>),
12}
13
14pub type TextItem = TextItemInner<'static>;
15
16pub type TextBody = HotTextInner<'static>;
17
18impl<'req> std::fmt::Debug for TextItemInner<'req> {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 match self {
21 Self::Static(bytes) => f
22 .debug_struct("TextItem::Static")
23 .field("len", &bytes.len())
24 .finish(),
25 Self::Shared(bytes) => f
26 .debug_struct("TextItem::Shared")
27 .field("len", &bytes.len())
28 .finish(),
29 Self::Borrowed(bytes) => f
30 .debug_struct("TextItem::Borrowed")
31 .field("len", &bytes.len())
32 .finish(),
33 Self::Retained(bytes) => f
34 .debug_struct("TextItem::Retained")
35 .field("len", &bytes.len())
36 .finish(),
37 }
38 }
39}
40
41impl<'req> TextItemInner<'req> {
42 pub(crate) fn placeholder() -> Self {
43 Self::Static(&[])
44 }
45
46 pub(crate) fn as_bytes(&self) -> &[u8] {
47 match self {
48 Self::Static(bytes) => bytes,
49 Self::Shared(bytes) => bytes.as_ref(),
50 Self::Borrowed(bytes) => bytes.as_slice(),
51 Self::Retained(bytes) => bytes.as_slice(),
52 }
53 }
54
55 pub(crate) fn len(&self) -> usize {
56 self.as_bytes().len()
57 }
58}
59
60#[allow(clippy::large_enum_variant)]
61#[derive(Clone, Debug)]
62pub enum HotHeadInner<'req, const N: usize = DEFAULT_HEADER_CAPACITY> {
63 Wire(Shared),
64 Direct(HeadInner<'req, N>),
65}
66
67impl<'req, const N: usize> HotHeadInner<'req, N> {
68 pub(super) fn into_bytes(self) -> Shared {
69 match self {
70 Self::Wire(bytes) => bytes,
71 Self::Direct(head) => {
72 let mut out = Owned::with_capacity(head.wire_len());
73 head.write_into_owned(&mut out);
74 out.freeze()
75 }
76 }
77 }
78}
79
80pub struct HotTextInner<'req> {
81 items: [TextItemInner<'req>; INLINE_HOT_TEXT_PARTS],
82 len: u8,
83 body_len: usize,
84}
85
86impl<'req> Clone for HotTextInner<'req> {
87 fn clone(&self) -> Self {
88 let len = usize::from(self.len);
89 let items = std::array::from_fn(|idx| {
90 if idx < len {
91 self.items[idx].clone()
92 } else {
93 TextItemInner::placeholder()
94 }
95 });
96 Self {
97 items,
98 len: self.len,
99 body_len: self.body_len,
100 }
101 }
102}
103
104impl<'req> std::fmt::Debug for HotTextInner<'req> {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 f.debug_struct("HotText")
107 .field("len", &self.len)
108 .field("body_len", &self.body_len)
109 .finish()
110 }
111}
112
113impl<'req> Default for HotTextInner<'req> {
114 fn default() -> Self {
115 Self::new()
116 }
117}
118
119impl<'req> HotTextInner<'req> {
120 pub fn new() -> Self {
121 Self {
122 items: std::array::from_fn(|_| TextItemInner::placeholder()),
123 len: 0,
124 body_len: 0,
125 }
126 }
127
128 pub fn from_items<const N: usize>(items: [TextItemInner<'req>; N]) -> Self {
129 assert!(
130 N <= INLINE_HOT_TEXT_PARTS,
131 "hot text part overflow: max {}",
132 INLINE_HOT_TEXT_PARTS
133 );
134 let mut iter = IntoIterator::into_iter(items);
135 let mut body_len = 0usize;
136 let entries = std::array::from_fn(|_| match iter.next() {
137 Some(item) => {
138 body_len += item.len();
139 item
140 }
141 None => TextItemInner::placeholder(),
142 });
143 Self {
144 items: entries,
145 len: N as u8,
146 body_len,
147 }
148 }
149
150 pub fn from_static(bytes: &'static [u8]) -> Self {
151 let mut body = Self::new();
152 body.push_static(bytes);
153 body
154 }
155
156 pub fn len(&self) -> usize {
157 self.body_len
158 }
159
160 pub fn is_empty(&self) -> bool {
161 self.body_len == 0
162 }
163
164 pub fn push_static(&mut self, bytes: &'static [u8]) -> &mut Self {
165 if !bytes.is_empty() {
166 self.push_item(TextItemInner::Static(bytes));
167 }
168 self
169 }
170
171 pub fn push_borrowed(&mut self, bytes: Bytes<Borrowed<'req>>) -> &mut Self {
172 if !bytes.is_empty() {
173 self.push_item(TextItemInner::Borrowed(bytes));
174 }
175 self
176 }
177
178 pub fn push_retained(&mut self, bytes: Bytes<Retained>) -> &mut Self {
179 if !bytes.is_empty() {
180 self.push_item(TextItemInner::Retained(bytes));
181 }
182 self
183 }
184
185 pub(crate) fn write_to(&self, out: &mut [u8]) -> usize {
186 let mut off = 0usize;
187 for item in &self.items[..usize::from(self.len)] {
188 let bytes = item.as_bytes();
189 let end = off + bytes.len();
190 out[off..end].copy_from_slice(bytes);
191 off = end;
192 }
193 off
194 }
195
196 pub fn into_bytes(self) -> Shared {
197 let mut out = Owned::with_capacity(self.body_len);
198 for item in &self.items[..usize::from(self.len)] {
199 out.extend_from_slice(item.as_bytes());
200 }
201 out.freeze()
202 }
203
204 fn push_item(&mut self, item: TextItemInner<'req>) {
205 assert!(
206 usize::from(self.len) < INLINE_HOT_TEXT_PARTS,
207 "hot text part overflow: max {}",
208 INLINE_HOT_TEXT_PARTS
209 );
210 self.body_len += item.len();
211 self.items[usize::from(self.len)] = item;
212 self.len += 1;
213 }
214}
215
216#[allow(clippy::large_enum_variant)]
217#[derive(Clone)]
218pub enum HotBodyInner<'req> {
219 Owned(Vec<u8>),
220 Shared(Shared),
221 Borrowed(Bytes<Borrowed<'req>>),
222 Retained(Bytes<Retained>),
223 Text(HotTextInner<'req>),
224 StaticSlice(&'static [u8]),
225}
226
227impl<'req> HotBodyInner<'req> {
228 pub(crate) fn body_len(&self) -> usize {
229 match self {
230 Self::Owned(body) => body.len(),
231 Self::Shared(body) => body.len(),
232 Self::Borrowed(body) => body.len(),
233 Self::Retained(body) => body.len(),
234 Self::Text(body) => body.len(),
235 Self::StaticSlice(body) => body.len(),
236 }
237 }
238
239 pub(crate) fn write_to(&self, out: &mut [u8]) -> usize {
240 match self {
241 Self::Owned(body) => {
242 let s = body.as_slice();
243 out[..s.len()].copy_from_slice(s);
244 s.len()
245 }
246 Self::Shared(body) => {
247 let s = body.as_ref();
248 out[..s.len()].copy_from_slice(s);
249 s.len()
250 }
251 Self::Borrowed(body) => {
252 let s = body.as_slice();
253 out[..s.len()].copy_from_slice(s);
254 s.len()
255 }
256 Self::Retained(body) => {
257 let s = body.as_slice();
258 out[..s.len()].copy_from_slice(s);
259 s.len()
260 }
261 Self::Text(body) => body.write_to(out),
262 Self::StaticSlice(body) => {
263 out[..body.len()].copy_from_slice(body);
264 body.len()
265 }
266 }
267 }
268
269 pub(crate) fn into_shared(self) -> Shared {
270 match self {
271 Self::Owned(body) => Shared::from(body),
272 Self::Shared(body) => body,
273 Self::Borrowed(body) => Shared::copy_from_slice(body.as_slice()),
274 Self::Retained(body) => body.into_shared(),
275 Self::Text(body) => body.into_bytes(),
276 Self::StaticSlice(body) => Shared::from_static(body),
277 }
278 }
279}
280
281impl<'req> From<BodyInner<'req>> for HotBodyInner<'req> {
282 fn from(body: BodyInner<'req>) -> Self {
283 match body {
284 BodyInner::Owned(body) => Self::Owned(body),
285 BodyInner::Shared(body) => Self::Shared(body),
286 BodyInner::Borrowed(body) => Self::Borrowed(body),
287 BodyInner::Retained(body) => Self::Retained(body),
288 BodyInner::StaticSlice(body) => Self::StaticSlice(body),
289 }
290 }
291}
292
293impl From<HotBodyInner<'static>> for BodyInner<'static> {
294 fn from(body: HotBodyInner<'static>) -> Self {
295 match body {
296 HotBodyInner::Owned(body) => Self::Owned(body),
297 HotBodyInner::Shared(body) => Self::Shared(body),
298 HotBodyInner::Borrowed(body) => Self::Shared(Shared::copy_from_slice(body.as_slice())),
299 HotBodyInner::Retained(body) => Self::Retained(body),
300 HotBodyInner::Text(body) => Self::Shared(body.into_bytes()),
301 HotBodyInner::StaticSlice(body) => Self::StaticSlice(body),
302 }
303 }
304}
305
306impl<'req> std::fmt::Debug for HotBodyInner<'req> {
307 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
308 match self {
309 Self::Owned(body) => f
310 .debug_struct("HotBody::Owned")
311 .field("len", &body.len())
312 .finish(),
313 Self::Shared(body) => f
314 .debug_struct("HotBody::Shared")
315 .field("len", &body.len())
316 .finish(),
317 Self::Borrowed(body) => f
318 .debug_struct("HotBody::Borrowed")
319 .field("len", &body.len())
320 .finish(),
321 Self::Retained(body) => f
322 .debug_struct("HotBody::Retained")
323 .field("len", &body.len())
324 .finish(),
325 Self::Text(body) => f
326 .debug_struct("HotBody::Text")
327 .field("len", &body.len())
328 .finish(),
329 Self::StaticSlice(body) => f
330 .debug_struct("HotBody::StaticSlice")
331 .field("len", &body.len())
332 .finish(),
333 }
334 }
335}