Skip to main content

substrate_data/wire/binary/write/
writer_record.rs

1//! [`Writer`] writing a map by its keys: a shape, written once and named
2//! after.
3
4use super::Writer;
5use super::static_shape::{STATIC_SHAPES, StaticShape};
6use crate::binary::{NEW_STRING, tag, varint};
7
8impl Writer {
9    /// A map of these `keys` (none repeated): the keys are written the
10    /// first time this set is met and named by number after that. A value
11    /// for each key follows, in order, with no [`Writer::key`].
12    pub fn record(&mut self, keys: &[&str]) -> &mut Self {
13        if keys.is_empty() {
14            return self.map(0);
15        }
16        self.out.push(tag::MAP_SHAPE);
17        self.shape(keys.iter().copied());
18        self
19    }
20
21    /// A map of the keys of `keys` that `present` has a bit for (bit `i`
22    /// for key `i`, at most 64 keys): what [`Writer::record`] is, for a
23    /// struct whose keys are always the same slice, found again by where it
24    /// is instead of by looking at its keys. A value for each key present
25    /// follows, in order.
26    pub fn record_masked(&mut self, keys: &'static [&'static str], present: u64) -> &mut Self {
27        if present == 0 {
28            return self.map(0);
29        }
30        self.out.push(tag::MAP_SHAPE);
31        let mixed = ((keys.as_ptr() as usize >> 4) as u64) ^ present;
32        let slot = usize::try_from(mixed % STATIC_SHAPES as u64).unwrap_or(0);
33        let known = self.cache.known[slot];
34        if known.shape != 0 && known.keys == keys.as_ptr() as usize && known.present == present {
35            varint(&mut self.out, u64::from(known.shape - 1) << 1);
36            return self;
37        }
38        let mut picked = std::mem::take(&mut self.cache.picked);
39        picked.clear();
40        picked.extend(
41            keys.iter()
42                .take(u64::BITS as usize)
43                .enumerate()
44                .filter(|&(i, _)| present >> i & 1 == 1)
45                .map(|(_, &key)| key),
46        );
47        let shape = self.shape(picked.iter().copied());
48        self.cache.picked = picked;
49        self.cache.known[slot] = StaticShape {
50            keys: keys.as_ptr() as usize,
51            present,
52            shape: u32::try_from(shape + 1).unwrap_or(0),
53        };
54        self
55    }
56
57    /// The shape of `keys`: written (a marker with their count, then them)
58    /// the first time, else its number. The shape's number.
59    pub(in crate::wire::binary) fn shape<'k>(
60        &mut self,
61        keys: impl ExactSizeIterator<Item = &'k str> + Clone,
62    ) -> usize {
63        let shape = match self.recent_shape(&keys) {
64            Some(shape) => {
65                varint(&mut self.out, (shape as u64) << 1);
66                shape
67            }
68            None => self.found_shape(keys),
69        };
70        self.cache.note(shape);
71        shape
72    }
73
74    /// The recent shape whose keys are `keys`, compared with their text:
75    /// found without looking any string up.
76    fn recent_shape<'k>(
77        &mut self,
78        keys: &(impl ExactSizeIterator<Item = &'k str> + Clone),
79    ) -> Option<usize> {
80        let (strings, shapes, out) = (&self.strings, &self.shapes, &self.out);
81        self.cache.find_recent(|shape| {
82            let numbers = shapes.keys_of(shape);
83            numbers.len() == keys.len()
84                && keys
85                    .clone()
86                    .zip(numbers)
87                    .all(|(key, &number)| strings.is(out, number, key))
88        })
89    }
90
91    /// The shape of `keys`, looked up by their strings: written when new.
92    #[inline(never)]
93    fn found_shape<'k>(&mut self, keys: impl ExactSizeIterator<Item = &'k str> + Clone) -> usize {
94        let n = keys.len();
95        let mut found = std::mem::take(&mut self.cache.found);
96        let mut numbers = std::mem::take(&mut self.cache.numbers);
97        found.clear();
98        numbers.clear();
99        for key in keys.clone() {
100            let at = self.strings.find(&self.out, key);
101            if let Ok(number) = at {
102                numbers.push(number);
103            }
104            found.push(at);
105        }
106        let known = if numbers.len() == n {
107            self.shapes.find(&numbers)
108        } else {
109            None
110        };
111        let shape = if let Some(shape) = known {
112            varint(&mut self.out, (shape as u64) << 1);
113            shape
114        } else {
115            varint(&mut self.out, ((n as u64) << 1) | NEW_STRING);
116            for (key, at) in keys.zip(found.iter().copied()) {
117                let string = self.put_string(key, at);
118                self.shapes.key(string);
119            }
120            self.shapes.seal()
121        };
122        self.cache.found = found;
123        self.cache.numbers = numbers;
124        shape
125    }
126}