1 import Base 2 import ./StorageBytes.bend as StorageBytes 3 import bend-kit-bytes@0.3.2.0/bytes.bend as Bytes 4 import ./hub_sha/sha256.bend as SHA 5 6 # Represent Manifest data used by the binary manifest codec. 7 type Manifest is Data: 8 M{levels: List<&2, List<&2, String>>} 9 10 # Represent Error data used by the binary manifest codec. 11 type Error is Data: 12 TooLarge{} 13 InvalidName{} 14 15 # Represents parseresult data in manifest. 16 type 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. 23 type 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. 29 type 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. 34 type 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 39 def 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. 47 def magic() -> Bytes.Bytes: 48 magic.result(Bytes.from_hex("4d594c534d334d00")) 49 50 # Handle u32 in the binary manifest codec. 51 def u32(+value: U32) -> Bytes.Bytes: 52 Bytes.set.u32be(Bytes.new(4), 0, value) 53 54 def bytes.clone.pair(+len: U32, copied: Array & Array) -> Bytes.Bytes & Bytes.Bytes: 55 match copied: 56 case (left, right): 57 (Bytes.Bytes{len, left}, Bytes.Bytes{len, right}) 58 59 def 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 64 def bytes.clone.first(pair: Bytes.Bytes & Bytes.Bytes) -> Bytes.Bytes: 65 match pair: 66 case (left, _): 67 left 68 69 def bytes.length(pair: Bytes.Bytes & U32) -> U32: 70 match pair: 71 case (_, len): 72 len 73 74 def bytes.slice.second(pair: Bytes.Bytes & Bytes.Bytes) -> Bytes.Bytes: 75 match pair: 76 case (_, second): 77 second 78 79 def encode.name.copies(+len: U32, tail: Bytes.Bytes, copies: Array & Array) -> Bytes.Bytes: 80 match copies: 81 case (stored, _unused): 82 Bytes.concat([u32(len), Bytes.Bytes{len, stored}, tail]) 83 84 def 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 89 def 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 94 def 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 101 def 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 108 def 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 115 def 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 122 def 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 129 def 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 138 def names.valid(names: List<&2, String>) -> Bool: 139 names.valid.step(names, True{}) 140 141 def 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 150 def levels.valid(levels: List<&2, List<&2, String>>) -> Bool: 151 levels.valid.step(levels, True{}) 152 153 def 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 160 def 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 167 def 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 172 def 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 179 def 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 184 def 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 188 def 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 195 def 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. 201 def serialize(+manifest: Manifest) -> Result<&1, &1, Error, Bytes.Bytes>: 202 encode.checked(manifest, manifest.valid(manifest)) 203 204 def 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. 212 def token(manifest: Manifest) -> String: 213 token.from.result(serialize(manifest)) 214 215 216 def cursor.u32(cursor: Bytes.Cursor) -> Bytes.Cursor & Maybe<&2, U32>: 217 Bytes.Cursor.u32be(cursor) 218 219 def cursor.bytes(cursor: Bytes.Cursor, len: U32) -> Bytes.Cursor & Maybe<&1, Bytes.CursorLimit>: 220 Bytes.Cursor.region(cursor, len) 221 222 def 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 234 def 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 245 def 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 252 def 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 265 def 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 270 def 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 280 def read.name.region(cursor: Bytes.Cursor, +len: U32) -> Bytes.Cursor & Maybe<&2, String>: 281 read.name.region.result(cursor.bytes(cursor, len), len) 282 283 def 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 290 def parse.step.reject.name(value: Bytes.Cursor & Maybe<&2, String>) -> ParseTransition: 291 match value: 292 case (cursor, _): 293 Reject{cursor} 294 295 def 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 302 def 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 313 def 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 320 def 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 329 def 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 342 def 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 355 def 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 371 def 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 383 def 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 396 def 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 409 def 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 422 def 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 427 def 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 438 def 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 451 def bytes.eq.result(comparison: Bytes.Bytes & Bytes.Bytes & Bool) -> Bool: 452 match comparison: 453 case (_, _, equal): 454 equal 455 456 def 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 459 def 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 467 def 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 477 def 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 490 def 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 500 def 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 509 def 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 518 def 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 523 def 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 530 def 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 537 def 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 544 def 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 551 def 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 558 def 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 565 def 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 572 def 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 579 def 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 586 def 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 591 def parse.input.with_magic(source: Bytes.Bytes) -> Maybe<&2, Manifest>: 592 parse.input.start(bytes.clone.split(source)) 593 594 def 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 601 def 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. 607 def parse(source: Bytes.Bytes) -> Maybe<&2, Manifest>: 608 parse.size(Bytes.length(source)) 609 610 def parse.result.parsed(parsed: Maybe<&2, Manifest>) -> ParseResult: 611 match parsed: 612 case Some{manifest}: 613 Parsed{manifest} 614 case None{}: 615 Malformed{} 616 617 def 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 628 def 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 638 def 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 649 def 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 659 def 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 670 def 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 680 def 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 685 def 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 692 def 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. 698 def parse_result(source: Bytes.Bytes) -> ParseResult: 699 parse.result.sized(Bytes.length(source)) 700 701 # Returns the error code for an unsupported Manifest version. 702 def unsupported_version_error_code() -> U32: 703 4294967295 704 705 # Returns the error code for malformed Manifest data. 706 def malformed_error_code() -> U32: 707 4294967294 708 709 # Returns the error code for a Manifest size limit. 710 def parse_limit_error_code() -> U32: 711 4294967293 712 713 # Check whether decided holds for the binary manifest codec. 714 def is_decided(_result: Maybe<&2, Manifest>) -> Bool: 715 True{}