substrate_data/wire/binary/write/
writer_value.rs1use super::Writer;
6use crate::binary::{tag, varint};
7use crate::model::value::{Map, Value};
8use crate::wire::binary::layout::narrows;
9
10#[derive(Clone, Copy, PartialEq, Eq)]
12enum ListForm {
13 Items,
15 Ints,
17 Floats,
19 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 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 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 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 fn values_of(&mut self, map: &Map) {
139 for v in map.values() {
140 self.value(v);
141 }
142 }
143}