1use std::convert::TryFrom;
4use std::fmt::Debug;
5use std::ffi::c_char;
6
7pub enum HeaderError {
9 NameTooLong,
10 ValueTooLong,
11 NameInvalidUtf8,
12 ValueInvalidUtf8,
13}
14
15pub struct Header {
19 buffer: Box<[u8]>,
20 name_offset: usize,
21 name_len: usize,
22 value_offset: usize,
23 value_len: usize,
24}
25
26impl Header {
27 pub const MAX_LEN_NAME: usize = u16::MAX as usize;
28 pub const MAX_LEN_VALUE: usize = u16::MAX as usize;
29
30 pub fn new<N, V>(name: N, value: V) -> Result<Self, HeaderError>
39 where
40 N: AsRef<str>,
41 V: AsRef<str>,
42 {
43 let name = name.as_ref();
44 let value = value.as_ref();
45
46 if name.len() > Self::MAX_LEN_NAME {
47 return Err(HeaderError::NameTooLong);
48 }
49
50 if value.len() > Self::MAX_LEN_VALUE {
51 return Err(HeaderError::ValueTooLong);
52 }
53
54 let mut buffer = Vec::with_capacity(name.len() + value.len());
55 buffer.extend(name.as_bytes());
56 buffer.extend(value.as_bytes());
57
58 let name_offset = 0;
59 let name_len = name.len();
60 let value_offset = name.len();
61 let value_len = value.len(); Ok(Self {
64 buffer: buffer.into_boxed_slice(),
65 name_offset,
66 name_len,
67 value_offset,
68 value_len,
69 })
70 }
71
72 #[inline]
74 pub fn name(&self) -> &str {
75 debug_assert!(std::str::from_utf8(
76 &self.buffer[self.name_offset..self.name_offset + self.name_len]
77 )
78 .is_ok());
79
80 unsafe {
81 std::str::from_utf8_unchecked(
82 &self.buffer[self.name_offset..self.name_offset + self.name_len],
83 )
84 }
85 }
86
87 #[inline]
89 pub fn value(&self) -> &str {
90 debug_assert!(std::str::from_utf8(
91 &self.buffer[self.value_offset..self.value_offset + self.value_len]
92 )
93 .is_ok());
94
95 unsafe {
96 std::str::from_utf8_unchecked(
97 &self.buffer[self.value_offset..self.value_offset + self.value_len],
98 )
99 }
100 }
101
102 pub(crate) fn with_buffer(
103 buffer: Box<[u8]>,
104 name_offset: usize,
105 name_len: usize,
106 value_offset: usize,
107 value_len: usize,
108 ) -> Result<Self, HeaderError> {
109 if name_len > Self::MAX_LEN_NAME {
110 return Err(HeaderError::NameTooLong);
111 }
112
113 if value_len > Self::MAX_LEN_VALUE {
114 return Err(HeaderError::ValueTooLong);
115 }
116
117 if std::str::from_utf8(&buffer[name_offset..name_offset + name_len]).is_err() {
118 return Err(HeaderError::NameInvalidUtf8);
119 }
120
121 if std::str::from_utf8(&buffer[value_offset..value_offset + value_len]).is_err() {
122 return Err(HeaderError::ValueInvalidUtf8);
123 }
124
125 debug_assert!(name_offset < u16::MAX as usize);
126 debug_assert!(value_offset < u16::MAX as usize);
127
128 Ok(Self {
129 buffer,
130 name_offset,
131 name_len,
132 value_offset,
133 value_len,
134 })
135 }
136
137 pub(crate) fn build_lsxpack_header(&mut self) -> LsxpackHeader {
139 LsxpackHeader::new(self)
140 }
141}
142
143impl Debug for Header {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 f.debug_struct("Header")
146 .field("name", &self.name())
147 .field("value", &self.value())
148 .finish()
149 }
150}
151
152pub trait TryIntoHeader {
161 fn try_into_header(self) -> Result<Header, HeaderError>;
162}
163
164impl<N, V> TryFrom<(N, V)> for Header
165where
166 N: AsRef<str>,
167 V: AsRef<str>,
168{
169 type Error = HeaderError;
170
171 fn try_from(value: (N, V)) -> Result<Self, Self::Error> {
172 Header::new(value.0, value.1)
173 }
174}
175
176impl<N, V> TryIntoHeader for (N, V)
177where
178 N: AsRef<str>,
179 V: AsRef<str>,
180{
181 fn try_into_header(self) -> Result<Header, HeaderError> {
182 Header::new(self.0, self.1)
183 }
184}
185
186pub(crate) struct LsxpackHeader<'a> {
187 header_sys: ls_qpack_sys::lsxpack_header,
188 #[allow(unused)]
189 header_ref: &'a mut Header,
190}
191
192impl<'a> LsxpackHeader<'a> {
193 pub(crate) fn new(header: &'a mut Header) -> Self {
194 debug_assert!(header.name_offset < u16::MAX as usize);
195 debug_assert!(header.name_len < Header::MAX_LEN_NAME);
196 debug_assert!(header.value_offset < u16::MAX as usize);
197 debug_assert!(header.value_len < Header::MAX_LEN_VALUE);
198
199 let header_sys = ls_qpack_sys::lsxpack_header {
200 buf: header.buffer.as_mut_ptr() as *mut c_char,
201 name_offset: header.name_offset as i32,
202 name_len: header.name_len as u16,
203 val_offset: header.value_offset as i32,
204 val_len: header.value_len as u16,
205 ..Default::default()
206 };
207
208 Self {
209 header_sys,
210 header_ref: header,
211 }
212 }
213}
214
215impl<'a> AsRef<ls_qpack_sys::lsxpack_header> for LsxpackHeader<'a> {
216 fn as_ref(&self) -> &ls_qpack_sys::lsxpack_header {
217 &self.header_sys
218 }
219}