src/transfer/FormatInspect.bend
mylsm-lsm-store@0.6.0.1 · 140 lines · 22 definitions
1import Base
2import mylsm-lsm-store@0.6.0.1/src/ByteManifest.bend as ByteManifest
3import mylsm-lsm-store@0.6.0.1/src/Manifest.bend as LegacyManifest
4import bend-kit-bytes@0.3.2.0/bytes.bend as Bytes
5
6
7type StorageFormat is Data:
8 Format04{}
9 Format06{}
10 UnknownFormat{}
11
12
13type Identity is Data:
14 Identity{package_version: String, storage_version: String, generation: U32}
15
16
17type Integrity is Data:
18 Valid{}
19 UnsupportedVersion{generation: U32}
20 UnsupportedComparator{generation: U32}
21 UnrecognizedFormat{}
22 Corrupt{}
23 ResourceLimit{}
24
25
26type Inspection is Data:
27 Inspection{identity: Identity, integrity: Integrity}
28
29
30def 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
38def magic.legacy() -> Bytes.Bytes:
39 magic.from_hex(Bytes.from_hex("4d594c534d334d00"))
40
41
42def magic.current() -> Bytes.Bytes:
43 magic.from_hex(Bytes.from_hex("4d594c534d344d00"))
44
45
46def classify.current(comparison: Bytes.Bytes & Bytes.Bytes & Bool) -> StorageFormat:
47 match comparison:
48 case (_, _, True{}):
49 Format06{}
50 case (_, _, False{}):
51 UnknownFormat{}
52
53
54def 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
62def classify_manifest(magic: Bytes.Bytes) -> StorageFormat:
63 classify.legacy(Bytes.eq(magic.legacy(), magic))
64
65
66def 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
76def inspect_manifest(magic: Bytes.Bytes) -> Identity:
77 describe(classify_manifest(magic))
78
79def magic.slice.result(pair: Bytes.Bytes & Bytes.Bytes) -> Bytes.Bytes:
80 match pair:
81 case (_, bytes): bytes
82
83def bytes.clone.pair(+len: U32, copied: Array<U32> & Array<U32>) -> Bytes.Bytes & Bytes.Bytes:
84 match copied:
85 case (left, right): (Bytes.Bytes{len, left}, Bytes.Bytes{len, right})
86
87def 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
92def 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
100def 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
111def 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
117def 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
123def 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
131def 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
139def inspect_manifest_bytes(bytes: Bytes.Bytes) -> Inspection:
140 inspect.bytes.copies(bytes.clone.split(bytes))