@bjornpagen/bumbledb-log 0.19.2 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/value.ts DELETED
@@ -1,336 +0,0 @@
1
- /**
2
- * The driver's raw-value vocabulary and its two canonical encodings:
3
- * the command codec's tagged little-endian form (the tag table the
4
- * batch wire already declared), and the engine's big-endian
5
- * order-preserving literal form the fingerprint mirror reproduces.
6
- * Values here are always RAW — strings as UTF-8, never intern ids —
7
- * so a key hashed from a raw value cannot depend on a catalog.
8
- */
9
-
10
- import type { ValueTypeSpec } from "@bjornpagen/bumbledb"
11
- import * as errors from "@superbuilders/errors"
12
- import type { ByteReader, ByteWriter } from "#bytes.ts"
13
- import { bytesEqual, I64_MAX, I64_MIN, U64_MAX, utf8Encoder, utf8StrictDecoder } from "#bytes.ts"
14
-
15
- interface Interval {
16
- readonly start: bigint
17
- readonly end: bigint
18
- }
19
-
20
- type Value = boolean | bigint | string | Uint8Array | Interval
21
-
22
- /** A string cell: well-formed UTF-8 by construction. A lone surrogate cannot enter. */
23
- declare const wellFormedUtf8Brand: unique symbol
24
- type WellFormedUtf8 = string & { readonly [wellFormedUtf8Brand]: typeof wellFormedUtf8Brand }
25
-
26
- /** Fatal encoder: refuses lone surrogates rather than emitting U+FFFD. */
27
- function wellFormedUtf8(text: string): WellFormedUtf8 {
28
- if (!text.isWellFormed()) {
29
- throw errors.new("string cell is not well-formed UTF-8")
30
- }
31
- return text as WellFormedUtf8
32
- }
33
-
34
- function parseWellFormedUtf8(raw: Uint8Array): WellFormedUtf8 | undefined {
35
- const decoded = errors.trySync(function decodeUtf8() {
36
- return utf8StrictDecoder.decode(raw)
37
- })
38
- if (decoded.error) {
39
- return undefined
40
- }
41
- return decoded.data as WellFormedUtf8
42
- }
43
-
44
- function domainCeiling(element: "u64" | "i64"): bigint {
45
- return element === "u64" ? U64_MAX : I64_MAX
46
- }
47
-
48
- /** Fixed-width `[start, start + width)`; the domain ceiling is not a value. */
49
- function fixedInterval(start: bigint, width: bigint, element: "u64" | "i64"): Interval | undefined {
50
- const end = start + width
51
- if (end <= start || end >= domainCeiling(element)) {
52
- return undefined
53
- }
54
- return { start, end }
55
- }
56
-
57
- /** 20's tag table: the codec's own numbering, normative to the byte. */
58
- const TAG = {
59
- bool: 0,
60
- u64: 1,
61
- i64: 2,
62
- string: 3,
63
- fixedBytes: 4,
64
- interval: 5,
65
- fixedInterval: 6
66
- } as const
67
-
68
- function isInterval(value: Value): value is Interval {
69
- return typeof value === "object" && !(value instanceof Uint8Array)
70
- }
71
-
72
- function wireTagOf(type: ValueTypeSpec): number {
73
- switch (type.kind) {
74
- case "bool":
75
- return TAG.bool
76
- case "u64":
77
- return TAG.u64
78
- case "i64":
79
- return TAG.i64
80
- case "string":
81
- return TAG.string
82
- case "fixedBytes":
83
- return TAG.fixedBytes
84
- case "interval":
85
- return type.width === undefined ? TAG.interval : TAG.fixedInterval
86
- }
87
- }
88
-
89
- function checkAgainst(context: string, type: ValueTypeSpec, value: Value): void {
90
- switch (type.kind) {
91
- case "bool": {
92
- if (typeof value !== "boolean") {
93
- throw errors.new(`${context}: expected boolean`)
94
- }
95
- return
96
- }
97
- case "u64": {
98
- if (typeof value !== "bigint" || value < 0n || value > U64_MAX) {
99
- throw errors.new(`${context}: expected u64 bigint`)
100
- }
101
- return
102
- }
103
- case "i64": {
104
- if (typeof value !== "bigint" || value < I64_MIN || value > I64_MAX) {
105
- throw errors.new(`${context}: expected i64 bigint`)
106
- }
107
- return
108
- }
109
- case "string": {
110
- if (typeof value !== "string") {
111
- throw errors.new(`${context}: expected well-formed string`)
112
- }
113
- wellFormedUtf8(value)
114
- return
115
- }
116
- case "fixedBytes": {
117
- if (!(value instanceof Uint8Array) || value.length !== type.len) {
118
- throw errors.new(`${context}: expected ${type.len}-byte Uint8Array`)
119
- }
120
- return
121
- }
122
- case "interval": {
123
- if (!(typeof value === "object") || value instanceof Uint8Array) {
124
- throw errors.new(`${context}: expected interval value`)
125
- }
126
- const lo = type.element === "u64" ? 0n : I64_MIN
127
- const hi = type.element === "u64" ? U64_MAX : I64_MAX
128
- if (value.start < lo || value.end > hi || value.start >= value.end) {
129
- throw errors.new(`${context}: interval bounds out of range or empty`)
130
- }
131
- if (type.width !== undefined) {
132
- const parsed = fixedInterval(value.start, type.width, type.element)
133
- if (parsed === undefined) {
134
- throw errors.new(`${context}: fixed interval end is the domain ceiling`)
135
- }
136
- if (parsed.end !== value.end) {
137
- throw errors.new(`${context}: interval width must be ${type.width}`)
138
- }
139
- }
140
- return
141
- }
142
- }
143
- }
144
-
145
- /** The codec's tagged form: `tag u8` + payload, at the field's layout. */
146
- function writeTagged(out: ByteWriter, type: ValueTypeSpec, value: Value): void {
147
- switch (type.kind) {
148
- case "bool": {
149
- out.u8(TAG.bool)
150
- out.u8(value === true ? 1 : 0)
151
- return
152
- }
153
- case "u64": {
154
- out.u8(TAG.u64)
155
- out.u64le(value as bigint)
156
- return
157
- }
158
- case "i64": {
159
- out.u8(TAG.i64)
160
- out.i64le(value as bigint)
161
- return
162
- }
163
- case "string": {
164
- const text = wellFormedUtf8(value as string)
165
- const raw = utf8Encoder.encode(text)
166
- out.u8(TAG.string)
167
- out.u32le(raw.length)
168
- out.bytes(raw)
169
- return
170
- }
171
- case "fixedBytes": {
172
- out.u8(TAG.fixedBytes)
173
- out.bytes(value as Uint8Array)
174
- return
175
- }
176
- case "interval": {
177
- const interval = value as Interval
178
- if (type.width === undefined) {
179
- out.u8(TAG.interval)
180
- if (type.element === "u64") {
181
- out.u64le(interval.start)
182
- out.u64le(interval.end)
183
- } else {
184
- out.i64le(interval.start)
185
- out.i64le(interval.end)
186
- }
187
- return
188
- }
189
- out.u8(TAG.fixedInterval)
190
- if (type.element === "u64") {
191
- out.u64le(interval.start)
192
- } else {
193
- out.i64le(interval.start)
194
- }
195
- return
196
- }
197
- }
198
- }
199
-
200
- /** The value parser's refusal channel: one method per proved cause,
201
- * matching the Rust decoder's cross-implementation identities. */
202
- interface TaggedRefusal {
203
- badTag(expected: number, actual: number): never
204
- boolByte(byte: number): never
205
- invalidUtf8(): never
206
- emptyInterval(): never
207
- intervalOverflow(): never
208
- }
209
-
210
- /** Full parse at the layout's type; every illegal byte is a typed refusal. */
211
- function readTagged(reader: ByteReader, type: ValueTypeSpec, refusal: TaggedRefusal): Value {
212
- const expected = wireTagOf(type)
213
- const tag = reader.u8("value tag")
214
- if (tag !== expected) {
215
- refusal.badTag(expected, tag)
216
- }
217
- switch (type.kind) {
218
- case "bool": {
219
- const byte = reader.u8("bool payload")
220
- if (byte > 1) {
221
- refusal.boolByte(byte)
222
- }
223
- return byte === 1
224
- }
225
- case "u64":
226
- return reader.u64le("u64 payload")
227
- case "i64":
228
- return reader.i64le("i64 payload")
229
- case "string": {
230
- const len = reader.u32le("string length")
231
- const raw = reader.bytes(len, "string payload")
232
- const text = parseWellFormedUtf8(raw)
233
- if (text === undefined) {
234
- refusal.invalidUtf8()
235
- }
236
- return text
237
- }
238
- case "fixedBytes":
239
- return reader.bytes(type.len, "fixedBytes payload")
240
- case "interval": {
241
- if (type.width === undefined) {
242
- const start = type.element === "u64" ? reader.u64le("interval start") : reader.i64le("interval start")
243
- const end = type.element === "u64" ? reader.u64le("interval end") : reader.i64le("interval end")
244
- if (start >= end) {
245
- refusal.emptyInterval()
246
- }
247
- return { start, end }
248
- }
249
- const start = type.element === "u64" ? reader.u64le("interval start") : reader.i64le("interval start")
250
- const parsed = fixedInterval(start, type.width, type.element)
251
- if (parsed === undefined) {
252
- refusal.intervalOverflow()
253
- }
254
- return parsed
255
- }
256
- }
257
- }
258
-
259
- function valuesEqual(a: Value, b: Value): boolean {
260
- if (typeof a === "boolean" || typeof a === "bigint" || typeof a === "string") {
261
- return a === b
262
- }
263
- if (a instanceof Uint8Array) {
264
- return b instanceof Uint8Array && bytesEqual(a, b)
265
- }
266
- if (typeof b !== "object" || b instanceof Uint8Array) {
267
- return false
268
- }
269
- return a.start === b.start && a.end === b.end
270
- }
271
-
272
- /**
273
- * The engine's canonical big-endian literal form (`encode_literal`) —
274
- * the fingerprint mirror's alphabet. Strings never reach this encoder:
275
- * the fingerprint's `put_literal` length-prefixes them separately, and
276
- * closed ground axioms with string columns are the mirror's recorded gap.
277
- */
278
- function writeCanonicalLiteral(out: ByteWriter, type: ValueTypeSpec, value: Value): void {
279
- switch (type.kind) {
280
- case "bool": {
281
- out.u8(value === true ? 1 : 0)
282
- return
283
- }
284
- case "u64": {
285
- out.u64be(value as bigint)
286
- return
287
- }
288
- case "i64": {
289
- out.i64beFlipped(value as bigint)
290
- return
291
- }
292
- case "string":
293
- throw errors.new("canonical literal: strings are length-prefixed by the caller, never encoded here")
294
- case "fixedBytes": {
295
- const raw = value as Uint8Array
296
- const padded = Math.ceil(type.len / 8) * 8
297
- out.bytes(raw)
298
- for (let i = raw.length; i < padded; i++) {
299
- out.u8(0)
300
- }
301
- return
302
- }
303
- case "interval": {
304
- const interval = value as Interval
305
- if (type.width !== undefined) {
306
- if (type.element === "u64") {
307
- out.u64be(interval.start)
308
- } else {
309
- out.i64beFlipped(interval.start)
310
- }
311
- return
312
- }
313
- if (type.element === "u64") {
314
- out.u64be(interval.start)
315
- out.u64be(interval.end)
316
- } else {
317
- out.i64beFlipped(interval.start)
318
- out.i64beFlipped(interval.end)
319
- }
320
- return
321
- }
322
- }
323
- }
324
-
325
- export type { Interval, TaggedRefusal, Value, WellFormedUtf8 }
326
- export {
327
- checkAgainst,
328
- isInterval,
329
- readTagged,
330
- TAG,
331
- valuesEqual,
332
- wellFormedUtf8,
333
- wireTagOf,
334
- writeCanonicalLiteral,
335
- writeTagged
336
- }