src/Manifest.bend
mylsm-lsm-store@0.6.0.1 · 715 lines · 100 definitions
1import Base
2import mylsm-lsm-store@0.6.0.1/src/StorageBytes.bend as StorageBytes
3import bend-kit-bytes@0.3.2.0/bytes.bend as Bytes
4import mylsm-lsm-store@0.6.0.1/src/hub_sha/sha256.bend as SHA
5
6
7type Manifest is Data:
8 M{levels: List<&2, List<&2, String>>}
9
10
11type Error is Data:
12 TooLarge{}
13 InvalidName{}
14
15
16type ParseResult is Data:
17 Parsed{manifest: Manifest}
18 UnsupportedVersion{version: U32}
19 Malformed{}
20 ParseLimitExceeded{}
21
22
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
29type ParseInput is Type:
30 NoInput{cursor: Bytes.Cursor}
31 NameInput{value: Bytes.Cursor & Maybe<&2, String>}
32
33
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
47def magic() -> Bytes.Bytes:
48 magic.result(Bytes.from_hex("4d594c534d334d00"))
49
50
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
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
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
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
698def parse_result(source: Bytes.Bytes) -> ParseResult:
699 parse.result.sized(Bytes.length(source))
700
701
702def unsupported_version_error_code() -> U32:
703 4294967295
704
705
706def malformed_error_code() -> U32:
707 4294967294
708
709
710def parse_limit_error_code() -> U32:
711 4294967293
712
713
714def is_decided(_result: Maybe<&2, Manifest>) -> Bool:
715 True{}