substrate_data/wire/binary/write/
writer_record.rs1use super::Writer;
5use super::static_shape::{STATIC_SHAPES, StaticShape};
6use crate::binary::{NEW_STRING, tag, varint};
7
8impl Writer {
9 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 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 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 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 #[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}