Skip to main content

sark_http/field/metadata/map/
mod.rs

1//! Packed metadata maps and their borrowed records.
2
3use std::mem;
4
5use metadata::packed::{Iter, RangeIter, prefix::Prefix};
6use o3::{
7    alloc,
8    alloc::{BoxSliceExt as _, VecExt as _},
9    buffer::write::{self, Sink as _, consume},
10};
11use record::Entry;
12
13use crate::field::metadata;
14
15pub mod record;
16
17#[derive(PartialEq, Eq)]
18pub struct Owned {
19    pub name: Vec<u8>,
20    pub value: Vec<u8>,
21    pub indexing: crate::field::Indexing,
22}
23
24impl Owned {
25    pub fn try_new(name: &[u8], value: &[u8]) -> Result<Self, alloc::Exhausted> {
26        Ok(Self {
27            name: Box::<[u8]>::try_copy(name)?.into_vec(),
28            value: Box::<[u8]>::try_copy(value)?.into_vec(),
29            indexing: crate::field::Indexing::Allowed,
30        })
31    }
32
33    pub fn as_ref(&self) -> Entry<'_> {
34        Entry::new(&self.name, &self.value).with_index(self.indexing)
35    }
36
37    pub fn with_index(mut self, indexing: crate::field::Indexing) -> Self {
38        self.indexing = indexing;
39        self
40    }
41}
42
43impl TryFrom<Entry<'_>> for Owned {
44    type Error = alloc::Exhausted;
45
46    fn try_from(field: Entry<'_>) -> Result<Self, Self::Error> {
47        Ok(Self::try_new(field.name, field.value)?.with_index(field.indexing))
48    }
49}
50
51#[derive(Clone)]
52pub struct OwnedIter<'a> {
53    fields: &'a [Owned],
54}
55
56impl<'a> Iterator for OwnedIter<'a> {
57    type Item = Entry<'a>;
58
59    fn next(&mut self) -> Option<Self::Item> {
60        let (field, rest) = self.fields.split_first()?;
61        self.fields = rest;
62        Some(field.as_ref())
63    }
64
65    fn size_hint(&self) -> (usize, Option<usize>) {
66        let len = self.fields.len();
67        (len, Some(len))
68    }
69}
70
71impl ExactSizeIterator for OwnedIter<'_> {}
72
73impl metadata::Metadata for Vec<Owned> {
74    type Iter<'a> = OwnedIter<'a>;
75
76    fn fields(&self) -> Self::Iter<'_> {
77        OwnedIter {
78            fields: self.as_slice(),
79        }
80    }
81}
82
83/// One contiguous packed field block with no secondary-owner slot.
84#[derive(PartialEq, Eq)]
85pub struct Fields {
86    bytes: Vec<u8>,
87}
88
89#[derive(Clone, Debug, PartialEq, Eq)]
90pub enum Error {
91    Reserve(alloc::Error),
92    Write(consume::Error),
93    ComponentTooLarge {
94        len: usize,
95    },
96    ValueLengthMismatch {
97        expected: usize,
98        actual: usize,
99    },
100}
101
102fn packed_len(len: usize) -> Result<u32, usize> {
103    if len > u32::MAX as usize {
104        return Err(len);
105    }
106    Ok(len as u32)
107}
108
109impl From<usize> for Error {
110    fn from(len: usize) -> Self {
111        Self::ComponentTooLarge { len }
112    }
113}
114
115impl metadata::Metadata for Fields {
116    type Iter<'a> = Iter<'a>;
117
118    fn fields(&self) -> Self::Iter<'_> {
119        Iter::new(self.bytes.as_ref())
120    }
121}
122
123impl Fields {
124    pub const fn new() -> Self {
125        Self { bytes: Vec::new() }
126    }
127
128    pub fn try_with(capacity: usize) -> Result<Self, Error> {
129        Ok(Self {
130            bytes: Vec::try_new(capacity).map_err(Error::Reserve)?,
131        })
132    }
133
134    pub fn push(&mut self, name: &[u8], value: &[u8]) -> Result<(), Error> {
135        self.push_entry(Entry::new(name, value))
136    }
137
138    pub fn push_entry(&mut self, field: Entry<'_>) -> Result<(), Error> {
139        self.push_with(
140            field.name,
141            field.value.len(),
142            field.indexing,
143            |writer| writer.write_slice(field.value),
144        )
145    }
146
147    /// Publishes only a successful callback that writes exactly `vlen` bytes.
148    /// Rejected writes leave the staged value unchanged and may be handled by
149    /// the callback; returning their error leaves this field unpublished.
150    pub fn push_encoded<F>(&mut self, name: &[u8], vlen: usize, encode: F) -> Result<(), Error>
151    where
152        F: FnOnce(&mut ValueWriter<'_>) -> Result<(), consume::Error>,
153    {
154        self.push_with(name, vlen, crate::field::Indexing::Allowed, encode)
155    }
156
157    /// Uses the publication and recovery contract of [`Self::push_encoded`].
158    pub fn push_with<F>(
159        &mut self,
160        name: &[u8],
161        vlen: usize,
162        indexing: crate::field::Indexing,
163        encode: F,
164    ) -> Result<(), Error>
165    where
166        F: FnOnce(&mut ValueWriter<'_>) -> Result<(), consume::Error>,
167    {
168        Space::new(&mut self.bytes, name.len(), vlen, indexing)?
169            .generated(name, encode)?
170            .commit();
171        Ok(())
172    }
173
174    pub fn iter(&self) -> Iter<'_> {
175        Iter::new(self.bytes.as_ref())
176    }
177
178    pub fn get(&self, name: &[u8]) -> Option<&[u8]> {
179        self.iter()
180            .find(|field| field.name == name)
181            .map(|field| field.value)
182    }
183
184    pub fn as_bytes(&self) -> &[u8] {
185        self.bytes.as_ref()
186    }
187
188    pub fn ranges(&self) -> RangeIter<'_> {
189        RangeIter::new(self.bytes.as_ref(), 0)
190    }
191}
192
193impl Default for Fields {
194    fn default() -> Self {
195        Self::new()
196    }
197}
198
199/// One callback-local value emission retaining its unpublished owner and exact capacity.
200#[repr(transparent)]
201pub struct ValueWriter<'a>(write::Staged<'a, usize>);
202
203impl write::Sink for ValueWriter<'_> {
204    type Error = consume::Error;
205
206    fn write_slice(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
207        self.0.write_slice(bytes)
208    }
209
210    fn write_slices<const N: usize>(&mut self, slices: [&[u8]; N]) -> Result<(), Self::Error> {
211        self.0.write_slices(slices)
212    }
213}
214
215const _: () = {
216    assert!(mem::size_of::<OwnedIter<'static>>() == mem::size_of::<&[Owned]>());
217    assert!(
218        mem::size_of::<ValueWriter<'static>>() == mem::size_of::<write::Staged<'static, usize>>()
219    );
220};
221
222struct Space<'a> {
223    stage: write::Staged<'a, usize>,
224    prefix: [u8; Prefix::LEN],
225    vlen: usize,
226}
227
228impl<'a> Space<'a> {
229    fn new(
230        bytes: &'a mut Vec<u8>,
231        name: usize,
232        value: usize,
233        indexing: crate::field::Indexing,
234    ) -> Result<Self, Error> {
235        let nwire = packed_len(name)?;
236        let vwire = packed_len(value)?;
237        let added = Prefix::LEN + nwire as usize + vwire as usize;
238        let stage = write::Staged::<usize>::try_reserve(bytes, added).map_err(Error::Reserve)?;
239        Ok(Self {
240            stage,
241            prefix: Prefix::new(nwire, vwire, indexing).to_bytes(),
242            vlen: value,
243        })
244    }
245
246    fn generated<F>(self, name: &[u8], encode: F) -> Result<write::Staged<'a, usize>, Error>
247    where
248        F: FnOnce(&mut ValueWriter<'_>) -> Result<(), consume::Error>,
249    {
250        let expected = self.vlen;
251        let prefix = self.stage.capacity() - expected;
252        let mut writer = ValueWriter(self.stage);
253        writer
254            .write_slices([&self.prefix, name])
255            .map_err(Error::Write)?;
256        encode(&mut writer).map_err(Error::Write)?;
257        writer.0.try_complete().map_err(|error| {
258            let (_, actual) = error.into_parts();
259            Error::ValueLengthMismatch {
260                expected,
261                actual: actual - prefix,
262            }
263        })
264    }
265}