aven_protocol/artifact/
codec.rs1use 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;
12const MAX_MANIFEST: usize = 8 + 32 + 8 + (8 + 8 + 32 + 24);
14pub 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
103pub 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}