Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_jdat/src/bdat/core.rs

18.0 KiB, 17 runs

created by r1870400018:443, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use crate::{
2 prelude::*,
3 usr::UsrKindId,
4};
5
6use oxedyne_fe2o3_core::prelude::*;
7
8
9impl Dat {
10
11 /// Returns the length of the encoding in bytes, if it can be known without actually performing
12 /// the encoding.
13 ///
14 /// A kind that encloses others answers from its children, so a whole tree is measured without
15 /// a byte of it being built: a list is its code, the compact length of its payload, and the
16 /// payload. `None` travels upwards, since a container holding one child it cannot measure is
17 /// one it cannot measure either.
18 ///
19 /// Only [`Dat::Aint`] and [`Dat::Adec`] answer `None` on their own account. An
20 /// arbitrary-precision number is written under a length taken from the digits it serialises
21 /// to, so measuring one is encoding one, and this promises not to.
22 pub fn byte_len(&self) -> Option<usize> {
23 match self {
24 // Atomic Kinds ===========================
25 // Logic
26 Self::Empty |
27 Self::Bool(_) => Some(1),
28 // Fixed
29 Self::U8(_) |
30 Self::I8(_) => Some(2),
31 Self::U16(_) |
32 Self::I16(_) => Some(3),
33 Self::U32(_) |
34 Self::I32(_) |
35 Self::F32(_) => Some(5),
36 Self::U64(_) |
37 Self::I64(_) |
38 Self::F64(_) => Some(9),
39 Self::U128(_) |
40 Self::I128(_) => Some(17),
41 // Variable
42 Self::Aint(_) |
43 Self::Adec(_) => None,
44 Self::C64(v) => Some(Self::c64_len(*v as usize)),
45 Self::Str(s) => {
46 let len = s.as_bytes().len();
47 Some(1 + Self::c64_len(len) + len)
48 },
49 // Molecule Kinds =========================
50 // Unitary
51 Self::Usr(_ukid, optboxd) => {
52 const CODE_LEN: usize = UsrKindId::CODE_BYTE_LEN;
53 match optboxd {
54 None => Some(2 + CODE_LEN),
55 Some(boxd) => match boxd.byte_len() {
56 None => None,
57 Some(len) => Some(2 + CODE_LEN + len),
58 },
59 }
60 },
61 Self::Box(boxd) => {
62 match boxd.byte_len() {
63 None => None,
64 Some(len) => Some(1 + len),
65 }
66 },
67 Self::Opt(boxoptd) => {
68 match &**boxoptd {
69 None => Some(1),
70 Some(d) => match d.byte_len() {
71 None => None,
72 Some(len) => Some(1 + len),
73 }
74 }
75 },
76 Self::ABox(_, boxd, s) => {
77 match boxd.byte_len() {
78 None => None,
79 Some(boxd_len) => {
80 let s_len = s.as_bytes().len();
81 Some(1 + boxd_len + Self::c64_len(s_len) + s_len)
82 }
83 }
84 },
85 // Heterogenous
86 Self::List(v) => Self::run_framed(v.iter()),
87 Self::Tup2(a) => Self::run_tagged(a.iter()),
88 Self::Tup3(a) => Self::run_tagged(a.iter()),
89 Self::Tup4(a) => Self::run_tagged(a.iter()),
90 Self::Tup5(a) => Self::run_tagged(a.iter()),
91 Self::Tup6(a) => Self::run_tagged(a.iter()),
92 Self::Tup7(a) => Self::run_tagged(a.iter()),
93 Self::Tup8(a) => Self::run_tagged(a.iter()),
94 Self::Tup9(a) => Self::run_tagged(a.iter()),
95 Self::Tup10(a) => Self::run_tagged(a.iter()),
96 Self::Map(map) => Self::run_framed(map.iter().flat_map(|(k, v)| [k, v])),
97 // An ordered map's key is written as its daticle alone; the ordinal beside it
98 // orders the entries and never leaves memory.
99 Self::OrdMap(m) => Self::run_framed(m.iter().flat_map(|(k, v)| [k.dat(), v])),
100 // Homogenous
101 Self::Vek(vek) => Self::run_framed(vek.iter()),
102 // Variable length bytes
103 Self::BU8(v) => Some(1 + 1 + v.len()),
104 Self::BU16(v) => Some(1 + 2 + v.len()),
105 Self::BU32(v) => Some(1 + 4 + v.len()),
106 Self::BU64(v) => Some(1 + 8 + v.len()),
107 Self::BC64(v) => {
108 let len = v.len();
109 Some(1 + Self::c64_len(len) + len)
110 },
111 // Fixed length bytes
112 Self::B2(_) => Some(3),
113 Self::B3(_) => Some(4),
114 Self::B4(_) => Some(5),
115 Self::B5(_) => Some(6),
116 Self::B6(_) => Some(7),
117 Self::B7(_) => Some(8),
118 Self::B8(_) => Some(9),
119 Self::B9(_) => Some(10),
120 Self::B10(_) => Some(11),
121 Self::B16(_) => Some(17),
122 Self::B32(_) => Some(33),
123 // Fixed length numbers
124 Self::Tup2u16(_) => Some(1 + 2 * 2),
125 Self::Tup3u16(_) => Some(1 + 3 * 2),
126 Self::Tup4u16(_) => Some(1 + 4 * 2),
127 Self::Tup5u16(_) => Some(1 + 5 * 2),
128 Self::Tup6u16(_) => Some(1 + 6 * 2),
129 Self::Tup7u16(_) => Some(1 + 7 * 2),
130 Self::Tup8u16(_) => Some(1 + 8 * 2),
131 Self::Tup9u16(_) => Some(1 + 9 * 2),
132 Self::Tup10u16(_) => Some(1 + 10 * 2),
133
134 Self::Tup2u32(_) => Some(1 + 2 * 4),
135 Self::Tup3u32(_) => Some(1 + 3 * 4),
136 Self::Tup4u32(_) => Some(1 + 4 * 4),
137 Self::Tup5u32(_) => Some(1 + 5 * 4),
138 Self::Tup6u32(_) => Some(1 + 6 * 4),
139 Self::Tup7u32(_) => Some(1 + 7 * 4),
140 Self::Tup8u32(_) => Some(1 + 8 * 4),
141 Self::Tup9u32(_) => Some(1 + 9 * 4),
142 Self::Tup10u32(_) => Some(1 + 10 * 4),
143
144 Self::Tup2u64(_) => Some(1 + 2 * 8),
145 Self::Tup3u64(_) => Some(1 + 3 * 8),
146 Self::Tup4u64(_) => Some(1 + 4 * 8),
147 Self::Tup5u64(_) => Some(1 + 5 * 8),
148 Self::Tup6u64(_) => Some(1 + 6 * 8),
149 Self::Tup7u64(_) => Some(1 + 7 * 8),
150 Self::Tup8u64(_) => Some(1 + 8 * 8),
151 Self::Tup9u64(_) => Some(1 + 9 * 8),
152 Self::Tup10u64(_) => Some(1 + 10 * 8),
153
154 Self::Tup2u8(_) => Some(1 + 2 * 1),
155 Self::Tup3u8(_) => Some(1 + 3 * 1),
156 Self::Tup4u8(_) => Some(1 + 4 * 1),
157 Self::Tup5u8(_) => Some(1 + 5 * 1),
158 Self::Tup6u8(_) => Some(1 + 6 * 1),
159 Self::Tup7u8(_) => Some(1 + 7 * 1),
160 Self::Tup8u8(_) => Some(1 + 8 * 1),
161 Self::Tup9u8(_) => Some(1 + 9 * 1),
162 Self::Tup10u8(_) => Some(1 + 10 * 1),
163
164 Self::Tup2i8(_) => Some(1 + 2 * 1),
165 Self::Tup3i8(_) => Some(1 + 3 * 1),
166 Self::Tup4i8(_) => Some(1 + 4 * 1),
167 Self::Tup5i8(_) => Some(1 + 5 * 1),
168 Self::Tup6i8(_) => Some(1 + 6 * 1),
169 Self::Tup7i8(_) => Some(1 + 7 * 1),
170 Self::Tup8i8(_) => Some(1 + 8 * 1),
171 Self::Tup9i8(_) => Some(1 + 9 * 1),
172 Self::Tup10i8(_) => Some(1 + 10 * 1),
173
174 Self::Tup2i16(_) => Some(1 + 2 * 2),
175 Self::Tup3i16(_) => Some(1 + 3 * 2),
176 Self::Tup4i16(_) => Some(1 + 4 * 2),
177 Self::Tup5i16(_) => Some(1 + 5 * 2),
178 Self::Tup6i16(_) => Some(1 + 6 * 2),
179 Self::Tup7i16(_) => Some(1 + 7 * 2),
180 Self::Tup8i16(_) => Some(1 + 8 * 2),
181 Self::Tup9i16(_) => Some(1 + 9 * 2),
182 Self::Tup10i16(_) => Some(1 + 10 * 2),
183
184 Self::Tup2i32(_) => Some(1 + 2 * 4),
185 Self::Tup3i32(_) => Some(1 + 3 * 4),
186 Self::Tup4i32(_) => Some(1 + 4 * 4),
187 Self::Tup5i32(_) => Some(1 + 5 * 4),
188 Self::Tup6i32(_) => Some(1 + 6 * 4),
189 Self::Tup7i32(_) => Some(1 + 7 * 4),
190 Self::Tup8i32(_) => Some(1 + 8 * 4),
191 Self::Tup9i32(_) => Some(1 + 9 * 4),
192 Self::Tup10i32(_) => Some(1 + 10 * 4),
193
194 Self::Tup2i64(_) => Some(1 + 2 * 8),
195 Self::Tup3i64(_) => Some(1 + 3 * 8),
196 Self::Tup4i64(_) => Some(1 + 4 * 8),
197 Self::Tup5i64(_) => Some(1 + 5 * 8),
198 Self::Tup6i64(_) => Some(1 + 6 * 8),
199 Self::Tup7i64(_) => Some(1 + 7 * 8),
200 Self::Tup8i64(_) => Some(1 + 8 * 8),
201 Self::Tup9i64(_) => Some(1 + 9 * 8),
202 Self::Tup10i64(_) => Some(1 + 10 * 8),
203
204 //// Scheduled for removal
205 //Self::PartKey(_) => Some(41),
206 }
207
208 }
209
210 /// The bytes a run of daticles comes to, in order and with nothing between them.
211 fn run_len<'a, I: Iterator<Item = &'a Dat>>(items: I) -> Option<usize> {
212 let mut sum = 0usize;
213 for item in items {
214 match item.byte_len() {
215 Some(len) => sum += len,
216 None => return None,
217 }
218 }
219 Some(sum)
220 }
221
222 /// A run under a code byte and a compact length, which is how a list, a vek and a map are all
223 /// written. A map's run is its keys and values alternating, and the sum does not depend on
224 /// which order the pairs come out in.
225 fn run_framed<'a, I: Iterator<Item = &'a Dat>>(items: I) -> Option<usize> {
226 match Self::run_len(items) {
227 Some(len) => Some(1 + Self::c64_len(len) + len),
228 None => None,
229 }
230 }
231
232 /// A run under a code byte alone. A tuple carries its length in its code, so nothing measures
233 /// the payload on the wire and nothing needs to here.
234 fn run_tagged<'a, I: Iterator<Item = &'a Dat>>(items: I) -> Option<usize> {
235 match Self::run_len(items) {
236 Some(len) => Some(1 + len),
237 None => None,
238 }
239 }
240
241 pub fn c64_len(num: usize) -> usize {
242 // Compare in `u64`: the upper literals exceed a 32-bit `usize` (e.g. on
243 // `wasm32`); widening `num` is lossless and keeps the ladder correct on
244 // both 32- and 64-bit targets.
245 let num = num as u64;
246 if num == 0 {
247 1
248 } else if num <= 0xff {
249 2
250 } else if num <= 0xffff {
251 3
252 } else if num <= 0xffffff {
253 4
254 } else if num <= 0xffffffff {
255 5
256 } else if num <= 0xffffffffff {
257 6
258 } else if num <= 0xffffffffffff {
259 7
260 } else {
261 8
262 }
263 }
264
265}
266
267#[cfg(test)]
268mod tests {
269 use super::*;
270
271 use crate::prelude::*;
272
273 use oxedyne_fe2o3_num::BigInt;
274
275 /// Every kind here is one the encoder writes as a code and a run of children, which is what
276 /// `byte_len` had to be taught and what it could get subtly wrong.
277 fn containers() -> Vec<(&'static str, Dat)> {
278 let atoms = vec![
279 Dat::Empty,
280 Dat::U8(7),
281 Dat::U64(1 << 40),
282 Dat::Str("a string".to_string()),
283 Dat::BU64(vec![9u8; 300]),
284 Dat::Opt(Box::new(Some(Dat::I32(-5)))),
285 Dat::Opt(Box::new(None)),
286 ];
287 let mut map = DaticleMap::new();
288 map.insert(Dat::Str("k".to_string()), Dat::List(atoms.clone()));
289 map.insert(Dat::U8(1), Dat::Empty);
290 let mut ordmap = OrdDaticleMap::new();
291 ordmap.insert(MapKey::new(0, Dat::Str("first".to_string())), Dat::BU8(vec![1, 2, 3]));
292 ordmap.insert(MapKey::new(1, Dat::U16(9)), Dat::List(vec![Dat::Empty]));
293 vec![
294 ("an empty list", Dat::List(Vec::new())),
295 ("a list of atoms", Dat::List(atoms.clone())),
296 ("a nested list", Dat::List(vec![Dat::List(atoms.clone()), Dat::List(vec![
297 Dat::List(atoms.clone()),
298 ])])),
299 ("an empty vek", Dat::Vek(Vek(Vec::new()))),
300 ("a vek", Dat::Vek(Vek(atoms.clone()))),
301 ("a tup2", Dat::Tup2(Box::new([Dat::Empty, Dat::List(atoms.clone())]))),
302 ("a tup3", Dat::Tup3(Box::new([Dat::U8(1), Dat::U8(2), Dat::U8(3)]))),
303 ("a tup4", Dat::Tup4(Box::new([
304 Dat::Empty, Dat::Empty, Dat::Empty,
305 Dat::List(atoms.clone()),
306 ]))),
307 ("a tup5", Dat::Tup5(Box::new([
308 Dat::U8(1), Dat::U8(2), Dat::U8(3), Dat::U8(4),
309 Dat::List(atoms.clone()),
310 ]))),
311 ("a tup6", Dat::Tup6(Box::new([
312 Dat::U8(1), Dat::U8(2), Dat::U8(3), Dat::U8(4),
313 Dat::U8(5), Dat::List(atoms.clone()),
314 ]))),
315 ("a tup7", Dat::Tup7(Box::new([
316 Dat::U8(1), Dat::U8(2), Dat::U8(3), Dat::U8(4),
317 Dat::U8(5), Dat::U8(6), Dat::List(atoms.clone()),
318 ]))),
319 ("a tup8", Dat::Tup8(Box::new([
320 Dat::U8(1), Dat::U8(2), Dat::U8(3), Dat::U8(4),
321 Dat::U8(5), Dat::U8(6), Dat::U8(7),
322 Dat::List(atoms.clone()),
323 ]))),
324 ("a tup9", Dat::Tup9(Box::new([
325 Dat::U8(1), Dat::U8(2), Dat::U8(3), Dat::U8(4),
326 Dat::U8(5), Dat::U8(6), Dat::U8(7), Dat::U8(8),
327 Dat::List(atoms.clone()),
328 ]))),
329 ("a tup10", Dat::Tup10(Box::new([
330 Dat::U8(1), Dat::U8(2), Dat::U8(3), Dat::U8(4),
331 Dat::U8(5), Dat::U8(6), Dat::U8(7), Dat::U8(8),
332 Dat::U8(9), Dat::List(atoms.clone()),
333 ]))),
334 ("an empty map", Dat::Map(DaticleMap::new())),
335 ("a map", Dat::Map(map.clone())),
336 ("an empty ordmap", Dat::OrdMap(OrdDaticleMap::new())),
337 ("an ordmap", Dat::OrdMap(ordmap.clone())),
338 ("a map inside a list", Dat::List(vec![Dat::Map(map), Dat::OrdMap(ordmap)])),
339 ]
340 }
341
342 /// Proved red by returning `None` from every container arm, which is where this started, and
343 /// again by dropping the compact length from `run_framed`.
344 #[test]
345 fn test_byte_len_is_what_the_encoder_writes() -> Outcome<()> {
346 for (name, dat) in containers() {
347 let bytes = res!(dat.to_bytes(Vec::new()));
348 match dat.byte_len() {
349 Some(len) => assert_eq!(len, bytes.len(),
350 "{} is measured at {} bytes and encodes to {}", name, len, bytes.len()),
351 None => return Err(err!(
352 "{} could not be measured at all, so a caller sizing a reply by it has \
353 to encode it to find out.", name;
354 Test, Invalid)),
355 }
356 }
357 Ok(())
358 }
359
360 /// The payload's length is itself written under a compact length that widens with it, so a
361 /// measurement that assumed one width would be right until it was not.
362 ///
363 /// Proved red by fixing `run_framed` at two bytes of length prefix.
364 #[test]
365 fn test_byte_len_widens_with_the_compact_length() -> Outcome<()> {
366 let mut widths = std::collections::BTreeSet::new();
367 for payload in [0usize, 1, 253, 254, 255, 256, 257, 65_534, 65_535, 65_536, 65_537] {
368 let child = Dat::BC64(vec![3u8; payload]);
369 let inner = match child.byte_len() {
370 Some(len) => len,
371 None => return Err(err!(
372 "A byte payload of {} could not be measured.", payload; Test, Invalid)),
373 };
374 let dat = Dat::List(vec![child]);
375 let bytes = res!(dat.to_bytes(Vec::new()));
376 let len = match dat.byte_len() {
377 Some(len) => len,
378 None => return Err(err!(
379 "A list holding {} bytes could not be measured.", payload;
380 Test, Invalid)),
381 };
382 assert_eq!(len, bytes.len(),
383 "a list holding {} bytes is measured at {} and encodes to {}",
384 payload, len, bytes.len());
385 widths.insert(Dat::c64_len(inner));
386 }
387 assert!(widths.len() >= 3,
388 "every case took the same {:?} byte length prefix, so the widening is untested",
389 widths);
390 Ok(())
391 }
392
393 /// A container answers `None` rather than a number that leaves out what it could not measure.
394 ///
395 /// Proved red by having `run_len` skip an unmeasurable child instead of giving up on the run.
396 #[test]
397 fn test_byte_len_declines_what_it_cannot_measure() -> Outcome<()> {
398 let unknown = Dat::Aint(BigInt::from(1u8));
399 assert_eq!(unknown.byte_len(), None, "an arbitrary-precision integer was measured");
400 let mut map = DaticleMap::new();
401 map.insert(Dat::U8(1), unknown.clone());
402 let mut ordmap = OrdDaticleMap::new();
403 ordmap.insert(MapKey::new(0, Dat::U8(1)), unknown.clone());
404 for (name, dat) in [
405 ("a list", Dat::List(vec![Dat::Empty, unknown.clone()])),
406 ("a list of lists", Dat::List(vec![Dat::List(vec![unknown.clone()])])),
407 ("a vek", Dat::Vek(Vek(vec![unknown.clone()]))),
408 ("a tuple", Dat::Tup2(Box::new([Dat::Empty, unknown.clone()]))),
409 ("a map", Dat::Map(map)),
410 ("an ordered map", Dat::OrdMap(ordmap)),
411 ] {
412 assert_eq!(dat.byte_len(), None,
413 "{} holding a number nothing can measure answered with a length", name);
414 }
415 Ok(())
416 }
417}