Skip to main content

sark_http/field/metadata/packed/
decoded.rs

1use std::mem;
2
3use map::{Owned, record::Entry};
4use o3::{
5    alloc,
6    buffer::{bytes::scope, pool, pool::owners, storage::Shared, write},
7};
8use packed::{Iter, RangeIter, prefix::Prefix};
9use write::{SpareExt as _, edit, spans};
10
11use crate::field::metadata::{self, lower::plain::Error, map, packed, section::storage};
12
13#[derive(Debug)]
14#[repr(transparent)]
15pub struct Decoded<S = pool::Span, const PREFIX: usize = 0> {
16    storage: S,
17}
18
19impl Decoded {
20    /// Validates arbitrary storage once before exposing infallible iteration.
21    pub fn try_from(storage: pool::Span) -> Result<Self, storage::Fault> {
22        Ok(<Self as storage::Block>::from(storage::Finished::try_from(
23            storage,
24        )?))
25    }
26}
27
28impl<const PREFIX: usize> Decoded<pool::Span, PREFIX> {
29    /// Consumes the record proof and returns its exclusively owned storage.
30    pub fn into_lease(self) -> pool::Span {
31        self.storage
32    }
33}
34
35impl<const PREFIX: usize> From<Decoded<pool::Span, PREFIX>> for Shared {
36    fn from(value: Decoded<pool::Span, PREFIX>) -> Self {
37        value.storage.freeze().into_shared()
38    }
39}
40
41impl<S: AsRef<[u8]>, const PREFIX: usize> Decoded<S, PREFIX> {
42    pub fn iter(&self) -> Iter<'_> {
43        Iter::new(&self.storage.as_ref()[PREFIX..])
44    }
45
46    pub fn len(&self) -> usize {
47        self.iter().count()
48    }
49
50    pub fn is_empty(&self) -> bool {
51        self.storage.as_ref().len() == PREFIX
52    }
53
54    pub fn get(&self, name: &[u8]) -> Option<&[u8]> {
55        self.iter()
56            .find(|field| field.name == name)
57            .map(|field| field.value)
58    }
59
60    pub fn as_bytes(&self) -> &[u8] {
61        self.storage.as_ref()
62    }
63
64    pub fn ranges(&self) -> RangeIter<'_> {
65        RangeIter::new(self.storage.as_ref(), PREFIX)
66    }
67
68    pub fn try_to_owned(&self) -> Result<Vec<Owned>, alloc::Error> {
69        let mut fields = Vec::new();
70        for field in self.iter() {
71            alloc::try_vacant(&mut fields)?(Owned::try_from(field)?);
72        }
73        Ok(fields)
74    }
75}
76
77impl<const PREFIX: usize> metadata::Metadata for Decoded<pool::Span, PREFIX> {
78    type Iter<'a> = Iter<'a>;
79
80    fn fields(&self) -> Self::Iter<'_> {
81        self.iter()
82    }
83}
84
85impl<const PREFIX: usize> storage::Block for Decoded<pool::Span, PREFIX> {
86    type Format = storage::Raw;
87    const PREFIX: &'static [u8] = &[0; PREFIX];
88
89    fn from(storage: storage::Finished<Self>) -> Self {
90        Self {
91            storage: storage.into_lease(),
92        }
93    }
94
95    fn into_bytes(self) -> storage::Bytes {
96        storage::Bytes::new(self.storage.freeze())
97    }
98}
99
100impl<S: AsRef<[u8]>, const PREFIX: usize> AsRef<[u8]> for Decoded<S, PREFIX> {
101    fn as_ref(&self) -> &[u8] {
102        self.storage.as_ref()
103    }
104}
105
106impl<const PREFIX: usize> PartialEq for Decoded<pool::Span, PREFIX> {
107    fn eq(&self, other: &Self) -> bool {
108        self.storage.as_ref() == other.storage.as_ref()
109    }
110}
111
112impl<const PREFIX: usize> Eq for Decoded<pool::Span, PREFIX> {}
113
114impl<'a, const PREFIX: usize> IntoIterator for &'a Decoded<pool::Span, PREFIX> {
115    type Item = Entry<'a>;
116    type IntoIter = Iter<'a>;
117
118    fn into_iter(self) -> Self::IntoIter {
119        self.iter()
120    }
121}
122
123const _: () = assert!(
124    mem::size_of::<Decoded>()
125        == mem::size_of::<pool::Span<owners::Plain<pool::Layout>, pool::Owned, pool::Frozen>>()
126);
127const _: () = assert!(mem::size_of::<Option<Decoded>>() == mem::size_of::<Decoded>());
128
129impl<const PREFIX: usize> storage::Scope for Decoded<pool::Span, PREFIX> {
130    type Scoped<'id> = Decoded<
131        scope::Owner<'id, pool::Span<owners::Plain<pool::Layout>, pool::Owned, pool::Frozen>>,
132        PREFIX,
133    >;
134
135    fn scope<T>(self, use_head: impl for<'id> FnOnce(Self::Scoped<'id>) -> T) -> T {
136        // Freeze before issuing an identity; a scoped or shared owner cannot
137        // recover the mutable lease through the unscoped consuming boundary.
138        scope::Owner::with(self.storage.freeze(), |storage| {
139            use_head(Decoded { storage })
140        })
141    }
142}
143
144impl<'id, const PREFIX: usize>
145    Decoded<
146        scope::Owner<'id, pool::Span<owners::Plain<pool::Layout>, pool::Owned, pool::Frozen>>,
147        PREFIX,
148    >
149{
150    pub fn view(&self) -> scope::View<'_, 'id> {
151        self.storage.view()
152    }
153}
154
155impl<'id, const PREFIX: usize>
156    From<
157        Decoded<
158            scope::Owner<'id, pool::Span<owners::Plain<pool::Layout>, pool::Owned, pool::Frozen>>,
159            PREFIX,
160        >,
161    > for scope::Owner<'id, Shared>
162{
163    fn from(
164        head: Decoded<
165            scope::Owner<'id, pool::Span<owners::Plain<pool::Layout>, pool::Owned, pool::Frozen>>,
166            PREFIX,
167        >,
168    ) -> Self {
169        head.storage.into_shared()
170    }
171}
172
173impl<const PREFIX: usize> storage::Writer<Decoded<pool::Span, PREFIX>> {
174    /// Commits a field after its producer supplies the name boundary.
175    pub fn try_write<E>(
176        &mut self,
177        write: impl FnOnce(&mut spans::Writer<'_, '_>) -> Result<usize, E>,
178    ) -> Result<(), E>
179    where
180        E: From<Error>,
181    {
182        self.try_write_as(crate::field::Indexing::Allowed, write)
183    }
184
185    pub fn try_write_as<E>(
186        &mut self,
187        indexing: crate::field::Indexing,
188        write: impl FnOnce(&mut spans::Writer<'_, '_>) -> Result<usize, E>,
189    ) -> Result<(), E>
190    where
191        E: From<Error>,
192    {
193        let mut output =
194            edit::Edit::try_new(self.lease.spare(), &[0; Prefix::LEN]).map_err(Error::Write)?;
195        let mut payload = output.bounded();
196        let name = write(&mut payload)?;
197        payload.commit();
198        let payload = output.len() - Prefix::LEN;
199        let value = payload
200            .checked_sub(name)
201            .ok_or(Error::Layout([0, name, payload]))?;
202        *output.prefix() = Prefix::try_new(name, value, indexing)?.to_bytes();
203        output.commit();
204        Ok(())
205    }
206}