1pub(crate) mod address;
8pub(crate) mod content_type;
9pub(crate) mod date;
10pub(crate) mod id;
11pub(crate) mod list;
12pub(crate) mod raw;
13pub(crate) mod received;
14pub(crate) mod thread;
15pub(crate) mod unstructured;
16
17#[cfg(test)]
18pub(crate) mod tests;
19
20use crate::{
21 HeaderValue,
22 scan::Kernel,
23 store::{
24 AddressEntry, ContentTypeEntry, GROUP_BIT, MessageData, ParamEntry, ReceivedEntry, Span,
25 Str, Value,
26 },
27 view::Resolver,
28};
29use std::{fmt, ops::Range};
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33#[repr(u8)]
34pub enum HeaderForm {
35 Raw,
37 Text,
39 Addresses,
41 MessageIds,
43 CommaList,
45 Date,
47 ContentType,
49 Received,
51 Ignore,
53}
54
55impl HeaderForm {
56 pub fn parse(self, value: &[u8]) -> ParsedValue<'_> {
71 ParsedValue::new(self, value, 0..value.len())
72 }
73
74 pub(crate) fn parse_field(self, ctx: &mut FieldCtx<'_>, value: Range<usize>) -> Value {
75 match self {
76 HeaderForm::Raw => ctx.parse_raw(value),
77 HeaderForm::Text => ctx.parse_unstructured(value),
78 HeaderForm::Addresses => ctx.parse_address(value),
79 HeaderForm::MessageIds => ctx.parse_id(value),
80 HeaderForm::CommaList => ctx.parse_comma_list(value),
81 HeaderForm::Date => ctx.parse_date(value),
82 HeaderForm::ContentType => ctx.parse_content_type(value),
83 HeaderForm::Received => ctx.parse_received(value),
84 HeaderForm::Ignore => Value::Empty,
85 }
86 }
87}
88
89#[derive(Clone)]
95pub struct ParsedValue<'x> {
96 source: &'x [u8],
97 data: Option<MessageData>,
98 value: Value,
99}
100
101static EMPTY_DATA: MessageData = MessageData::EMPTY;
102
103impl<'x> ParsedValue<'x> {
104 pub(crate) fn new(form: HeaderForm, source: &'x [u8], range: Range<usize>) -> Self {
105 let range = first_field(source, range);
106 let value = match form {
107 HeaderForm::Ignore => Value::Empty,
108 HeaderForm::Date => date::parse_bytes(source.get(range).unwrap_or_default())
109 .map_or(Value::Empty, Value::DateTime),
110 HeaderForm::Raw => match raw::borrowed(source, range.clone()) {
111 Some(value) => value,
112 None => return Self::stored(source, |ctx| ctx.parse_raw(range)),
113 },
114 HeaderForm::Text => match unstructured::standalone(source, range) {
115 Ok(value) => value,
116 Err(pending) => return Self::stored(source, |ctx| pending.parse(ctx)),
117 },
118 HeaderForm::Addresses
119 | HeaderForm::MessageIds
120 | HeaderForm::CommaList
121 | HeaderForm::ContentType
122 | HeaderForm::Received => {
123 return Self::stored(source, |ctx| form.parse_field(ctx, range));
124 }
125 };
126 ParsedValue {
127 source,
128 data: None,
129 value,
130 }
131 }
132
133 fn stored(source: &'x [u8], parse: impl FnOnce(&mut FieldCtx<'_>) -> Value) -> Self {
134 let mut data = MessageData::default();
135 let value = parse(&mut FieldCtx::new(source, &mut data));
136 ParsedValue {
137 source,
138 data: Some(data),
139 value,
140 }
141 }
142
143 pub fn value(&self) -> HeaderValue<'_> {
145 let data = self.data.as_ref().unwrap_or(&EMPTY_DATA);
146 HeaderValue::new(Resolver::new(self.source, &data.strings), data, self.value)
147 }
148}
149
150impl PartialEq for ParsedValue<'_> {
151 fn eq(&self, other: &Self) -> bool {
152 self.value() == other.value()
153 }
154}
155
156impl Eq for ParsedValue<'_> {}
157
158impl fmt::Debug for ParsedValue<'_> {
159 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160 f.debug_struct("ParsedValue")
161 .field("value", &self.value())
162 .finish()
163 }
164}
165
166pub(crate) fn first_field(source: &[u8], range: Range<usize>) -> Range<usize> {
167 let end = Kernel::MEMCHR
168 .field_end(source, range.start)
169 .map_or(range.end, |newline| range.end.min(newline + 1));
170 range.start..end
171}
172
173const FIRST_ADDRESSES: usize = 16;
174const FIRST_PARAMS: usize = 16;
175const FIRST_CONTENT_TYPES: usize = 16;
176const FIRST_RECEIVED: usize = 8;
177
178fn push_sized<T>(items: &mut Vec<T>, item: T, first: usize) {
179 if items.capacity() == 0 {
180 items.reserve_exact(first);
181 }
182 items.push(item);
183}
184
185pub(crate) fn push_utf8_lossy(out: &mut String, bytes: &[u8]) {
186 for chunk in bytes.utf8_chunks() {
187 out.push_str(chunk.valid());
188 if !chunk.invalid().is_empty() {
189 out.push(char::REPLACEMENT_CHARACTER);
190 }
191 }
192}
193
194pub(crate) fn is_fws(byte: u8) -> bool {
195 matches!(byte, b' ' | b'\t' | b'\r' | b'\n')
196}
197
198pub(crate) fn trim_fws(src: &[u8], range: Range<usize>) -> Range<usize> {
199 let bytes = src.get(range.clone()).unwrap_or_default();
200 let start = bytes.iter().position(|&byte| !is_fws(byte));
201 let end = bytes.iter().rposition(|&byte| !is_fws(byte));
202 match (start, end) {
203 (Some(start), Some(end)) => range.start + start..range.start + end + 1,
204 _ => range.start..range.start,
205 }
206}
207
208pub(crate) struct FieldCtx<'a> {
209 src: &'a [u8],
210 data: &'a mut MessageData,
211 kernel: Kernel,
212}
213
214#[derive(Debug, Clone, Copy, PartialEq, Eq)]
215pub(crate) struct GroupMark(u32);
216
217impl<'a> FieldCtx<'a> {
218 pub(crate) fn new(src: &'a [u8], data: &'a mut MessageData) -> Self {
219 FieldCtx::with_kernel(src, data, Kernel::best())
220 }
221
222 pub(crate) fn with_kernel(src: &'a [u8], data: &'a mut MessageData, kernel: Kernel) -> Self {
223 FieldCtx { src, data, kernel }
224 }
225
226 pub(crate) fn src(&self) -> &'a [u8] {
227 self.src
228 }
229
230 pub(crate) fn kernel(&self) -> Kernel {
231 self.kernel
232 }
233
234 pub(crate) fn bytes(&self, range: Range<usize>) -> &'a [u8] {
235 self.src.get(range).unwrap_or_default()
236 }
237
238 pub(crate) fn resolve(&self, text: Str) -> &str {
239 text.resolve(self.src, &self.data.strings)
240 }
241
242 pub(crate) fn try_borrow(&self, range: Range<usize>) -> Option<Str> {
243 Str::borrow(self.src, range)
244 }
245
246 pub(crate) fn borrow(&mut self, range: Range<usize>) -> Str {
247 match Str::borrow(self.src, range.clone()) {
248 Some(text) => text,
249 None => self.push_lossy(self.bytes(range)),
250 }
251 }
252
253 pub(crate) fn push_str(&mut self, text: &str) -> Str {
254 Str::push(&mut self.data.strings, text)
255 }
256
257 pub(crate) fn push_lossy(&mut self, bytes: &[u8]) -> Str {
258 Str::push_with(&mut self.data.strings, |pool| push_utf8_lossy(pool, bytes))
259 }
260
261 pub(crate) fn push_with(&mut self, write: impl FnOnce(&mut String)) -> Str {
262 Str::push_with(&mut self.data.strings, write)
263 }
264
265 pub(crate) fn lowercase(&mut self, range: Range<usize>) -> Str {
266 let upper = self.bytes(range.clone()).iter().any(u8::is_ascii_uppercase);
267 self.lowercase_scanned(range, upper)
268 }
269
270 pub(crate) fn lowercase_scanned(&mut self, range: Range<usize>, upper: bool) -> Str {
271 if !upper && let Some(text) = Str::borrow(self.src, range.clone()) {
272 return text;
273 }
274 let bytes = self.bytes(range);
275 Str::push_with(&mut self.data.strings, |pool| {
276 let start = pool.len();
277 push_utf8_lossy(pool, bytes);
278 if let Some(pushed) = pool.get_mut(start..) {
279 pushed.make_ascii_lowercase();
280 }
281 })
282 }
283
284 pub(crate) fn trim_fws(&self, range: Range<usize>) -> Range<usize> {
285 trim_fws(self.src, range)
286 }
287
288 pub(crate) fn take_text_scratch(&mut self) -> String {
289 let mut text = std::mem::take(&mut self.data.scratch.text);
290 text.clear();
291 text
292 }
293
294 pub(crate) fn put_text_scratch(&mut self, text: String) {
295 self.data.scratch.text = text;
296 }
297
298 pub(crate) fn take_bytes_scratch(&mut self) -> Vec<u8> {
299 let mut bytes = std::mem::take(&mut self.data.scratch.bytes);
300 bytes.clear();
301 bytes
302 }
303
304 pub(crate) fn put_bytes_scratch(&mut self, bytes: Vec<u8>) {
305 self.data.scratch.bytes = bytes;
306 }
307
308 pub(crate) fn text_items_mark(&self) -> u32 {
309 self.data.text_items.len() as u32
310 }
311
312 pub(crate) fn push_text_item(&mut self, item: Str) {
313 self.data.push_text_item(item);
314 }
315
316 pub(crate) fn text_list(&self, mark: u32) -> Value {
317 match (self.data.text_items.len() as u32).saturating_sub(mark) {
318 0 => Value::Empty,
319 len => Value::TextList(Span { start: mark, len }),
320 }
321 }
322
323 pub(crate) fn address_mark(&self) -> u32 {
324 self.data.address_items.len() as u32
325 }
326
327 pub(crate) fn push_mailbox(&mut self, name: Option<Str>, address: Option<Str>) {
328 self.data.address_items.push(
329 AddressEntry {
330 name: Str::from_option(name),
331 address: Str::from_option(address),
332 group: 0,
333 },
334 FIRST_ADDRESSES,
335 );
336 }
337
338 pub(crate) fn push_group(&mut self, name: Option<Str>) -> GroupMark {
339 let mark = GroupMark(self.data.address_items.len() as u32);
340 self.data.address_items.push(
341 AddressEntry {
342 name: Str::from_option(name),
343 address: Str::NONE,
344 group: GROUP_BIT,
345 },
346 FIRST_ADDRESSES,
347 );
348 mark
349 }
350
351 pub(crate) fn end_group(&mut self, group: GroupMark) {
352 let members = (self.data.address_items.len() as u32).saturating_sub(group.0 + 1);
353 if let Some(entry) = self.data.address_items.get_mut(group.0 as usize) {
354 entry.group = GROUP_BIT | members;
355 }
356 }
357
358 pub(crate) fn address_list(&self, mark: u32) -> Value {
359 let len = (self.data.address_items.len() as u32).saturating_sub(mark);
360 if len == 0 {
361 Value::Empty
362 } else {
363 Value::Address(Span { start: mark, len })
364 }
365 }
366
367 pub(crate) fn params_mark(&self) -> u32 {
368 self.data.params.len() as u32
369 }
370
371 pub(crate) fn push_param(&mut self, name: Str, value: Str) {
372 self.data
373 .params
374 .push(ParamEntry { name, value }, FIRST_PARAMS);
375 }
376
377 pub(crate) fn params_since(&self, mark: u32) -> &[ParamEntry] {
378 self.data.params.get(mark as usize..).unwrap_or_default()
379 }
380
381 pub(crate) fn set_param_value(&mut self, index: u32, value: Str) {
382 if let Some(param) = self.data.params.get_mut(index as usize) {
383 param.value = value;
384 }
385 }
386
387 pub(crate) fn rollback_params(&mut self, mark: u32) {
388 self.data.params.truncate(mark as usize);
389 }
390
391 pub(crate) fn remove_param(&mut self, index: u32) {
392 if let Some(param) = self.data.params.get_mut(index as usize) {
393 param.name = Str::NONE;
394 }
395 }
396
397 pub(crate) fn drop_removed_params(&mut self, mark: u32) {
398 let params = &mut self.data.params;
399 let mut kept = mark as usize;
400 for index in mark as usize..params.len() {
401 let Some(¶m) = params.get(index) else {
402 break;
403 };
404 if param.name.is_some() {
405 if let Some(slot) = params.get_mut(kept) {
406 *slot = param;
407 }
408 kept += 1;
409 }
410 }
411 params.truncate(kept);
412 }
413
414 pub(crate) fn content_type(&mut self, ctype: Str, subtype: Option<Str>, params: u32) -> Value {
415 let index = self.data.content_types.len() as u32;
416 let params = Span {
417 start: params,
418 len: (self.data.params.len() as u32).saturating_sub(params),
419 };
420 self.data.content_types.push(
421 ContentTypeEntry {
422 ctype,
423 subtype: Str::from_option(subtype),
424 params,
425 },
426 FIRST_CONTENT_TYPES,
427 );
428 Value::ContentType(index)
429 }
430
431 pub(crate) fn received(&mut self, entry: ReceivedEntry) -> Value {
432 let index = self.data.received.len() as u32;
433 push_sized(&mut self.data.received, entry, FIRST_RECEIVED);
434 Value::Received(index)
435 }
436}