Skip to main content

substrate_data/wire/binary/write/
writer.rs

1//! Writing the binary form: one buffer, strings written where first used.
2
3use super::shape_cache::ShapeCache;
4use crate::binary::{
5    INLINE_INT_MAX, INLINE_INT_MIN, MAGIC, NEW_STRING, STR_INDEX_COUNT, VERSION, tag, varint,
6    zigzag,
7};
8use crate::wire::binary::layout::{narrow, narrows};
9use crate::wire::binary::table::interner::Interner;
10use crate::wire::binary::table::shape_table::ShapeTable;
11
12/// What a writer reserves to start with: most messages fit.
13pub(crate) const START_BYTES: usize = 256;
14
15/// Writes the binary form piece by piece, from data that isn't a [`Value`](crate::Value)
16/// — nothing is built or copied on the way. A map or list is given its
17/// length, then that many entries (`key` then a value) or values.
18///
19/// ```
20/// let mut w = substrate_data::binary::Writer::new();
21/// w.map(2).key("id").str("docs/intro").key("count").int(3);
22/// let v = substrate_data::binary::decode(&w.finish()).unwrap();
23/// assert_eq!(v.get("count").and_then(|c| c.as_i64()), Some(3));
24/// ```
25#[derive(Debug)]
26pub struct Writer {
27    pub(in crate::wire::binary) out: Vec<u8>,
28    /// The strings written, by where they are in `out`.
29    pub(in crate::wire::binary) strings: Interner,
30    /// The map shapes written, by their keys.
31    pub(in crate::wire::binary) shapes: ShapeTable,
32    /// How shapes are found again quickly, and the buffers that takes.
33    pub(in crate::wire::binary) cache: ShapeCache,
34}
35
36impl Default for Writer {
37    fn default() -> Self {
38        Self::new()
39    }
40}
41
42impl Writer {
43    /// A writer of a whole document: the header first.
44    #[must_use]
45    pub fn new() -> Self {
46        let mut out = Vec::with_capacity(START_BYTES);
47        out.extend_from_slice(MAGIC);
48        out.push(VERSION);
49        Self::over(out)
50    }
51
52    /// A writer that writes after what `out` holds.
53    fn over(out: Vec<u8>) -> Self {
54        Writer {
55            out,
56            strings: Interner::new(),
57            shapes: ShapeTable::default(),
58            cache: ShapeCache::default(),
59        }
60    }
61
62    /// A writer that appends a whole document (header first) to `out`,
63    /// which it takes: [`Writer::finish`] gives it back.
64    pub(crate) fn appending(mut out: Vec<u8>) -> Self {
65        out.extend_from_slice(MAGIC);
66        out.push(VERSION);
67        Self::over(out)
68    }
69
70    /// Starts a new document after `prefix` zeroed bytes, keeping every
71    /// buffer it has grown: a message written without allocating.
72    pub(crate) fn restart(&mut self, prefix: usize) {
73        self.out.clear();
74        self.out.resize(prefix, 0);
75        self.out.extend_from_slice(MAGIC);
76        self.out.push(VERSION);
77        self.strings.clear();
78        self.shapes.clear();
79        self.cache.clear();
80    }
81
82    /// What is written so far, to patch or send.
83    pub(crate) fn buffer_mut(&mut self) -> &mut Vec<u8> {
84        &mut self.out
85    }
86
87    /// Null.
88    pub fn null(&mut self) -> &mut Self {
89        self.out.push(tag::NULL);
90        self
91    }
92
93    /// A bool.
94    pub fn bool(&mut self, b: bool) -> &mut Self {
95        self.out.push(if b { tag::TRUE } else { tag::FALSE });
96        self
97    }
98
99    /// An integer: one byte for -16 to 111, else a tag and a varint.
100    #[inline]
101    pub fn int(&mut self, n: i64) -> &mut Self {
102        let inline = u8::try_from(n.wrapping_sub(INLINE_INT_MIN))
103            .ok()
104            .filter(|&at| i64::from(at) <= INLINE_INT_MAX - INLINE_INT_MIN);
105        if let Some(at) = inline {
106            self.out.push(tag::INT_INLINE + at);
107            return self;
108        }
109        self.out.push(tag::INT);
110        varint(&mut self.out, zigzag(n));
111        self
112    }
113
114    /// A float: four bytes when it is an `f32` exactly (`layout::narrows`, what a
115    /// reader gives back bit for bit), else eight.
116    pub fn float(&mut self, f: f64) -> &mut Self {
117        if narrows(f) {
118            return self.float32(narrow(f));
119        }
120        self.out.push(tag::FLOAT);
121        self.out.extend_from_slice(&f.to_le_bytes());
122        self
123    }
124
125    /// A 32-bit float: half the bytes of [`Writer::float`].
126    pub fn float32(&mut self, f: f32) -> &mut Self {
127        self.out.push(tag::FLOAT32);
128        self.out.extend_from_slice(&f.to_le_bytes());
129        self
130    }
131
132    /// A string: its bytes the first time, its index after (in the tag
133    /// itself for the first 32 strings of the document).
134    pub fn str(&mut self, s: &str) -> &mut Self {
135        let found = self.strings.lookup(&self.out, s);
136        if let Ok(i) = found
137            && let Ok(at) = u8::try_from(i)
138            && at < STR_INDEX_COUNT
139        {
140            self.out.push(tag::STR_INDEX + at);
141            return self;
142        }
143        self.out.push(tag::STR);
144        self.put_string(s, found);
145        self
146    }
147
148    /// Bytes as they are.
149    pub fn bytes(&mut self, b: &[u8]) -> &mut Self {
150        self.out.push(tag::BYTES);
151        varint(&mut self.out, b.len() as u64);
152        self.out.extend_from_slice(b);
153        self
154    }
155
156    /// A list of `len` values.
157    pub fn list(&mut self, len: usize) -> &mut Self {
158        self.out.push(tag::LIST);
159        varint(&mut self.out, len as u64);
160        self
161    }
162
163    /// A stream ([`crate::Stream`]): `len` items, already written apart.
164    pub(crate) fn stream_body(&mut self, len: usize, items: &[u8]) -> &mut Self {
165        let mut count = Vec::new();
166        varint(&mut count, len as u64);
167        self.out.push(tag::STREAM);
168        let body = u32::try_from(count.len() + items.len()).unwrap_or(u32::MAX);
169        self.out.extend_from_slice(&body.to_le_bytes());
170        self.out.extend_from_slice(&count);
171        self.out.extend_from_slice(items);
172        self
173    }
174
175    /// A writer of a stream's body alone (no header).
176    pub(crate) fn body() -> Self {
177        Self::over(Vec::with_capacity(START_BYTES))
178    }
179
180    /// A map of `len` entries, each a [`Writer::key`] and a value: its
181    /// keys written one by one, and again in every map that has them.
182    /// [`Writer::record`] writes a map's keys once for all maps with them.
183    pub fn map(&mut self, len: usize) -> &mut Self {
184        self.out.push(tag::MAP);
185        varint(&mut self.out, len as u64);
186        self
187    }
188
189    /// A map's key.
190    pub fn key(&mut self, k: &str) -> &mut Self {
191        self.string(k);
192        self
193    }
194
195    /// The bytes.
196    #[must_use]
197    pub fn finish(self) -> Vec<u8> {
198        self.out
199    }
200
201    /// `s`: a reference if it was written before, else itself: its number in the table.
202    pub(in crate::wire::binary) fn string(&mut self, s: &str) -> usize {
203        let found = self.strings.find(&self.out, s);
204        self.put_string(s, found)
205    }
206
207    /// `s` as a string of the table, where [`Interner::find`] said `found`.
208    #[inline]
209    pub(in crate::wire::binary) fn put_string(
210        &mut self,
211        s: &str,
212        found: Result<usize, Option<u32>>,
213    ) -> usize {
214        match found {
215            Ok(i) => {
216                varint(&mut self.out, (i as u64) << 1);
217                i
218            }
219            Err(hash) => {
220                varint(&mut self.out, ((s.len() as u64) << 1) | NEW_STRING);
221                let at = self.out.len();
222                self.out.extend_from_slice(s.as_bytes());
223                self.strings.add(&self.out, s, at, hash)
224            }
225        }
226    }
227}