76a7e0ddde50e8a600ae8855d9091aa59af3235193605e5a7a07532ae90372af.tri (7962B)
1 !import prelude * 2 !import io * 3 !import native_math as N 4 !export sourceObjectTreeDomain 5 !export sourceObjectFlatTreeDomain 6 !export sourceObjectManifestDomain 7 !export sourceObjectTreeAbi 8 !export sourceObjectTreeKind 9 !export sourceObjectEncodeOnto 10 !export sourceObjectEncode 11 !export sourceObjectDecode 12 !export sourceObjectDecodeComplete 13 !export sourceObjectShard 14 !export sourceObjectPath 15 !export sourceObjectDigest 16 !export sourceObjectHashHex 17 !export sourceObjectHashValid 18 !export sourceObjectVerify 19 !export sourceObjectGet 20 !export sourceObjectStoreAt 21 !export sourceObjectStore 22 !export sourceObjectPutTree 23 !export sourceObjectGetTree 24 25 -- Native executable objects preserve sharing as name-neutral indexed bundles. 26 -- The flat codec below remains an independent data codec with its own domain; 27 -- it is not the native executable publication format. 28 sourceObjectTreeDomain = "arboricx.indexed-tree.v1" 29 sourceObjectFlatTreeDomain = "arboricx.tree-term.v1" 30 sourceObjectManifestDomain = "arboricx.module-manifest.v1" 31 sourceObjectTreeAbi = "arboricx.abi.tree.v1" 32 sourceObjectTreeKind = "arboricx.indexed-tree.v1" 33 34 -- Build directly onto a suffix. Appending each encoded left subtree copies 35 -- its byte list once per enclosing fork and retains huge intermediate lists 36 -- for compiler exports. This visits each expanded tree occurrence once. 37 -- Keep triage as the small shape eliminator; canonical preorder is unchanged. 38 sourceObjectEncodeOnto tree suffix = 39 triage 40 (pair 0 suffix) 41 (child : pair 1 (sourceObjectEncodeOnto child suffix)) 42 (left right : pair 2 (sourceObjectEncodeOnto left (sourceObjectEncodeOnto right suffix))) 43 tree 44 sourceObjectEncode tree = sourceObjectEncodeOnto tree t 45 46 sourceObjectDecode bytes = 47 lazyList 48 (_ : err "truncated tree-term" bytes) 49 (tag rest : 50 lazyBool 51 (_ : ok t rest) 52 (_ : lazyBool 53 (_ : lazyResult 54 (problem remaining : err problem remaining) 55 (child remaining : ok (t child) remaining) 56 (sourceObjectDecode rest)) 57 (_ : lazyBool 58 (_ : lazyResult 59 (problem remaining : err problem remaining) 60 (left remaining : lazyResult 61 (problem tail : err problem tail) 62 (right tail : ok (t left right) tail) 63 (sourceObjectDecode remaining)) 64 (sourceObjectDecode rest)) 65 (_ : err "invalid tree-term tag" rest) 66 (equal? tag 2)) 67 (equal? tag 1)) 68 (equal? tag 0)) 69 bytes 70 71 sourceObjectDecodeComplete bytes = 72 lazyResult 73 (problem remaining : err problem remaining) 74 (tree remaining : lazyList 75 (_ : ok tree t) 76 (_ _ : err "trailing tree-term bytes" t) 77 remaining) 78 (sourceObjectDecode bytes) 79 80 -- The shard is taken by finite destructuring: it must not cause recursion 81 -- over an abstract hash during fresh-store normalization. 82 sourceObjectShard hash = 83 matchList t (a r0 : 84 matchList t (b r1 : 85 matchList t (c _ : pair a (pair b (pair c t))) r1) r0) hash 86 sourceObjectPath root hash = 87 append root (append "/objects/" (append (sourceObjectShard hash) 88 (append "/" hash))) 89 sourceObjectDigest domain payload = 90 sha256Hex (append domain (pair 0 payload)) 91 92 -- Native math assumes canonical naturals. Keep the existing behavior for 93 -- arbitrary trees: only canonical bytes use the binary comparison fast path. 94 -- Canonical-byte helpers stay private; malformed trees retain the reference path. 95 sourceObjectByteLeaf? value = triage true (_ : false) (_ _ : false) value 96 sourceObjectByteBit? value = triage true (child : sourceObjectByteLeaf? child) (_ _ : false) value 97 sourceObjectByteOne? value = triage false (child : sourceObjectByteLeaf? child) (_ _ : false) value 98 sourceObjectByteWithin value budget = (triage 99 true 100 (_ : false) 101 (bit rest : lazyBool 102 (_ : lazyBool 103 (_ : sourceObjectByteOne? bit) 104 (_ : andLazy? (sourceObjectByteBit? bit) (_ : sourceObjectByteWithin rest (pred_ budget))) 105 (sourceObjectByteLeaf? rest)) 106 (_ : false) 107 (not? (isZero_? budget))) 108 value) 109 sourceObjectCanonicalByte value = sourceObjectByteWithin value 8 110 -- This compatibility path must not call base's canonical-only arithmetic. 111 -- The historical predecessor leaves Stem values unchanged and interprets any 112 -- non-Leaf bit/tail as truthy. Comparison counts down its finite byte bound; 113 -- structural equality (not numeric equality) controls the strict endpoint. 114 sourceObjectReferencePred value = (triage 115 0 116 (child : t child) 117 (bit rest : lazyBool 118 (_ : matchBool (t t rest) 0 rest) 119 (_ : t (t t) (sourceObjectReferencePred rest)) bit) 120 value) 121 sourceObjectReferenceLte value bound = (lazyBool 122 (_ : true) 123 (_ : lazyBool (_ : false) 124 (_ : sourceObjectReferenceLte (sourceObjectReferencePred value) 125 (sourceObjectReferencePred bound)) (isZero_? bound)) 126 (isZero_? value)) 127 sourceObjectReferenceLt value bound = (and? 128 (sourceObjectReferenceLte value bound) (not? (equal? value bound))) 129 sourceObjectHashByteReference? byte = (or? 130 (and? (not? (sourceObjectReferenceLt byte 48)) (sourceObjectReferenceLte byte 57)) 131 (and? (not? (sourceObjectReferenceLt byte 97)) (sourceObjectReferenceLte byte 102))) 132 sourceObjectHashByte? byte = (lazyBool 133 (_ : N.lowerHex byte) 134 (_ : sourceObjectHashByteReference? byte) 135 (sourceObjectCanonicalByte byte)) 136 sourceObjectHashHex bytes = (lazyList 137 (_ : true) 138 (byte rest : andLazy? (sourceObjectHashByte? byte) (_ : sourceObjectHashHex rest)) 139 bytes) 140 sourceObjectHashValid hash = 141 andLazy? (equal? (length hash) 64) 142 (_ : sourceObjectHashHex hash) 143 144 sourceObjectVerify domain payload expected = 145 146 onResult_ (sourceObjectDigest domain payload) 147 (problem : pure (err problem t)) 148 (actual : lazyBool 149 (_ : pure (ok payload t)) 150 (_ : pure (err "CAS digest mismatch" t)) 151 (equal? actual expected)) 152 153 sourceObjectGet root domain hash = 154 lazyBool 155 (_ : onResult_ (readFile (sourceObjectPath root hash)) 156 (problem : pure (err problem t)) 157 (payload : sourceObjectVerify domain payload hash)) 158 (_ : pure (err "invalid CAS digest" t)) 159 (sourceObjectHashValid hash) 160 161 sourceObjectStore root domain payload = 162 onOk_ (sourceObjectDigest domain payload) (hash : 163 onOk_ (createDirectory root) (_ : 164 onOk_ (createDirectory (append root "/objects")) (_ : 165 onOk_ (createDirectory (append root (append "/objects/" 166 (sourceObjectShard hash)))) (_ : 167 sourceObjectStoreAt root domain payload hash)))) 168 169 -- Host publishes via a unique same-directory temp and an atomic no-replace 170 -- link; tricu owns the object identity and verifies even a racing winner. 171 sourceObjectStoreAt root domain payload hash = 172 onOk_ (writeBytesIfAbsent (sourceObjectPath root hash) payload) (_ : 173 onResult_ (sourceObjectGet root domain hash) 174 (problem : pure (err problem t)) 175 (old : lazyBool 176 (_ : pure (ok hash t)) 177 (_ : pure (err "CAS object exists with different bytes" t)) 178 (equal? old payload))) 179 180 -- tricu owns sharding/directories; the host hashes and atomically transports 181 -- the inert tree as an indexed DAG, with verified no-replace writes. 182 sourceObjectPutTree root tree = 183 onOk_ (hashIndexedTree tree) (hash : 184 onOk_ (createDirectory root) (_ : 185 onOk_ (createDirectory (append root "/objects")) (_ : 186 onOk_ (createDirectory (append root (append "/objects/" 187 (sourceObjectShard hash)))) (_ : 188 onOk_ (writeIndexedTreeIfAbsent (sourceObjectPath root hash) hash tree) 189 (_ : pure (ok hash t)))))) 190 -- Typed verified transport avoids expanding raw executable bytes into a 191 -- tricu byte list for hashing and decoding. The portable codec stays available 192 -- as an independent reference; this path does not silently fall back to it. 193 sourceObjectGetTree root hash = 194 lazyBool 195 (_ : readIndexedTree (sourceObjectPath root hash) hash) 196 (_ : pure (err "invalid CAS digest" t)) 197 (sourceObjectHashValid hash) 198