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