Skip to main content

base_message/
owned_fields.rs

1// Released under the MIT License.
2// Copyright, 2026, by Samuel Williams.
3
4use crate::__private::{IncomingField, IncomingName};
5use crate::FieldRef;
6use crate::field_ref::{IntoField, debug_field};
7use std::fmt;
8
9/// One field, owned, with its position in the original section.
10#[derive(Clone, PartialEq, Eq, Hash)]
11pub struct OwnedField {
12    position: usize,
13    name: String,
14    value: Vec<u8>,
15}
16
17impl OwnedField {
18    /// The field's position in the original section.
19    pub fn position(&self) -> usize {
20        self.position
21    }
22
23    /// The name as it was written.
24    pub fn name(&self) -> &str {
25        &self.name
26    }
27
28    /// The value, as it was passed to the section.
29    pub fn value(&self) -> &[u8] {
30        &self.value
31    }
32
33    /// The field, borrowed, so that another section can interpret it.
34    pub fn as_field_ref(&self) -> FieldRef<'_> {
35        FieldRef::new(self.position, &self.name, &self.value)
36    }
37}
38
39/// Shows the value's length rather than its bytes, since values such as `Authorization` and `Cookie` carry credentials that must not reach logs.
40impl fmt::Debug for OwnedField {
41    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
42        debug_field(
43            formatter,
44            "OwnedField",
45            self.position,
46            &self.name,
47            &self.value,
48        )
49    }
50}
51
52impl<'a> From<FieldRef<'a>> for OwnedField {
53    fn from(field: FieldRef<'a>) -> Self {
54        Self {
55            position: field.position(),
56            name: field.name().to_owned(),
57            value: field.value().to_vec(),
58        }
59    }
60}
61
62impl<'a, S> IntoField<'a, S> for &'a OwnedField {
63    fn into_field(self, _index: usize) -> IncomingField<'a> {
64        IncomingField {
65            position: self.position,
66            name: IncomingName::Text(&self.name),
67            value: &self.value,
68        }
69    }
70}
71
72/// A remainder that owns its fields, for keeping the fields a section does not take beyond the lifetime of the input, in order.
73///
74/// Use a `Vec<FieldRef>` instead to borrow them without copying. A section interprets owned fields by reference, keeping their original positions:
75///
76/// ```
77/// use base_message::{FieldSection, FieldType, FieldValueError, OwnedFields, ascii_text, combination::Singleton};
78///
79/// struct Text(String);
80///
81/// impl FieldType<'_> for Text {
82///     type Combination = Singleton;
83///     fn parse(value: &[u8]) -> Result<Self, FieldValueError> {
84///         Ok(Self(ascii_text(value)?.to_owned()))
85///     }
86/// }
87///
88/// #[derive(FieldSection)]
89/// struct Transport {
90///     #[field("host")]
91///     host: Text,
92/// }
93///
94/// #[derive(FieldSection)]
95/// struct Application {
96///     #[field("x-request-id")]
97///     request_id: Option<Text>,
98/// }
99///
100/// let (_, rest): (Transport, OwnedFields) = Transport::partition([("Host", "example.com"), ("X-Request-Id", "abc")])?;
101/// let application = Application::interpret(&rest)?;
102/// assert_eq!(application.request_id.map(|id| id.0).as_deref(), Some("abc"));
103/// # Ok::<(), base_message::FieldError>(())
104/// ```
105#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
106pub struct OwnedFields {
107    fields: Vec<OwnedField>,
108}
109
110impl OwnedFields {
111    /// The fields, in order.
112    pub fn iter(&self) -> std::slice::Iter<'_, OwnedField> {
113        self.fields.iter()
114    }
115
116    /// The fields, in order, as a slice.
117    pub fn as_slice(&self) -> &[OwnedField] {
118        &self.fields
119    }
120
121    /// The number of fields.
122    pub fn len(&self) -> usize {
123        self.fields.len()
124    }
125
126    /// Whether there are no fields.
127    pub fn is_empty(&self) -> bool {
128        self.fields.is_empty()
129    }
130
131    /// The values of every field named `name`, compared case-insensitively, in order.
132    pub fn values<'a>(&'a self, name: &'a str) -> impl Iterator<Item = &'a [u8]> + 'a {
133        self.fields
134            .iter()
135            .filter(move |field| field.name.eq_ignore_ascii_case(name))
136            .map(OwnedField::value)
137    }
138}
139
140impl<'a> Extend<FieldRef<'a>> for OwnedFields {
141    fn extend<I: IntoIterator<Item = FieldRef<'a>>>(&mut self, fields: I) {
142        self.fields.extend(fields.into_iter().map(OwnedField::from));
143    }
144}
145
146impl<'a> FromIterator<FieldRef<'a>> for OwnedFields {
147    fn from_iter<I: IntoIterator<Item = FieldRef<'a>>>(fields: I) -> Self {
148        Self {
149            fields: fields.into_iter().map(OwnedField::from).collect(),
150        }
151    }
152}
153
154impl<'a> IntoIterator for &'a OwnedFields {
155    type Item = &'a OwnedField;
156    type IntoIter = std::slice::Iter<'a, OwnedField>;
157
158    fn into_iter(self) -> Self::IntoIter {
159        self.iter()
160    }
161}
162
163impl IntoIterator for OwnedFields {
164    type Item = OwnedField;
165    type IntoIter = std::vec::IntoIter<OwnedField>;
166
167    fn into_iter(self) -> Self::IntoIter {
168        self.fields.into_iter()
169    }
170}