Skip to main content

sark_http/field/metadata/block/
table.rs

1use crate::field::metadata::{block, map::record::Span};
2
3/// Immutable entries with admitted values and cached name classes.
4pub struct Table<'a, const N: usize> {
5    entries: [(&'a [u8], &'a [u8]); N],
6    names: [block::Name; N],
7}
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub struct Error {
11    pub index: usize,
12}
13
14/// One bounds-checked entry retaining its table and source bytes.
15#[derive(Clone, Copy)]
16pub struct Entry<'table, 'data> {
17    bytes: &'table (&'data [u8], &'data [u8]),
18    proof: block::Name,
19}
20
21impl<'a, const N: usize> Table<'a, N> {
22    pub const fn try_new(entries: [(&'a [u8], &'a [u8]); N]) -> Result<Self, Error> {
23        let mut names = [block::Name::REGULAR; N];
24        let mut index = 0;
25        while index < N {
26            let (name, value) = entries[index];
27            let mut scan = block::Value::new();
28            let mut offset = 0;
29            while offset < value.len() {
30                scan.push(value[offset]);
31                offset += 1;
32            }
33            if !scan.is_valid() {
34                return Err(Error { index });
35            }
36            names[index] = block::Name::classify(name);
37            index += 1;
38        }
39        Ok(Self { entries, names })
40    }
41
42    pub const fn len(&self) -> usize {
43        N
44    }
45
46    pub const fn is_empty(&self) -> bool {
47        N == 0
48    }
49
50    pub const fn entries(&self) -> &[(&'a [u8], &'a [u8]); N] {
51        &self.entries
52    }
53
54    pub fn get(&self, index: usize) -> Option<Entry<'_, 'a>> {
55        let bytes = self.entries.get(index)?;
56        Some(Entry {
57            bytes,
58            proof: self.names[index],
59        })
60    }
61}
62
63impl<'a> Entry<'_, 'a> {
64    pub const fn name(self) -> block::Named<'a> {
65        block::Named::from_scanned(Span::from_slice(self.bytes.0), self.proof)
66    }
67
68    pub const fn value(self) -> &'a [u8] {
69        self.bytes.1
70    }
71
72    pub const fn valued(self) -> block::Valued<'a> {
73        block::Valued::from_scanned(Span::from_slice(self.bytes.1), block::Validation::Valid)
74    }
75
76    pub const fn validation(self) -> block::Validation {
77        if self.proof.is_forbidden() {
78            block::Validation::Malformed
79        } else {
80            block::Validation::Valid
81        }
82    }
83}
84
85const _: () = assert!(core::mem::size_of::<Entry<'_, '_>>() == 2 * core::mem::size_of::<usize>());