Skip to main content

substrate_data/wire/binary/write/
writer_value.rs

1//! [`Writer`] writing a whole [`Value`]: the form a value takes is chosen
2//! from the value alone, so every writer (this one, a port's) writes the
3//! same bytes for it — `docs/format.md`, "Binary", says how.
4
5use super::Writer;
6use crate::binary::{tag, varint};
7use crate::model::value::{Map, Value};
8use crate::wire::binary::layout::narrows;
9
10/// How a list of values is written.
11#[derive(Clone, Copy, PartialEq, Eq)]
12enum ListForm {
13    /// One tag per item.
14    Items,
15    /// Every item an int: packed.
16    Ints,
17    /// Every item a float: packed.
18    Floats,
19    /// Every item a map with the same keys: the keys once.
20    Records,
21}
22
23impl ListForm {
24    fn of(items: &[Value]) -> ListForm {
25        match items.split_first() {
26            Some((Value::Int(_), rest)) if rest.iter().all(|v| matches!(v, Value::Int(_))) => {
27                ListForm::Ints
28            }
29            Some((Value::Float(_), rest)) if rest.iter().all(|v| matches!(v, Value::Float(_))) => {
30                ListForm::Floats
31            }
32            Some((Value::Map(first), rest))
33                if !first.is_empty()
34                    && rest
35                        .iter()
36                        .all(|v| matches!(v, Value::Map(m) if m.keys().eq(first.keys()))) =>
37            {
38                ListForm::Records
39            }
40            _ => ListForm::Items,
41        }
42    }
43}
44
45impl Writer {
46    /// A whole value. A list of ints or of floats is packed, a list of
47    /// maps with one set of keys writes the keys once, a map's keys are a
48    /// shape, a small int takes a byte.
49    pub fn value(&mut self, v: &Value) -> &mut Self {
50        match v {
51            Value::Null => self.null(),
52            Value::Bool(b) => self.bool(*b),
53            Value::Int(n) => self.int(*n),
54            Value::Float(f) => self.float(*f),
55            Value::Str(s) => self.str(s),
56            Value::List(items) => self.list_value(items),
57            Value::Map(map) => self.map_value(map),
58            Value::Ref(r) => {
59                self.out.push(tag::REF);
60                self.string(r.kind.as_str());
61                self.string(r.id.as_str());
62                self
63            }
64            Value::Bytes(b) => self.bytes(b),
65        }
66    }
67
68    fn list_value(&mut self, items: &[Value]) -> &mut Self {
69        match ListForm::of(items) {
70            ListForm::Ints => self.ints(items.iter().map(|v| match v {
71                Value::Int(n) => *n,
72                _ => 0,
73            })),
74            ListForm::Floats => self.float_items(items),
75            ListForm::Records => self.records_value(items),
76            ListForm::Items => {
77                self.list(items.len());
78                for item in items {
79                    self.value(item);
80                }
81                self
82            }
83        }
84    }
85
86    /// A list of floats: four bytes each when every one is an `f32` exactly.
87    fn float_items(&mut self, items: &[Value]) -> &mut Self {
88        let float = |v: &Value| match v {
89            Value::Float(f) => *f,
90            _ => 0.0,
91        };
92        let narrow = items.iter().all(|v| narrows(float(v)));
93        self.out
94            .push(if narrow { tag::FLOATS32 } else { tag::FLOATS });
95        varint(&mut self.out, items.len() as u64);
96        for v in items {
97            let f = float(v);
98            if narrow {
99                #[expect(
100                    clippy::cast_possible_truncation,
101                    reason = "every item narrows exactly, checked above"
102                )]
103                self.out.extend_from_slice(&(f as f32).to_le_bytes());
104            } else {
105                self.out.extend_from_slice(&f.to_le_bytes());
106            }
107        }
108        self
109    }
110
111    /// A list of maps that all have the keys of the first: the keys once.
112    fn records_value(&mut self, items: &[Value]) -> &mut Self {
113        let Some(Value::Map(first)) = items.first() else {
114            return self.list(0);
115        };
116        self.out.push(tag::RECORDS);
117        varint(&mut self.out, items.len() as u64);
118        self.shape(first.keys());
119        for item in items {
120            if let Value::Map(map) = item {
121                self.values_of(map);
122            }
123        }
124        self
125    }
126
127    fn map_value(&mut self, map: &Map) -> &mut Self {
128        if map.is_empty() {
129            return self.map(0);
130        }
131        self.out.push(tag::MAP_SHAPE);
132        self.shape(map.keys());
133        self.values_of(map);
134        self
135    }
136
137    /// The values of `map`, in order, with no keys.
138    fn values_of(&mut self, map: &Map) {
139        for v in map.values() {
140            self.value(v);
141        }
142    }
143}