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<S> {
86    bytes: S,
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    CapacityOverflow {
97        current: usize,
98        name: usize,
99        value: usize,
100    },
101    ValueLengthMismatch {
102        expected: usize,
103        actual: usize,
104    },
105}
106
107fn packed_len(len: usize) -> Result<u32, usize> {
108    if len > u32::MAX as usize {
109        return Err(len);
110    }
111    Ok(len as u32)
112}
113
114impl From<usize> for Error {
115    fn from(len: usize) -> Self {
116        Self::ComponentTooLarge { len }
117    }
118}
119
120impl<S: AsRef<[u8]>> metadata::Metadata for Fields<S> {
121    type Iter<'a>
122        = Iter<'a>
123    where
124        S: 'a;
125
126    fn fields(&self) -> Self::Iter<'_> {
127        Iter::new(self.bytes.as_ref())
128    }
129}
130
131impl Fields<Vec<u8>> {
132    pub const fn new() -> Self {
133        Self { bytes: Vec::new() }
134    }
135
136    pub fn try_with(capacity: usize) -> Result<Self, Error> {
137        Ok(Self {
138            bytes: Vec::try_new(capacity).map_err(Error::Reserve)?,
139        })
140    }
141
142    pub fn push(&mut self, name: &[u8], value: &[u8]) -> Result<(), Error> {
143        self.push_entry(Entry::new(name, value))
144    }
145
146    pub fn push_entry(&mut self, field: Entry<'_>) -> Result<(), Error> {
147        Space::new(
148            &mut self.bytes,
149            field.name.len(),
150            field.value.len(),
151            field.indexing,
152        )?
153        .generated(field.name, |writer| writer.write_slice(field.value))?
154        .commit();
155        Ok(())
156    }
157
158    /// Publishes only a successful callback that writes exactly `vlen` bytes.
159    /// Rejected writes leave the staged value unchanged and may be handled by
160    /// the callback; returning their error leaves this field unpublished.
161    pub fn push_encoded<F>(&mut self, name: &[u8], vlen: usize, encode: F) -> Result<(), Error>
162    where
163        F: FnOnce(&mut ValueWriter<'_>) -> Result<(), consume::Error>,
164    {
165        self.push_with(name, vlen, crate::field::Indexing::Allowed, encode)
166    }
167
168    /// Uses the publication and recovery contract of [`Self::push_encoded`].
169    pub fn push_with<F>(
170        &mut self,
171        name: &[u8],
172        vlen: usize,
173        indexing: crate::field::Indexing,
174        encode: F,
175    ) -> Result<(), Error>
176    where
177        F: FnOnce(&mut ValueWriter<'_>) -> Result<(), consume::Error>,
178    {
179        Space::new(&mut self.bytes, name.len(), vlen, indexing)?
180            .generated(name, encode)?
181            .commit();
182        Ok(())
183    }
184}
185
186impl<S: AsRef<[u8]>> Fields<S> {
187    pub fn iter(&self) -> Iter<'_> {
188        Iter::new(self.bytes.as_ref())
189    }
190
191    pub fn get(&self, name: &[u8]) -> Option<&[u8]> {
192        self.iter()
193            .find(|field| field.name == name)
194            .map(|field| field.value)
195    }
196
197    pub fn as_bytes(&self) -> &[u8] {
198        self.bytes.as_ref()
199    }
200
201    pub fn ranges(&self) -> RangeIter<'_> {
202        RangeIter::new(self.bytes.as_ref())
203    }
204}
205
206impl Default for Fields<Vec<u8>> {
207    fn default() -> Self {
208        Self::new()
209    }
210}
211
212/// One callback-local value emission retaining its unpublished owner and exact capacity.
213#[repr(transparent)]
214pub struct ValueWriter<'a>(write::Staged<'a, usize>);
215
216impl write::Sink for ValueWriter<'_> {
217    type Error = consume::Error;
218
219    fn write_slice(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
220        self.0.write_slice(bytes)
221    }
222
223    fn write_slices<const N: usize>(&mut self, slices: [&[u8]; N]) -> Result<(), Self::Error> {
224        self.0.write_slices(slices)
225    }
226}
227
228const _: () = {
229    assert!(mem::size_of::<OwnedIter<'static>>() == mem::size_of::<&[Owned]>());
230    assert!(
231        mem::size_of::<ValueWriter<'static>>() == mem::size_of::<write::Staged<'static, usize>>()
232    );
233};
234
235struct Space<'a> {
236    stage: write::Staged<'a, usize>,
237    prefix: [u8; Prefix::LEN],
238    vlen: usize,
239}
240
241impl<'a> Space<'a> {
242    fn new(
243        bytes: &'a mut Vec<u8>,
244        name: usize,
245        value: usize,
246        indexing: crate::field::Indexing,
247    ) -> Result<Self, Error> {
248        let nwire = packed_len(name)?;
249        let vwire = packed_len(value)?;
250        let added = Prefix::LEN + nwire as usize + vwire as usize;
251        let stage = write::Staged::<usize>::try_reserve(bytes, added).map_err(Error::Reserve)?;
252        Ok(Self {
253            stage,
254            prefix: Prefix::new(nwire, vwire, indexing).to_bytes(),
255            vlen: value,
256        })
257    }
258
259    fn generated<F>(self, name: &[u8], encode: F) -> Result<write::Staged<'a, usize>, Error>
260    where
261        F: FnOnce(&mut ValueWriter<'_>) -> Result<(), consume::Error>,
262    {
263        let expected = self.vlen;
264        let prefix = self.stage.capacity() - expected;
265        let mut writer = ValueWriter(self.stage);
266        writer
267            .write_slices([&self.prefix, name])
268            .map_err(Error::Write)?;
269        encode(&mut writer).map_err(Error::Write)?;
270        writer.0.try_complete().map_err(|error| {
271            let (_, actual) = error.into_parts();
272            Error::ValueLengthMismatch {
273                expected,
274                actual: actual - prefix,
275            }
276        })
277    }
278}