1 import Base 2 import ../ByteManifest.bend as ByteManifest 3 import ../Manifest.bend as LegacyManifest 4 import bend-kit-bytes@0.3.2.0/bytes.bend as Bytes 5 6 # Identifies the storage generation independently of the writing package. 7 type StorageFormat is Data: 8 Format04{} 9 Format06{} 10 UnknownFormat{} 11 12 # Reports package and storage identities as separate fields. 13 type Identity is Data: 14 Identity{package_version: String, storage_version: String, generation: U32} 15 16 # Reports validation status without conflating it with the format identity. 17 type Integrity is Data: 18 Valid{} 19 UnsupportedVersion{generation: U32} 20 UnsupportedComparator{generation: U32} 21 UnrecognizedFormat{} 22 Corrupt{} 23 ResourceLimit{} 24 25 # Separates API/storage version identity from manifest integrity. 26 type Inspection is Data: 27 Inspection{identity: Identity, integrity: Integrity} 28 29 # Converts a decoded hex literal to an owned buffer. 30 def magic.from_hex(value: Maybe<&1, Bytes.Bytes>) -> Bytes.Bytes: 31 match value: 32 case Some{bytes}: 33 bytes 34 case None{}: 35 Bytes.new(0) 36 37 # Produces the generation-three Manifest magic. 38 def magic.legacy() -> Bytes.Bytes: 39 magic.from_hex(Bytes.from_hex("4d594c534d334d00")) 40 41 # Produces the generation-four Manifest magic. 42 def magic.current() -> Bytes.Bytes: 43 magic.from_hex(Bytes.from_hex("4d594c534d344d00")) 44 45 # Classifies the current magic after an unsuccessful legacy comparison. 46 def classify.current(comparison: Bytes.Bytes & Bytes.Bytes & Bool) -> StorageFormat: 47 match comparison: 48 case (_, _, True{}): 49 Format06{} 50 case (_, _, False{}): 51 UnknownFormat{} 52 53 # Preserves the candidate bytes while checking the current manifest magic. 54 def classify.legacy(comparison: Bytes.Bytes & Bytes.Bytes & Bool) -> StorageFormat: 55 match comparison: 56 case (_, candidate, True{}): 57 Format04{} 58 case (_, candidate, False{}): 59 classify.current(Bytes.eq(magic.current(), candidate)) 60 61 # Classifies known Manifest signatures without opening or modifying storage. 62 def classify_manifest(magic: Bytes.Bytes) -> StorageFormat: 63 classify.legacy(Bytes.eq(magic.legacy(), magic)) 64 65 # Describes the package release and storage format separately. 66 def describe(format: StorageFormat) -> Identity: 67 match format: 68 case Format04{}: 69 Identity{"0.5.0.0", "0.4.0.0", 3} 70 case Format06{}: 71 Identity{"0.6.0.0", "0.6.0.0", 4} 72 case UnknownFormat{}: 73 Identity{"unknown", "unknown", 0} 74 75 # Identifies a Manifest and returns its separate version fields. 76 def inspect_manifest(magic: Bytes.Bytes) -> Identity: 77 describe(classify_manifest(magic)) 78 79 def magic.slice.result(pair: Bytes.Bytes & Bytes.Bytes) -> Bytes.Bytes: 80 match pair: 81 case (_, bytes): bytes 82 83 def bytes.clone.pair(+len: U32, copied: Array & Array) -> Bytes.Bytes & Bytes.Bytes: 84 match copied: 85 case (left, right): (Bytes.Bytes{len, left}, Bytes.Bytes{len, right}) 86 87 def bytes.clone.split(bytes: Bytes.Bytes) -> Bytes.Bytes & Bytes.Bytes: 88 match bytes: 89 case Bytes.Bytes{+len, buffer}: 90 bytes.clone.pair(len, Bytes.copy.bytes(len, buffer, Bytes.alloc(len), 0, 0)) 91 92 def inspect.legacy.result(result: LegacyManifest.ParseResult) -> Integrity: 93 match result: 94 case LegacyManifest.Parsed{_}: Valid{} 95 case LegacyManifest.UnsupportedVersion{version}: 96 UnsupportedVersion{version} 97 case LegacyManifest.ParseLimitExceeded{}: ResourceLimit{} 98 case LegacyManifest.Malformed{}: Corrupt{} 99 100 def inspect.current.result( 101 result: Result<&1, &1, ByteManifest.Error, ByteManifest.ManifestValue> 102 ) -> Integrity: 103 match result: 104 case Done{_}: Valid{} 105 case Fail{ByteManifest.UnsupportedVersion{generation}}: 106 UnsupportedVersion{generation} 107 case Fail{ByteManifest.ComparatorMismatch{generation}}: 108 UnsupportedComparator{generation} 109 case Fail{_}: Corrupt{} 110 111 def inspect.result(format: StorageFormat, bytes: Bytes.Bytes) -> Integrity: 112 match format: 113 case Format04{}: inspect.legacy.result(LegacyManifest.parse_result(bytes)) 114 case Format06{}: inspect.current.result(ByteManifest.decode(bytes)) 115 case UnknownFormat{}: UnrecognizedFormat{} 116 117 def format.clone(format: StorageFormat) -> StorageFormat & StorageFormat: 118 match format: 119 case Format04{}: (Format04{}, Format04{}) 120 case Format06{}: (Format06{}, Format06{}) 121 case UnknownFormat{}: (UnknownFormat{}, UnknownFormat{}) 122 123 def inspect.bytes.format( 124 bytes: Bytes.Bytes, 125 formats: StorageFormat & StorageFormat 126 ) -> Inspection: 127 match formats: 128 case (identity_format, integrity_format): 129 Inspection{describe(identity_format), inspect.result(integrity_format, bytes)} 130 131 def inspect.bytes.copies(copies: Bytes.Bytes & Bytes.Bytes) -> Inspection: 132 match copies: 133 case (data, magic_bytes): 134 inspect.bytes.format(data, 135 format.clone(classify_manifest(magic.slice.result( 136 Bytes.slice(magic_bytes, 0, 8))))) 137 138 # Identifies and validates one complete manifest without changing storage. 139 def inspect_manifest_bytes(bytes: Bytes.Bytes) -> Inspection: 140 inspect.bytes.copies(bytes.clone.split(bytes))