base-message 0.1.0

Interpret the header and trailer field sections of protocol messages into typed structs
Documentation
// Released under the MIT License.
// Copyright, 2026, by Samuel Williams.

use crate::FieldValueError;
use crate::combination::Combination;

/// What an invalid value means for a section.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum InvalidValue {
    /// The section cannot be interpreted. This suits fields whose meaning matters for safety, such as `Content-Length`.
    Error,
    /// 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.
    Ignore,
}

/// One kind of field: how its instances combine, how one value parses, and what an invalid value means.
///
/// 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<'_>`:
///
/// ```
/// use base_message::{FieldType, FieldValueError, ascii_text, combination::Singleton};
///
/// struct ContentLength(u64);
///
/// impl FieldType<'_> for ContentLength {
///     type Combination = Singleton;
///
///     fn parse(value: &[u8]) -> Result<Self, FieldValueError> {
///         let text = ascii_text(value)?;
///         if text.is_empty() || !text.bytes().all(|byte| byte.is_ascii_digit()) {
///             return Err(FieldValueError::new("not a decimal length"));
///         }
///         text.parse().map(Self).map_err(|_| FieldValueError::new("length too large"))
///     }
/// }
///
/// /// A field type that borrows its value, rather than copying it.
/// struct Host<'a>(&'a str);
///
/// impl<'a> FieldType<'a> for Host<'a> {
///     type Combination = Singleton;
///
///     fn parse(value: &'a [u8]) -> Result<Self, FieldValueError> {
///         ascii_text(value).map(Self)
///     }
/// }
/// ```
pub trait FieldType<'a>: Sized {
    /// One of the markers in [`combination`](crate::combination): [`Singleton`](crate::combination::Singleton), [`List`](crate::combination::List), or [`Separate`](crate::combination::Separate).
    type Combination: Combination;

    /// What an invalid value means, unless a declaration overrides it with `invalid = "..."`. A required declaration always treats an invalid value as an error.
    const INVALID: InvalidValue = InvalidValue::Error;

    /// Parse one instance, or one element of a list, with surrounding spaces and tabs already removed.
    ///
    /// # Errors
    ///
    /// A [`FieldValueError`] describing why the value is invalid, without repeating it.
    fn parse(value: &'a [u8]) -> Result<Self, FieldValueError>;
}