Skip to main content

aven_protocol/artifact/
codec.rs

1use super::{Error, Result};
2
3pub const CHUNK: u64 = 1_048_576;
4pub const STATE_LIMIT: u64 = 256 * CHUNK;
5pub const CATALOG_LIMIT: u64 = 16 * CHUNK;
6pub const RECORD_LIMIT: u64 = 1_000_000;
7pub const IMAGE_LIMIT: u64 = 25 * CHUNK;
8pub const IMAGE_COUNT: u64 = 1024;
9pub const ID_LIMIT: u64 = 256;
10const MAX_SLICES: usize = (CATALOG_LIMIT / CHUNK) as usize;
11const MAX_DECLARATION: usize = 1 + 8 + 8 + 32 + 32 * MAX_SLICES;
12// The manifest is at most one chunk: total, aggregate, count, then one entry.
13const MAX_MANIFEST: usize = 8 + 32 + 8 + (8 + 8 + 32 + 24);
14/// Header, five IDs, prefix count, three declarations and the manifest recipe.
15pub const MAX_DESCRIPTOR_BYTES: usize = 7 + 5 * 32 + 8 + 3 * MAX_DECLARATION + MAX_MANIFEST;
16
17pub fn valid(ok: bool) -> Result<()> {
18    if ok { Ok(()) } else { Err(Error::Invalid) }
19}
20
21pub fn bound(value: u64, maximum: u64) -> Result<()> {
22    if value <= maximum {
23        Ok(())
24    } else {
25        Err(Error::ResourceLimit)
26    }
27}
28
29pub fn add(a: u64, b: u64) -> Result<u64> {
30    a.checked_add(b).ok_or(Error::Invalid)
31}
32
33pub fn size(value: u64) -> Result<usize> {
34    usize::try_from(value).map_err(|_| Error::ResourceLimit)
35}
36
37pub fn number(value: usize) -> Result<u64> {
38    u64::try_from(value).map_err(|_| Error::ResourceLimit)
39}
40
41pub fn count(total: u64) -> u64 {
42    (total / CHUNK + u64::from(!total.is_multiple_of(CHUNK))).max(1)
43}
44
45pub fn u64_bytes(out: &mut Vec<u8>, value: u64) {
46    out.extend_from_slice(&value.to_be_bytes());
47}
48
49pub fn bytes(out: &mut Vec<u8>, value: &[u8]) -> Result<()> {
50    u64_bytes(out, number(value.len())?);
51    out.extend_from_slice(value);
52    Ok(())
53}
54
55pub fn text(out: &mut Vec<u8>, value: &str) -> Result<()> {
56    valid(!value.is_empty())?;
57    bound(number(value.len())?, ID_LIMIT)?;
58    bytes(out, value.as_bytes())
59}
60
61pub struct Reader<'a>(pub &'a [u8]);
62
63impl<'a> Reader<'a> {
64    pub fn take(&mut self, n: usize) -> Result<&'a [u8]> {
65        valid(n <= self.0.len())?;
66        let (value, rest) = self.0.split_at(n);
67        self.0 = rest;
68        Ok(value)
69    }
70    pub fn array<const N: usize>(&mut self) -> Result<[u8; N]> {
71        self.take(N)?.try_into().map_err(|_| Error::Invalid)
72    }
73    pub fn byte(&mut self) -> Result<u8> {
74        Ok(self.array::<1>()?[0])
75    }
76    pub fn flag(&mut self) -> Result<bool> {
77        match self.byte()? {
78            0 => Ok(false),
79            1 => Ok(true),
80            _ => Err(Error::Invalid),
81        }
82    }
83    pub fn u64(&mut self) -> Result<u64> {
84        Ok(u64::from_be_bytes(self.array()?))
85    }
86    pub fn bytes(&mut self, maximum: u64) -> Result<&'a [u8]> {
87        let len = self.u64()?;
88        bound(len, maximum)?;
89        self.take(size(len)?)
90    }
91    pub fn text(&mut self) -> Result<String> {
92        let value = self.bytes(ID_LIMIT)?;
93        valid(!value.is_empty())?;
94        Ok(std::str::from_utf8(value)
95            .map_err(|_| Error::Invalid)?
96            .to_owned())
97    }
98    pub fn end(self) -> Result<()> {
99        valid(self.0.is_empty())
100    }
101}
102
103// Every sequential stream includes its class and count in its committed bytes.
104pub fn stream(class: u8, records: &[Vec<u8>]) -> Result<Vec<u8>> {
105    bound(number(records.len())?, RECORD_LIMIT)?;
106    let mut out = b"AVBC\0\x01".to_vec();
107    out.push(class);
108    u64_bytes(&mut out, number(records.len())?);
109    for record in records {
110        bound(
111            add(number(out.len())?, add(8, number(record.len())?)?)?,
112            CATALOG_LIMIT,
113        )?;
114        bytes(&mut out, record)?;
115    }
116    Ok(out)
117}
118
119pub fn read_stream(input: &[u8], class: u8) -> Result<Vec<&[u8]>> {
120    bound(number(input.len())?, CATALOG_LIMIT)?;
121    let mut r = Reader(input);
122    valid(r.take(6)? == b"AVBC\0\x01" && r.byte()? == class)?;
123    let n = r.u64()?;
124    bound(n, RECORD_LIMIT)?;
125    valid(n <= number(r.0.len())? / 8)?;
126    let mut out = Vec::new();
127    for _ in 0..n {
128        out.push(r.bytes(CATALOG_LIMIT)?);
129    }
130    r.end()?;
131    Ok(out)
132}