Skip to main content

base_message/
field_type.rs

1// Released under the MIT License.
2// Copyright, 2026, by Samuel Williams.
3
4use crate::FieldValueError;
5use crate::combination::Combination;
6
7/// What an invalid value means for a section.
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
9pub enum InvalidValue {
10    /// The section cannot be interpreted. This suits fields whose meaning matters for safety, such as `Content-Length`.
11    Error,
12    /// The value is skipped, as RFC 9110 permits for advisory fields such as `Accept`. A skipped singleton still counts as present, so a second instance is still a duplicate. A required declaration always treats an invalid value as an error.
13    Ignore,
14}
15
16/// One kind of field: how its instances combine, how one value parses, and what an invalid value means.
17///
18/// The lifetime is that of the field values, so a field type can borrow from them. A field type that owns its value implements `FieldType<'_>`:
19///
20/// ```
21/// use base_message::{FieldType, FieldValueError, ascii_text, combination::Singleton};
22///
23/// struct ContentLength(u64);
24///
25/// impl FieldType<'_> for ContentLength {
26///     type Combination = Singleton;
27///
28///     fn parse(value: &[u8]) -> Result<Self, FieldValueError> {
29///         let text = ascii_text(value)?;
30///         if text.is_empty() || !text.bytes().all(|byte| byte.is_ascii_digit()) {
31///             return Err(FieldValueError::new("not a decimal length"));
32///         }
33///         text.parse().map(Self).map_err(|_| FieldValueError::new("length too large"))
34///     }
35/// }
36///
37/// /// A field type that borrows its value, rather than copying it.
38/// struct Host<'a>(&'a str);
39///
40/// impl<'a> FieldType<'a> for Host<'a> {
41///     type Combination = Singleton;
42///
43///     fn parse(value: &'a [u8]) -> Result<Self, FieldValueError> {
44///         ascii_text(value).map(Self)
45///     }
46/// }
47/// ```
48pub trait FieldType<'a>: Sized {
49    /// One of the markers in [`combination`](crate::combination): [`Singleton`](crate::combination::Singleton), [`List`](crate::combination::List), or [`Separate`](crate::combination::Separate).
50    type Combination: Combination;
51
52    /// What an invalid value means, unless a declaration overrides it with `invalid = "..."`. A required declaration always treats an invalid value as an error.
53    const INVALID: InvalidValue = InvalidValue::Error;
54
55    /// Parse one instance, or one element of a list, with surrounding spaces and tabs already removed.
56    ///
57    /// # Errors
58    ///
59    /// A [`FieldValueError`] describing why the value is invalid, without repeating it.
60    fn parse(value: &'a [u8]) -> Result<Self, FieldValueError>;
61}