src/Manifest.bend

mylsm-lsm-store@0.5.0.0 · 715 lines · 0 definitions

1import Base
2import mylsm-lsm-store@0.5.0.0/src/StorageBytes.bend as StorageBytes
3import bend-kit-bytes@0.3.2.0/bytes.bend as Bytes
4import mylsm-lsm-store@0.5.0.0/src/hub_sha/sha256.bend as SHA
5
6# Represent Manifest data used by the binary manifest codec.
7type Manifest is Data:
8  M{levels: List<&2, List<&2, String>>}
9
10# Represent Error data used by the binary manifest codec.
11type Error is Data:
12  TooLarge{}
13  InvalidName{}
14
15# Represents parseresult data in manifest.
16type ParseResult is Data:
17  Parsed{manifest: Manifest}
18  UnsupportedVersion{version: U32}
19  Malformed{}
20  ParseLimitExceeded{}
21
22# Represent ParseState data used by the binary manifest codec.
23type ParseState is Data:
24  ReadNamesCount{levels_left: Nat, levels_acc: List<&2, List<&2, String>>}
25  ReadNameLength{levels_left: Nat, levels_acc: List<&2, List<&2, String>>, names_left: Nat, names_acc: List<&2, String>}
26  ReadNameBody{levels_left: Nat, levels_acc: List<&2, List<&2, String>>, names_left: Nat, names_acc: List<&2, String>}
27
28# Represent ParseInput data used by the binary manifest codec.
29type ParseInput is Type:
30  NoInput{cursor: Bytes.Cursor}
31  NameInput{value: Bytes.Cursor & Maybe<&2, String>}
32
33# Represent ParseTransition data used by the binary manifest codec.
34type ParseTransition is Type:
35  Continue{state: ParseState, input: ParseInput}
36  Reject{cursor: Bytes.Cursor}
37  Finish{cursor: Bytes.Cursor, levels: List<&2, List<&2, String>>}
38
39def magic.result(result: Maybe<&1, Bytes.Bytes>) -> Bytes.Bytes:
40  match result:
41    case Some{bytes}:
42      bytes
43    case None{}:
44      Bytes.new(0)
45
46# Handle magic in the binary manifest codec.
47def magic() -> Bytes.Bytes:
48  magic.result(Bytes.from_hex("4d594c534d334d00"))
49
50# Handle u32 in the binary manifest codec.
51def u32(+value: U32) -> Bytes.Bytes:
52  Bytes.set.u32be(Bytes.new(4), 0, value)
53
54def bytes.clone.pair(+len: U32, copied: Array<U32> & Array<U32>) -> Bytes.Bytes & Bytes.Bytes:
55  match copied:
56    case (left, right):
57      (Bytes.Bytes{len, left}, Bytes.Bytes{len, right})
58
59def bytes.clone.split(bytes: Bytes.Bytes) -> Bytes.Bytes & Bytes.Bytes:
60  match bytes:
61    case Bytes.Bytes{+len, buf}:
62      bytes.clone.pair(len, Bytes.copy.bytes(len, buf, Bytes.alloc(len), 0, 0))
63
64def bytes.clone.first(pair: Bytes.Bytes & Bytes.Bytes) -> Bytes.Bytes:
65  match pair:
66    case (left, _):
67      left
68
69def bytes.length(pair: Bytes.Bytes & U32) -> U32:
70  match pair:
71    case (_, len):
72      len
73
74def bytes.slice.second(pair: Bytes.Bytes & Bytes.Bytes) -> Bytes.Bytes:
75  match pair:
76    case (_, second):
77      second
78
79def encode.name.copies(+len: U32, tail: Bytes.Bytes, copies: Array<U32> & Array<U32>) -> Bytes.Bytes:
80  match copies:
81    case (stored, _unused):
82      Bytes.concat([u32(len), Bytes.Bytes{len, stored}, tail])
83
84def encode.name.buffer(+len: U32, tail: Bytes.Bytes, packed: Bytes.Bytes) -> Bytes.Bytes:
85  match packed:
86    case Bytes.Bytes{_, buf}:
87      encode.name.copies(len, tail, Bytes.copy.bytes(len, buf, Bytes.alloc(len), 0, 0))
88
89def encode.name.copy(pair: Bytes.Bytes & U32, tail: Bytes.Bytes) -> Bytes.Bytes:
90  match pair:
91    case (packed, +len):
92      encode.name.buffer(len, tail, packed)
93
94def encode.name.prefix(result: Result<&1, &1, U32 & String, Bytes.Bytes>, tail: Bytes.Bytes) -> Bytes.Bytes:
95  match result:
96    case Fail{_}:
97      Bytes.concat([u32(0), Bytes.new(0), tail])
98    case Done{encoded}:
99      encode.name.copy(Bytes.length(encoded), tail)
100
101def name.char.valid(+char: Char) -> Bool:
102  +byte = Char.to_u32(char)
103  U32.is_le(48, byte) && U32.is_le(byte, 57) ||
104    U32.is_le(65, byte) && U32.is_le(byte, 90) ||
105    U32.is_le(97, byte) && U32.is_le(byte, 122) ||
106    U32.is_eq(byte, 45) || U32.is_eq(byte, 95) || U32.is_eq(byte, 46) || U32.is_lt(127, byte)
107
108def name.text.valid.chars(text: String, valid: Bool) -> Bool:
109  match text:
110    case SNil{}:
111      valid
112    case SCon{+char, rest}:
113      name.text.valid.chars(rest, valid && name.char.valid(char))
114
115def name.text.valid.edge(text: String, dot_component: Bool) -> Bool:
116  match dot_component:
117    case True{}:
118      False{}
119    case False{}:
120      name.text.valid.chars(text, True{})
121
122def name.text.valid(+text: String) -> Bool:
123  match text:
124    case SNil{}:
125      False{}
126    case SCon{_, _}:
127      name.text.valid.edge(text, String.eq(text, ".") || String.eq(text, ".."))
128
129def names.valid.step(rest: List<&2, String>, valid: Bool) -> Bool:
130  match rest valid:
131    case _ False{}:
132      False{}
133    case Nil{} True{}:
134      True{}
135    case Con{name, tail} True{}:
136      names.valid.step(tail, name.text.valid(name))
137
138def names.valid(names: List<&2, String>) -> Bool:
139  names.valid.step(names, True{})
140
141def levels.valid.step(rest: List<&2, List<&2, String>>, valid: Bool) -> Bool:
142  match rest valid:
143    case _ False{}:
144      False{}
145    case Nil{} True{}:
146      True{}
147    case Con{+names, tail} True{}:
148      levels.valid.step(tail, names.valid(names))
149
150def levels.valid(levels: List<&2, List<&2, String>>) -> Bool:
151  levels.valid.step(levels, True{})
152
153def encode.names(names: List<&2, String>) -> Bytes.Bytes:
154  match names:
155    case Nil{}:
156      Bytes.new(0)
157    case Con{name, rest}:
158      encode.name.prefix(StorageBytes.from_string(name), encode.names(rest))
159
160def encode.levels(levels: List<&2, List<&2, String>>) -> Bytes.Bytes:
161  match levels:
162    case Nil{}:
163      Bytes.new(0)
164    case Con{+names, rest}:
165      Bytes.concat([u32(U32.from_nat(List.length(&2, String, names))), encode.names(names), encode.levels(rest)])
166
167def encode.body(+manifest: Manifest) -> Bytes.Bytes:
168  match manifest:
169    case M{levels}:
170      Bytes.concat([magic(), u32(3), u32(U32.from_nat(List.length(&2, List<&2, String>, levels))), encode.levels(levels)])
171
172def encode.digest.checked(pair: Bytes.Bytes & Bytes.Bytes) -> Result<&1, &1, Error, Bytes.Bytes>:
173  match pair:
174    case (packed, size_packed):
175      Bool.pick(Result<&1, &1, Error, Bytes.Bytes>,
176        U32.is_le(bytes.length(Bytes.length(size_packed)), StorageBytes.MAX_MANIFEST_BYTES()),
177        Done{packed}, Fail{TooLarge{}})
178
179def encode.body.digest(pair: Bytes.Bytes & Bytes.Bytes) -> Result<&1, &1, Error, Bytes.Bytes>:
180      match pair:
181        case (body, hash_body):
182          encode.digest.checked(bytes.clone.split(Bytes.concat([body, SHA.sha256_packed_bytes(hash_body)])))
183
184def encode.body.checked(manifest: Manifest) -> Result<&1, &1, Error, Bytes.Bytes>:
185      body_pair = bytes.clone.split(encode.body(manifest))
186      encode.body.digest(body_pair)
187
188def encode.checked(manifest: Manifest, valid: Bool) -> Result<&1, &1, Error, Bytes.Bytes>:
189  match valid:
190    case False{}:
191      Fail{InvalidName{}}
192    case True{}:
193      encode.body.checked(manifest)
194
195def manifest.valid(manifest: Manifest) -> Bool:
196  match manifest:
197    case M{levels}:
198      levels.valid(levels)
199
200# Handle serialize in the binary manifest codec.
201def serialize(+manifest: Manifest) -> Result<&1, &1, Error, Bytes.Bytes>:
202  encode.checked(manifest, manifest.valid(manifest))
203
204def token.from.result(result: Result<&1, &1, Error, Bytes.Bytes>) -> String:
205  match result:
206    case Done{bytes}:
207      Bytes.to_hex(bytes)
208    case Fail{_}:
209      ""
210
211# Handle token in the binary manifest codec.
212def token(manifest: Manifest) -> String:
213  token.from.result(serialize(manifest))
214
215
216def cursor.u32(cursor: Bytes.Cursor) -> Bytes.Cursor & Maybe<&2, U32>:
217  Bytes.Cursor.u32be(cursor)
218
219def cursor.bytes(cursor: Bytes.Cursor, len: U32) -> Bytes.Cursor & Maybe<&1, Bytes.CursorLimit>:
220  Bytes.Cursor.region(cursor, len)
221
222def read.name.text(
223  cursor: Bytes.Cursor,
224  limit: Bytes.CursorLimit,
225  name: String,
226  valid: Bool
227) -> Bytes.Cursor & Maybe<&2, String>:
228  match valid:
229    case False{}:
230      (Bytes.Cursor.leave(cursor, limit), None{})
231    case True{}:
232      (Bytes.Cursor.leave(cursor, limit), Some{name})
233
234def read.name.decoded(
235  cursor: Bytes.Cursor,
236  limit: Bytes.CursorLimit,
237  decoded: Result<&1, &1, U32 & String, String>
238) -> Bytes.Cursor & Maybe<&2, String>:
239  match decoded:
240    case Fail{_}:
241      (Bytes.Cursor.leave(cursor, limit), None{})
242    case Done{+name}:
243      read.name.text(cursor, limit, name, name.text.valid(name))
244
245def read.name.checked(
246  cursor: Bytes.Cursor,
247  limit: Bytes.CursorLimit,
248  bytes: Bytes.Bytes
249) -> Bytes.Cursor & Maybe<&2, String>:
250  read.name.decoded(cursor, limit, StorageBytes.to_string_strict(bytes))
251
252def read.name.buffer.copies(
253  limit: Bytes.CursorLimit,
254  len: U32,
255  +offset: U32,
256  start: U32,
257  end: U32,
258  copies: Bytes.Bytes & Bytes.Bytes
259) -> Bytes.Cursor & Maybe<&2, String>:
260  match copies:
261    case (cursor_bytes, slice_bytes):
262      read.name.checked(Bytes.Cursor{cursor_bytes, offset, start, end}, limit,
263        bytes.slice.second(Bytes.slice(slice_bytes, offset, len)))
264
265def read.name.buffer(cursor: Bytes.Cursor, limit: Bytes.CursorLimit, len: U32) -> Bytes.Cursor & Maybe<&2, String>:
266  match cursor:
267    case Bytes.Cursor{source, +offset, +start, +end}:
268      read.name.buffer.copies(limit, len, offset, start, end, bytes.clone.split(source))
269
270def read.name.region.result(
271  region: Bytes.Cursor & Maybe<&1, Bytes.CursorLimit>,
272  len: U32
273) -> Bytes.Cursor & Maybe<&2, String>:
274  match region:
275    case (next, None{}):
276      (next, None{})
277    case (next, Some{limit}):
278      read.name.buffer(next, limit, len)
279
280def read.name.region(cursor: Bytes.Cursor, +len: U32) -> Bytes.Cursor & Maybe<&2, String>:
281  read.name.region.result(cursor.bytes(cursor, len), len)
282
283def read.name(pair: Bytes.Cursor & Maybe<&2, U32>) -> Bytes.Cursor & Maybe<&2, String>:
284  match pair:
285    case (cursor, None{}):
286      (cursor, None{})
287    case (cursor, Some{len}):
288      read.name.region(cursor, len)
289
290def parse.step.reject.name(value: Bytes.Cursor & Maybe<&2, String>) -> ParseTransition:
291  match value:
292    case (cursor, _):
293      Reject{cursor}
294
295def parse.step.reject(input: ParseInput) -> ParseTransition:
296  match input:
297    case NoInput{cursor}:
298      Reject{cursor}
299    case NameInput{value}:
300      parse.step.reject.name(value)
301
302def parse.step.count.value(
303  levels_left: Nat,
304  levels_acc: List<&2, List<&2, String>>,
305  value: Bytes.Cursor & Maybe<&2, U32>
306) -> ParseTransition:
307  match value:
308    case (cursor, None{}):
309      Reject{cursor}
310    case (cursor, Some{count}):
311      Continue{ReadNameLength{levels_left, levels_acc, U32.to_nat(count), Nil{}}, NoInput{cursor}}
312
313def parse.step.count(levels_left: Nat, levels_acc: List<&2, List<&2, String>>, input: ParseInput) -> ParseTransition:
314  match input:
315    case NoInput{cursor}:
316      parse.step.count.value(levels_left, levels_acc, cursor.u32(cursor))
317    case NameInput{_}:
318      parse.step.reject(input)
319
320def parse.step.length.named(
321  levels_left: Nat,
322  levels_acc: List<&2, List<&2, String>>,
323  names_left: Nat,
324  names_acc: List<&2, String>,
325  value: Bytes.Cursor & Maybe<&2, String>
326) -> ParseTransition:
327  Continue{ReadNameBody{levels_left, levels_acc, names_left, names_acc}, NameInput{value}}
328
329def parse.step.length.value(
330  levels_left: Nat,
331  levels_acc: List<&2, List<&2, String>>,
332  names_left: Nat,
333  names_acc: List<&2, String>,
334  value: Bytes.Cursor & Maybe<&2, U32>
335) -> ParseTransition:
336  match value:
337    case (cursor, None{}):
338      Reject{cursor}
339    case (cursor, Some{len}):
340      parse.step.length.named(levels_left, levels_acc, names_left, names_acc, read.name((cursor, Some{len})))
341
342def parse.step.length.input(
343  levels_left: Nat,
344  levels_acc: List<&2, List<&2, String>>,
345  names_left: Nat,
346  names_acc: List<&2, String>,
347  input: ParseInput
348) -> ParseTransition:
349  match input:
350    case NoInput{cursor}:
351      parse.step.length.value(levels_left, levels_acc, names_left, names_acc, cursor.u32(cursor))
352    case NameInput{_}:
353      parse.step.reject(input)
354
355def parse.step.level.remaining(
356  levels_left: Nat,
357  levels_acc: List<&2, List<&2, String>>,
358  names: List<&2, String>,
359  cursor: Bytes.Cursor
360) -> ParseTransition:
361  match levels_left:
362    case 0n:
363      Reject{cursor}
364    case 1n+rest:
365      match rest:
366        case 0n:
367          Finish{cursor, List.reverse(&2, List<&2, String>, Con{names, levels_acc})}
368        case 1n+more:
369          Continue{ReadNamesCount{1n+more, Con{names, levels_acc}}, NoInput{cursor}}
370
371def parse.step.level(
372  levels_left: Nat,
373  levels_acc: List<&2, List<&2, String>>,
374  names_acc: List<&2, String>,
375  input: ParseInput
376) -> ParseTransition:
377  match input:
378    case NoInput{cursor}:
379      parse.step.level.remaining(levels_left, levels_acc, List.reverse(&2, String, names_acc), cursor)
380    case NameInput{_}:
381      parse.step.reject(input)
382
383def parse.step.name.value(
384  levels_left: Nat,
385  levels_acc: List<&2, List<&2, String>>,
386  names_left: Nat,
387  names_acc: List<&2, String>,
388  value: Bytes.Cursor & Maybe<&2, String>
389) -> ParseTransition:
390  match value:
391    case (cursor, None{}):
392      Reject{cursor}
393    case (cursor, Some{name}):
394      Continue{ReadNameLength{levels_left, levels_acc, names_left, Con{name, names_acc}}, NoInput{cursor}}
395
396def parse.step.name(
397  levels_left: Nat,
398  levels_acc: List<&2, List<&2, String>>,
399  names_left: Nat,
400  names_acc: List<&2, String>,
401  input: ParseInput
402) -> ParseTransition:
403  match input:
404    case NameInput{value}:
405      parse.step.name.value(levels_left, levels_acc, names_left, names_acc, value)
406    case NoInput{_}:
407      parse.step.reject(input)
408
409def parse.step.state(state: ParseState, input: ParseInput) -> ParseTransition:
410  match state:
411    case ReadNamesCount{levels_left, levels_acc}:
412      parse.step.count(levels_left, levels_acc, input)
413    case ReadNameLength{levels_left, levels_acc, names_left, names_acc}:
414      match names_left:
415        case 0n:
416          parse.step.level(levels_left, levels_acc, names_acc, input)
417        case 1n+rest:
418          parse.step.length.input(levels_left, levels_acc, rest, names_acc, input)
419    case ReadNameBody{levels_left, levels_acc, names_left, names_acc}:
420      parse.step.name(levels_left, levels_acc, names_left, names_acc, input)
421
422def parse.loop.exhausted.name(value: Bytes.Cursor & Maybe<&2, String>) -> Bytes.Cursor & Maybe<&2, Manifest>:
423  match value:
424    case (cursor, _):
425      (cursor, None{})
426
427def parse.loop.exhausted(transition: ParseTransition) -> Bytes.Cursor & Maybe<&2, Manifest>:
428  match transition:
429    case Continue{_, NoInput{cursor}}:
430      (cursor, None{})
431    case Continue{_, NameInput{value}}:
432      parse.loop.exhausted.name(value)
433    case Reject{cursor}:
434      (cursor, None{})
435    case Finish{cursor, _}:
436      (cursor, None{})
437
438def parse.loop(fuel: Nat, transition: ParseTransition) -> Bytes.Cursor & Maybe<&2, Manifest>:
439  match fuel:
440    case 0n:
441      parse.loop.exhausted(transition)
442    case 1n+rest:
443      match transition:
444        case Reject{cursor}:
445          (cursor, None{})
446        case Finish{cursor, levels}:
447          (cursor, Some{M{levels}})
448        case Continue{state, input}:
449          parse.loop(rest, parse.step.state(state, input))
450
451def bytes.eq.result(comparison: Bytes.Bytes & Bytes.Bytes & Bool) -> Bool:
452  match comparison:
453    case (_, _, equal):
454      equal
455
456def checksum.valid(bytes: Bytes.Bytes, body_len: U32, digest: Bytes.Bytes) -> Bool:
457  bytes.eq.result(Bytes.eq(SHA.sha256_packed_bytes(bytes.slice.second(Bytes.slice(bytes, 0, body_len))), digest))
458
459def parse.body.digest.verified(
460  body_len: U32,
461  hash_source: Bytes.Bytes,
462  levels: List<&2, List<&2, String>>,
463  digest: Bytes.Bytes
464) -> Maybe<&2, Manifest>:
465  Bool.pick(Maybe<&2, Manifest>, checksum.valid(hash_source, body_len, digest), Some{M{levels}}, None{})
466
467def parse.body.digest.footer(
468  +body_len: U32,
469  hash_source: Bytes.Bytes,
470  levels: List<&2, List<&2, String>>,
471  copies: Bytes.Bytes & Bytes.Bytes
472) -> Maybe<&2, Manifest>:
473  match copies:
474    case (_, digest_source):
475      parse.body.digest.verified(body_len, hash_source, levels, bytes.slice.second(Bytes.slice(digest_source, body_len, 32)))
476
477def parse.body.digest.checked(
478  body_len: U32,
479  hash_source: Bytes.Bytes,
480  footer_source: Bytes.Bytes,
481  levels: List<&2, List<&2, String>>,
482  within_size: Bool
483) -> Maybe<&2, Manifest>:
484  match within_size:
485    case False{}:
486      None{}
487    case True{}:
488      parse.body.digest.footer(body_len, hash_source, levels, bytes.clone.split(footer_source))
489
490def parse.body.digest.size(
491  +body_len: U32,
492  hash_source: Bytes.Bytes,
493  size_pair: Bytes.Bytes & U32,
494  levels: List<&2, List<&2, String>>
495) -> Maybe<&2, Manifest>:
496  match size_pair:
497    case (footer_source, +total):
498      parse.body.digest.checked(body_len, hash_source, footer_source, levels, U32.is_eq(total, (body_len + 32 : U32)))
499
500def parse.body.digest.sources(
501  body_len: U32,
502  levels: List<&2, List<&2, String>>,
503  sources: Bytes.Bytes & Bytes.Bytes
504) -> Maybe<&2, Manifest>:
505  match sources:
506    case (hash_source, footer_source):
507      parse.body.digest.size(body_len, hash_source, Bytes.length(footer_source), levels)
508
509def parse.body.position(
510  cursor: Bytes.Cursor,
511  source: Bytes.Bytes,
512  levels: List<&2, List<&2, String>>
513) -> Maybe<&2, Manifest>:
514  match cursor:
515    case Bytes.Cursor{_, +body_len, _, _}:
516      parse.body.digest.sources(body_len, levels, bytes.clone.split(source))
517
518def parse.body.levels.manifest(cursor: Bytes.Cursor, source: Bytes.Bytes, manifest: Manifest) -> Maybe<&2, Manifest>:
519  match manifest:
520    case M{levels}:
521      parse.body.position(cursor, source, levels)
522
523def parse.body.levels(source: Bytes.Bytes, result: Bytes.Cursor & Maybe<&2, Manifest>) -> Maybe<&2, Manifest>:
524  match result:
525    case (_, None{}):
526      None{}
527    case (body_end, Some{manifest}):
528      parse.body.levels.manifest(body_end, source, manifest)
529
530def parse.body.start(count: Nat, cursor: Bytes.Cursor, source: Bytes.Bytes) -> Maybe<&2, Manifest>:
531  match count:
532    case 0n:
533      parse.body.levels(source, parse.loop(Nat.add(Nat.mul(3n, U32.to_nat(StorageBytes.MAX_MANIFEST_BYTES())), 16n), Finish{cursor, Nil{}}))
534    case 1n+rest:
535      parse.body.levels(source, parse.loop(Nat.add(Nat.mul(3n, U32.to_nat(StorageBytes.MAX_MANIFEST_BYTES())), 16n), Continue{ReadNamesCount{1n+rest, Nil{}}, NoInput{cursor}}))
536
537def parse.body(pair: Bytes.Cursor & Maybe<&2, U32>, source: Bytes.Bytes) -> Maybe<&2, Manifest>:
538  match pair:
539    case (_, None{}):
540      None{}
541    case (cursor, Some{count}):
542      parse.body.start(U32.to_nat(count), cursor, source)
543
544def parse.version(cursor: Bytes.Cursor, source: Bytes.Bytes, valid: Bool) -> Maybe<&2, Manifest>:
545  match valid:
546    case False{}:
547      None{}
548    case True{}:
549      parse.body(cursor.u32(cursor), source)
550
551def parse.magic(pair: Bytes.Cursor & Maybe<&2, U32>, source: Bytes.Bytes) -> Maybe<&2, Manifest>:
552  match pair:
553    case (_, None{}):
554      None{}
555    case (cursor, Some{+version}):
556      parse.version(cursor, source, U32.is_eq(version, 3))
557
558def parse.input.second.valid(source: Bytes.Bytes, cursor: Bytes.Cursor, valid: Bool) -> Maybe<&2, Manifest>:
559  match valid:
560    case False{}:
561      None{}
562    case True{}:
563      parse.magic(cursor.u32(cursor), source)
564
565def parse.input.second(source: Bytes.Bytes, pair: Bytes.Cursor & Maybe<&2, U32>) -> Maybe<&2, Manifest>:
566  match pair:
567    case (_, None{}):
568      None{}
569    case (cursor, Some{second}):
570      parse.input.second.valid(source, cursor, U32.is_eq(second, 1295207680))
571
572def parse.input.first.valid(source: Bytes.Bytes, cursor: Bytes.Cursor, valid: Bool) -> Maybe<&2, Manifest>:
573  match valid:
574    case False{}:
575      None{}
576    case True{}:
577      parse.input.second(source, cursor.u32(cursor))
578
579def parse.input.first(source: Bytes.Bytes, pair: Bytes.Cursor & Maybe<&2, U32>) -> Maybe<&2, Manifest>:
580  match pair:
581    case (_, None{}):
582      None{}
583    case (cursor, Some{first}):
584      parse.input.first.valid(source, cursor, U32.is_eq(first, 1297697875))
585
586def parse.input.start(sources: Bytes.Bytes & Bytes.Bytes) -> Maybe<&2, Manifest>:
587  match sources:
588    case (source, cursor_source):
589      parse.input.first(source, Bytes.Cursor.u32be(Bytes.Cursor.new(cursor_source)))
590
591def parse.input.with_magic(source: Bytes.Bytes) -> Maybe<&2, Manifest>:
592  parse.input.start(bytes.clone.split(source))
593
594def parse.bounded(source: Bytes.Bytes, within_limit: Bool) -> Maybe<&2, Manifest>:
595  match within_limit:
596    case False{}:
597      None{}
598    case True{}:
599      parse.input.with_magic(source)
600
601def parse.size(size_pair: Bytes.Bytes & U32) -> Maybe<&2, Manifest>:
602  match size_pair:
603    case (source, len):
604      parse.bounded(source, U32.is_le(len, StorageBytes.MAX_MANIFEST_BYTES()))
605
606# Handle parse in the binary manifest codec.
607def parse(source: Bytes.Bytes) -> Maybe<&2, Manifest>:
608  parse.size(Bytes.length(source))
609
610def parse.result.parsed(parsed: Maybe<&2, Manifest>) -> ParseResult:
611  match parsed:
612    case Some{manifest}:
613      Parsed{manifest}
614    case None{}:
615      Malformed{}
616
617def parse.result.version.checked(
618  source: Bytes.Bytes,
619  version: U32,
620  supported: Bool
621) -> ParseResult:
622  match supported:
623    case False{}:
624      UnsupportedVersion{version}
625    case True{}:
626      parse.result.parsed(parse(source))
627
628def parse.result.version.read(
629  source: Bytes.Bytes,
630  pair: Bytes.Cursor & Maybe<&2, U32>
631) -> ParseResult:
632  match pair:
633    case (_, None{}):
634      Malformed{}
635    case (cursor, Some{+version}):
636      parse.result.version.checked(source, version, U32.is_eq(version, 3))
637
638def parse.result.second.checked(
639  source: Bytes.Bytes,
640  pair: Bytes.Cursor & Maybe<&2, U32>,
641  valid: Bool
642) -> ParseResult:
643  match valid:
644    case False{}:
645      Malformed{}
646    case True{}:
647      parse.result.version.read(source, pair)
648
649def parse.result.second.read(
650  source: Bytes.Bytes,
651  pair: Bytes.Cursor & Maybe<&2, U32>
652) -> ParseResult:
653  match pair:
654    case (_, None{}):
655      Malformed{}
656    case (cursor, Some{word}):
657      parse.result.second.checked(source, Bytes.Cursor.u32be(cursor), U32.is_eq(word, 1295207680))
658
659def parse.result.first.checked(
660  source: Bytes.Bytes,
661  pair: Bytes.Cursor & Maybe<&2, U32>,
662  valid: Bool
663) -> ParseResult:
664  match valid:
665    case False{}:
666      Malformed{}
667    case True{}:
668      parse.result.second.read(source, pair)
669
670def parse.result.first.read(
671  source: Bytes.Bytes,
672  pair: Bytes.Cursor & Maybe<&2, U32>
673) -> ParseResult:
674  match pair:
675    case (_, None{}):
676      Malformed{}
677    case (cursor, Some{word}):
678      parse.result.first.checked(source, Bytes.Cursor.u32be(cursor), U32.is_eq(word, 1297697875))
679
680def parse.result.start(pair: Bytes.Bytes & Bytes.Bytes) -> ParseResult:
681  match pair:
682    case (source, cursor_source):
683      parse.result.first.read(source, Bytes.Cursor.u32be(Bytes.Cursor.new(cursor_source)))
684
685def parse.result.bounded(source: Bytes.Bytes, within: Bool) -> ParseResult:
686  match within:
687    case False{}:
688      ParseLimitExceeded{}
689    case True{}:
690      parse.result.start(bytes.clone.split(source))
691
692def parse.result.sized(pair: Bytes.Bytes & U32) -> ParseResult:
693  match pair:
694    case (source, +size):
695      parse.result.bounded(source, U32.is_le(size, StorageBytes.MAX_MANIFEST_BYTES()))
696
697# Separates a valid Manifest from unsupported and malformed input.
698def parse_result(source: Bytes.Bytes) -> ParseResult:
699  parse.result.sized(Bytes.length(source))
700
701# Returns the error code for an unsupported Manifest version.
702def unsupported_version_error_code() -> U32:
703  4294967295
704
705# Returns the error code for malformed Manifest data.
706def malformed_error_code() -> U32:
707  4294967294
708
709# Returns the error code for a Manifest size limit.
710def parse_limit_error_code() -> U32:
711  4294967293
712
713# Check whether decided holds for the binary manifest codec.
714def is_decided(_result: Maybe<&2, Manifest>) -> Bool:
715  True{}