Skip to main content

substrate_data/wire/binary/decode/
decoder.rs

1//! [`Decoder`]: reads the binary form — as a [`Value`] (`decoder_value`),
2//! borrowed as a [`ValueRef`] (`decoder_ref`), or step by step by a schema
3//! reading itself (`decoder_straight`). This file holds what they share: the
4//! header, the numbers, the string table.
5
6use super::shape::{Shapes, Walk};
7use crate::binary::{
8    DecodeError, LEGACY_VERSION, MAGIC, MAX_DEPTH, NEW_STRING, STR_INDEX_COUNT, STREAM_LEN_BYTES,
9    VERSION, read_varint, tag,
10};
11use crate::model::value::{KindName, Value};
12use crate::sync::Arc;
13
14/// Strings a decoder makes room for at once: a message's keys and values.
15pub(in crate::wire::binary) const STRINGS_START: usize = 16;
16
17/// Bytes of a float, and of a 32-bit one.
18pub(in crate::wire::binary) const F64_BYTES: usize = 8;
19pub(in crate::wire::binary) const F32_BYTES: usize = 4;
20
21/// Bytes a map entry takes at least: its key and its value's tag.
22pub(in crate::wire::binary) const MAP_ENTRY_MIN: usize = 2;
23
24/// Reads the binary form. The step-by-step reads ([`Decoder::int`],
25/// [`Decoder::map`] …) answer `None` for anything but what
26/// [`crate::Schema::encode`] writes there — the schema then reads the
27/// slow way, which says what's wrong.
28#[derive(Debug)]
29pub struct Decoder<'b> {
30    pub(in crate::wire::binary) b: &'b [u8],
31    pub(in crate::wire::binary) i: usize,
32    pub(in crate::wire::binary) strings: Vec<&'b str>,
33    /// Map keys made so far, by table index: each key is allocated once.
34    pub(in crate::wire::binary) keys: Vec<Option<Arc<str>>>,
35    /// Reference kinds checked so far, by table index of their string.
36    pub(in crate::wire::binary) kinds: Vec<Option<KindName>>,
37    pub(in crate::wire::binary) depth: usize,
38    /// Whether the tags of version 2 are accepted (a version 1 document is
39    /// read with only the tags it was written with).
40    pub(in crate::wire::binary) v2: bool,
41    /// The map shapes defined so far (version 2).
42    pub(in crate::wire::binary) shapes: Shapes,
43    /// The shaped maps being read step by step, innermost last.
44    pub(in crate::wire::binary) frames: Vec<Walk>,
45}
46
47impl<'b> Decoder<'b> {
48    /// After the header: the root value next. Versions 1 and 2 are read;
49    /// a version 1 document may use only the tags it was written with.
50    ///
51    /// # Errors
52    ///
53    /// [`DecodeError`] when the header isn't `SDAT` and a version this reads.
54    pub fn open(bytes: &'b [u8]) -> Result<Self, DecodeError> {
55        let mut d = Decoder::body(bytes);
56        d.v2 = false;
57        if !bytes.starts_with(MAGIC) {
58            return Err(d.error("not Substrate Data (no `SDAT` header)"));
59        }
60        d.i = MAGIC.len();
61        let version = d.byte()?;
62        match version {
63            VERSION => d.v2 = true,
64            LEGACY_VERSION => {}
65            _ => {
66                return Err(d.error(format!(
67                    "Substrate Data version {version}, this reads versions {LEGACY_VERSION} and {VERSION}"
68                )));
69            }
70        }
71        Ok(d)
72    }
73
74    /// A body with no header ([`crate::Stream`]'s, a frame's tagged value):
75    /// its strings and shapes its own, every tag of version 2 read.
76    pub(crate) fn body(bytes: &'b [u8]) -> Self {
77        Decoder {
78            b: bytes,
79            i: 0,
80            strings: Vec::with_capacity(STRINGS_START),
81            keys: Vec::new(),
82            kinds: Vec::new(),
83            depth: 0,
84            v2: true,
85            shapes: Shapes::default(),
86            frames: Vec::new(),
87        }
88    }
89
90    /// A body inside this one: the same version, its tables its own.
91    pub(in crate::wire::binary) fn inner(&self, bytes: &'b [u8]) -> Self {
92        let mut d = Decoder::body(bytes);
93        d.v2 = self.v2;
94        d.depth = self.depth;
95        d
96    }
97
98    /// A stream's body: its bytes, read past.
99    pub(in crate::wire::binary) fn stream_body(&mut self) -> Result<&'b [u8], DecodeError> {
100        let len = u32::from_le_bytes(self.fixed::<STREAM_LEN_BYTES>()?) as usize;
101        self.take(len)
102    }
103
104    /// A stream's values, decoded as a list.
105    pub(in crate::wire::binary) fn stream_values(&mut self) -> Result<Vec<Value>, DecodeError> {
106        let body = self.stream_body()?;
107        let mut d = self.inner(body);
108        let n = d.count(1)?;
109        let mut items = Vec::with_capacity(n);
110        for _ in 0..n {
111            items.push(d.value()?);
112        }
113        d.end()?;
114        Ok(items)
115    }
116
117    /// Whether every byte was read.
118    #[must_use]
119    pub fn at_end(&self) -> bool {
120        self.i == self.b.len()
121    }
122
123    pub(in crate::wire::binary) fn end(&self) -> Result<(), DecodeError> {
124        if self.at_end() {
125            Ok(())
126        } else {
127            Err(self.error("bytes after the value"))
128        }
129    }
130
131    pub(in crate::wire::binary) fn error(&self, message: impl Into<String>) -> DecodeError {
132        DecodeError {
133            message: message.into(),
134            offset: self.i,
135        }
136    }
137
138    pub(in crate::wire::binary) fn byte(&mut self) -> Result<u8, DecodeError> {
139        let b = *self
140            .b
141            .get(self.i)
142            .ok_or_else(|| self.error("unexpected end"))?;
143        self.i += 1;
144        Ok(b)
145    }
146
147    pub(in crate::wire::binary) fn varint(&mut self) -> Result<u64, DecodeError> {
148        read_varint(self.b, &mut self.i)
149            .ok_or_else(|| self.error("a varint cut short or longer than 64 bits"))
150    }
151
152    /// A length, checked against what's left: each of the `count` things takes at least `min` bytes.
153    pub(in crate::wire::binary) fn count(&mut self, min: usize) -> Result<usize, DecodeError> {
154        let n = self.varint()?;
155        let left = self.b.len() - self.i;
156        match usize::try_from(n) {
157            Ok(n) if n <= left / min.max(1) => Ok(n),
158            _ => Err(self.error(format!("length {n} past the end ({left} bytes left)"))),
159        }
160    }
161
162    pub(in crate::wire::binary) fn fixed<const N: usize>(
163        &mut self,
164    ) -> Result<[u8; N], DecodeError> {
165        let bytes = self
166            .b
167            .get(self.i..self.i + N)
168            .ok_or_else(|| self.error("unexpected end"))?;
169        self.i += N;
170        bytes.try_into().map_err(|_| self.error("unexpected end"))
171    }
172
173    /// `len` bytes.
174    pub(in crate::wire::binary) fn take(&mut self, len: usize) -> Result<&'b [u8], DecodeError> {
175        let end = self
176            .i
177            .checked_add(len)
178            .filter(|&e| e <= self.b.len())
179            .ok_or_else(|| self.error("bytes past the end"))?;
180        let out = &self.b[self.i..end];
181        self.i = end;
182        Ok(out)
183    }
184
185    /// A packed list of floats `N` bytes wide: each one's bytes, read in place (no alignment asked).
186    pub(in crate::wire::binary) fn packed_floats<const N: usize>(
187        &mut self,
188    ) -> Result<std::slice::Iter<'b, [u8; N]>, DecodeError> {
189        let n = self.count(N)?;
190        let bytes = self.take(n * N)?;
191        Ok(bytes.as_chunks::<N>().0.iter())
192    }
193
194    /// A length and that many bytes.
195    pub(in crate::wire::binary) fn length_bytes(&mut self) -> Result<&'b [u8], DecodeError> {
196        let len =
197            usize::try_from(self.varint()?).map_err(|_| self.error("a length beyond memory"))?;
198        self.take(len)
199    }
200
201    /// A string: new (read, and added to the table) or the table's.
202    pub(in crate::wire::binary) fn string(&mut self) -> Result<&'b str, DecodeError> {
203        let i = self.string_index()?;
204        Ok(self.strings[i])
205    }
206
207    /// The string a tag of its own names (`tag - STR_INDEX` in the table).
208    pub(in crate::wire::binary) fn indexed(&self, t: u8) -> Result<&'b str, DecodeError> {
209        let i = usize::from(t - tag::STR_INDEX);
210        self.strings
211            .get(i)
212            .copied()
213            .ok_or_else(|| self.error(format!("string {i} isn't in the table")))
214    }
215
216    /// Whether `t` is a tag that names a table string by itself.
217    pub(in crate::wire::binary) fn is_indexed(&self, t: u8) -> bool {
218        self.v2 && t.wrapping_sub(tag::STR_INDEX) < STR_INDEX_COUNT
219    }
220
221    /// Whether `t` is a tag that is an int by itself.
222    pub(in crate::wire::binary) fn is_inline_int(&self, t: u8) -> bool {
223        self.v2 && t >= tag::INT_INLINE
224    }
225
226    pub(in crate::wire::binary) fn string_index(&mut self) -> Result<usize, DecodeError> {
227        let v = self.varint()?;
228        if v & NEW_STRING == 0 {
229            let i = (v >> 1) as usize;
230            return if i < self.strings.len() {
231                Ok(i)
232            } else {
233                Err(self.error(format!("string {i} isn't in the table")))
234            };
235        }
236        let len = usize::try_from(v >> 1).map_err(|_| self.error("a length beyond memory"))?;
237        let at = self.i;
238        let s = crate::utf8::from_utf8(self.take(len)?).map_err(|_| DecodeError {
239            message: "a string isn't UTF-8".into(),
240            offset: at,
241        })?;
242        self.strings.push(s);
243        Ok(self.strings.len() - 1)
244    }
245
246    /// The key at table index `i`: shared with every other map that has it.
247    pub(in crate::wire::binary) fn shared_key_at(&mut self, i: usize) -> Arc<str> {
248        if self.keys.len() <= i {
249            self.keys.resize(i + 1, None);
250        }
251        self.keys[i]
252            .get_or_insert_with(|| self.strings[i].into())
253            .clone()
254    }
255
256    pub(in crate::wire::binary) fn deeper(&mut self) -> Result<(), DecodeError> {
257        self.depth += 1;
258        if self.depth > MAX_DEPTH {
259            return Err(self.error(format!("nested deeper than {MAX_DEPTH} levels")));
260        }
261        Ok(())
262    }
263}