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<owners::Plain<pool::Layout>, pool::Owned, pool::Frozen>> {
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 From<Decoded> for Shared {
29    fn from(value: Decoded) -> Self {
30        value.storage.into_shared()
31    }
32}
33
34impl<S: AsRef<[u8]>> Decoded<S> {
35    pub fn iter(&self) -> Iter<'_> {
36        Iter::new(self.storage.as_ref())
37    }
38
39    pub fn len(&self) -> usize {
40        self.iter().count()
41    }
42
43    pub fn is_empty(&self) -> bool {
44        self.storage.as_ref().is_empty()
45    }
46
47    pub fn get(&self, name: &[u8]) -> Option<&[u8]> {
48        self.iter()
49            .find(|field| field.name == name)
50            .map(|field| field.value)
51    }
52
53    pub fn as_bytes(&self) -> &[u8] {
54        self.storage.as_ref()
55    }
56
57    pub fn ranges(&self) -> RangeIter<'_> {
58        RangeIter::new(self.storage.as_ref())
59    }
60
61    pub fn try_to_owned(&self) -> Result<Vec<Owned>, alloc::Error> {
62        let mut fields = Vec::new();
63        for field in self.iter() {
64            let slot = alloc::Vacant::try_new(&mut fields)?;
65            slot.insert(Owned::try_from(field)?);
66        }
67        Ok(fields)
68    }
69}
70
71impl metadata::Metadata for Decoded {
72    type Iter<'a> = Iter<'a>;
73
74    fn fields(&self) -> Self::Iter<'_> {
75        Iter::new(self.storage.as_ref())
76    }
77}
78
79impl storage::Block for Decoded {
80    type Format = storage::Raw;
81
82    fn from(storage: storage::Finished<Self>) -> Self {
83        Self {
84            storage: storage.into_frozen(),
85        }
86    }
87
88    fn into_bytes(self) -> storage::Bytes {
89        storage::Bytes::new(self.storage)
90    }
91}
92
93impl<S: AsRef<[u8]>> AsRef<[u8]> for Decoded<S> {
94    fn as_ref(&self) -> &[u8] {
95        self.storage.as_ref()
96    }
97}
98
99impl PartialEq for Decoded {
100    fn eq(&self, other: &Self) -> bool {
101        self.storage.as_ref() == other.storage.as_ref()
102    }
103}
104
105impl Eq for Decoded {}
106
107impl<'a> IntoIterator for &'a Decoded {
108    type Item = Entry<'a>;
109    type IntoIter = Iter<'a>;
110
111    fn into_iter(self) -> Self::IntoIter {
112        self.iter()
113    }
114}
115
116const _: () = assert!(
117    mem::size_of::<Decoded>()
118        == mem::size_of::<pool::Span<owners::Plain<pool::Layout>, pool::Owned, pool::Frozen>>()
119);
120const _: () = assert!(mem::size_of::<Option<Decoded>>() == mem::size_of::<Decoded>());
121
122impl storage::Scope for Decoded {
123    type Scoped<'id> = Decoded<
124        scope::Owner<'id, pool::Span<owners::Plain<pool::Layout>, pool::Owned, pool::Frozen>>,
125    >;
126
127    fn scope<T>(self, use_head: impl for<'id> FnOnce(Self::Scoped<'id>) -> T) -> T {
128        scope::Owner::with(self.storage, |storage| use_head(Decoded { storage }))
129    }
130}
131
132impl<'id>
133    Decoded<scope::Owner<'id, pool::Span<owners::Plain<pool::Layout>, pool::Owned, pool::Frozen>>>
134{
135    pub fn view(&self) -> scope::View<'_, 'id> {
136        self.storage.view()
137    }
138}
139
140impl<'id>
141    From<
142        Decoded<
143            scope::Owner<'id, pool::Span<owners::Plain<pool::Layout>, pool::Owned, pool::Frozen>>,
144        >,
145    > for scope::Owner<'id, Shared>
146{
147    fn from(
148        head: Decoded<
149            scope::Owner<'id, pool::Span<owners::Plain<pool::Layout>, pool::Owned, pool::Frozen>>,
150        >,
151    ) -> Self {
152        head.storage.into_shared()
153    }
154}
155
156impl storage::Writer<Decoded> {
157    /// Commits a field after its producer supplies the name boundary.
158    pub fn try_write<E>(
159        &mut self,
160        write: impl FnOnce(&mut spans::Writer<'_, '_, false>) -> Result<usize, E>,
161    ) -> Result<(), E>
162    where
163        E: From<Error>,
164    {
165        self.try_write_as(crate::field::Indexing::Allowed, write)
166    }
167
168    pub fn try_write_as<E>(
169        &mut self,
170        indexing: crate::field::Indexing,
171        write: impl FnOnce(&mut spans::Writer<'_, '_, false>) -> Result<usize, E>,
172    ) -> Result<(), E>
173    where
174        E: From<Error>,
175    {
176        let mut output =
177            edit::Edit::try_new(self.lease.spare(), &[0; Prefix::LEN]).map_err(Error::Write)?;
178        let mut payload = output.bounded();
179        let name = write(&mut payload)?;
180        payload.commit();
181        let payload = output.len() - Prefix::LEN;
182        let value = payload
183            .checked_sub(name)
184            .ok_or(Error::Layout([0, name, payload]))?;
185        *output.prefix() = Prefix::try_new(name, value, indexing)?.to_bytes();
186        output.commit();
187        Ok(())
188    }
189}