@bcts/dcbor 1.0.0-alpha.10

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.
Files changed (45) hide show
  1. package/LICENSE +48 -0
  2. package/README.md +13 -0
  3. package/dist/index.cjs +9151 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +3107 -0
  6. package/dist/index.d.cts.map +1 -0
  7. package/dist/index.d.mts +3107 -0
  8. package/dist/index.d.mts.map +1 -0
  9. package/dist/index.iife.js +9155 -0
  10. package/dist/index.iife.js.map +1 -0
  11. package/dist/index.mjs +9027 -0
  12. package/dist/index.mjs.map +1 -0
  13. package/package.json +80 -0
  14. package/src/.claude-flow/metrics/agent-metrics.json +1 -0
  15. package/src/.claude-flow/metrics/performance.json +87 -0
  16. package/src/.claude-flow/metrics/task-metrics.json +10 -0
  17. package/src/byte-string.ts +300 -0
  18. package/src/cbor-codable.ts +170 -0
  19. package/src/cbor-tagged-codable.ts +72 -0
  20. package/src/cbor-tagged-decodable.ts +184 -0
  21. package/src/cbor-tagged-encodable.ts +138 -0
  22. package/src/cbor-tagged.ts +104 -0
  23. package/src/cbor.ts +869 -0
  24. package/src/conveniences.ts +840 -0
  25. package/src/date.ts +553 -0
  26. package/src/decode.ts +276 -0
  27. package/src/diag.ts +462 -0
  28. package/src/dump.ts +277 -0
  29. package/src/error.ts +259 -0
  30. package/src/exact.ts +714 -0
  31. package/src/float.ts +279 -0
  32. package/src/global.d.ts +34 -0
  33. package/src/globals.d.ts +0 -0
  34. package/src/index.ts +180 -0
  35. package/src/map.ts +308 -0
  36. package/src/prelude.ts +70 -0
  37. package/src/set.ts +515 -0
  38. package/src/simple.ts +153 -0
  39. package/src/stdlib.ts +55 -0
  40. package/src/string-util.ts +55 -0
  41. package/src/tag.ts +53 -0
  42. package/src/tags-store.ts +294 -0
  43. package/src/tags.ts +231 -0
  44. package/src/varint.ts +124 -0
  45. package/src/walk.ts +516 -0
package/src/set.ts ADDED
@@ -0,0 +1,515 @@
1
+ /**
2
+ * Set data structure for CBOR with tag(258) encoding.
3
+ *
4
+ * A Set is encoded as an array with no duplicate elements,
5
+ * tagged with tag(258) to indicate set semantics.
6
+ *
7
+ * @module set
8
+ */
9
+
10
+ import { type Cbor, MajorType, type CborInput } from "./cbor";
11
+ import { cbor, cborData } from "./cbor";
12
+ import { CborMap } from "./map";
13
+ import { createTag, type Tag } from "./tag";
14
+ import { TAG_SET } from "./tags";
15
+ import {
16
+ type CborTaggedEncodable,
17
+ type CborTaggedDecodable,
18
+ createTaggedCbor,
19
+ validateTag,
20
+ extractTaggedContent,
21
+ } from "./cbor-tagged";
22
+ import { extractCbor } from "./conveniences";
23
+ import { CborError } from "./error";
24
+
25
+ /**
26
+ * CBOR Set type with tag(258) encoding.
27
+ *
28
+ * Internally uses a CborMap to ensure unique elements with deterministic ordering.
29
+ * Elements are ordered by their CBOR encoding (lexicographic byte order).
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * // Create set
34
+ * const set = CborSet.fromArray([1, 2, 3]);
35
+ * const set2 = CborSet.fromSet(new Set([1, 2, 3]));
36
+ *
37
+ * // Add elements
38
+ * set.insert(4);
39
+ * set.insert(2); // Duplicate, no effect
40
+ *
41
+ * // Check membership
42
+ * console.log(set.contains(2)); // true
43
+ * console.log(set.contains(99)); // false
44
+ *
45
+ * // Encode to CBOR
46
+ * const tagged = set.taggedCbor();
47
+ * ```
48
+ */
49
+ export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet> {
50
+ readonly #map: CborMap;
51
+
52
+ constructor() {
53
+ this.#map = new CborMap();
54
+ }
55
+
56
+ // =========================================================================
57
+ // Factory Methods
58
+ // =========================================================================
59
+
60
+ /**
61
+ * Create CborSet from array.
62
+ *
63
+ * Duplicates are automatically removed.
64
+ *
65
+ * @param items - Array of items to add to the set
66
+ * @returns New CborSet instance
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * const set = CborSet.fromArray([1, 2, 3, 2, 1]);
71
+ * console.log(set.size); // 3
72
+ * ```
73
+ */
74
+ static fromArray<T extends CborInput>(items: T[]): CborSet {
75
+ const set = new CborSet();
76
+ for (const item of items) {
77
+ set.insert(item);
78
+ }
79
+ return set;
80
+ }
81
+
82
+ /**
83
+ * Create CborSet from JavaScript Set.
84
+ *
85
+ * @param items - JavaScript Set of items
86
+ * @returns New CborSet instance
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * const jsSet = new Set([1, 2, 3]);
91
+ * const cborSet = CborSet.fromSet(jsSet);
92
+ * ```
93
+ */
94
+ static fromSet<T extends CborInput>(items: Set<T>): CborSet {
95
+ return CborSet.fromArray(Array.from(items));
96
+ }
97
+
98
+ /**
99
+ * Create CborSet from iterable.
100
+ *
101
+ * @param items - Iterable of items
102
+ * @returns New CborSet instance
103
+ */
104
+ static fromIterable<T extends CborInput>(items: Iterable<T>): CborSet {
105
+ return CborSet.fromArray(Array.from(items));
106
+ }
107
+
108
+ // =========================================================================
109
+ // Core Methods
110
+ // =========================================================================
111
+
112
+ /**
113
+ * Insert an element into the set.
114
+ *
115
+ * If the element already exists, has no effect.
116
+ *
117
+ * @param value - Value to insert
118
+ *
119
+ * @example
120
+ * ```typescript
121
+ * const set = new CborSet();
122
+ * set.insert(1);
123
+ * set.insert(2);
124
+ * set.insert(1); // No effect, already exists
125
+ * ```
126
+ */
127
+ insert(value: CborInput): void {
128
+ const cborValue = encodeCborValue(value);
129
+ // In a set, key and value are the same
130
+ this.#map.set(cborValue, cborValue);
131
+ }
132
+
133
+ /**
134
+ * Check if set contains an element.
135
+ *
136
+ * @param value - Value to check
137
+ * @returns true if element is in the set
138
+ *
139
+ * @example
140
+ * ```typescript
141
+ * const set = CborSet.fromArray([1, 2, 3]);
142
+ * console.log(set.contains(2)); // true
143
+ * console.log(set.contains(99)); // false
144
+ * ```
145
+ */
146
+ contains(value: CborInput): boolean {
147
+ const cborValue = encodeCborValue(value);
148
+ return this.#map.has(cborValue);
149
+ }
150
+
151
+ /**
152
+ * Remove an element from the set.
153
+ *
154
+ * @param value - Value to remove
155
+ * @returns true if element was removed, false if not found
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * const set = CborSet.fromArray([1, 2, 3]);
160
+ * set.delete(2); // Returns true
161
+ * set.delete(99); // Returns false
162
+ * ```
163
+ */
164
+ delete(value: CborInput): boolean {
165
+ const cborValue = encodeCborValue(value);
166
+ return this.#map.delete(cborValue);
167
+ }
168
+
169
+ /**
170
+ * Remove all elements from the set.
171
+ */
172
+ clear(): void {
173
+ this.#map.clear();
174
+ }
175
+
176
+ /**
177
+ * Get the number of elements in the set.
178
+ *
179
+ * @returns Number of elements
180
+ */
181
+ get size(): number {
182
+ return this.#map.size;
183
+ }
184
+
185
+ /**
186
+ * Check if the set is empty.
187
+ *
188
+ * @returns true if set has no elements
189
+ */
190
+ isEmpty(): boolean {
191
+ return this.#map.size === 0;
192
+ }
193
+
194
+ // =========================================================================
195
+ // Set Operations
196
+ // =========================================================================
197
+
198
+ /**
199
+ * Create a new set containing elements in this set or the other set.
200
+ *
201
+ * @param other - Other set
202
+ * @returns New set with union of elements
203
+ *
204
+ * @example
205
+ * ```typescript
206
+ * const set1 = CborSet.fromArray([1, 2, 3]);
207
+ * const set2 = CborSet.fromArray([3, 4, 5]);
208
+ * const union = set1.union(set2);
209
+ * // union contains [1, 2, 3, 4, 5]
210
+ * ```
211
+ */
212
+ union(other: CborSet): CborSet {
213
+ const result = new CborSet();
214
+ for (const value of this) {
215
+ result.insert(extractCbor(value) as CborInput);
216
+ }
217
+ for (const value of other) {
218
+ result.insert(extractCbor(value) as CborInput);
219
+ }
220
+ return result;
221
+ }
222
+
223
+ /**
224
+ * Create a new set containing elements in both this set and the other set.
225
+ *
226
+ * @param other - Other set
227
+ * @returns New set with intersection of elements
228
+ *
229
+ * @example
230
+ * ```typescript
231
+ * const set1 = CborSet.fromArray([1, 2, 3]);
232
+ * const set2 = CborSet.fromArray([2, 3, 4]);
233
+ * const intersection = set1.intersection(set2);
234
+ * // intersection contains [2, 3]
235
+ * ```
236
+ */
237
+ intersection(other: CborSet): CborSet {
238
+ const result = new CborSet();
239
+ for (const value of this) {
240
+ const extracted = extractCbor(value) as CborInput;
241
+ if (other.contains(extracted)) {
242
+ result.insert(extracted);
243
+ }
244
+ }
245
+ return result;
246
+ }
247
+
248
+ /**
249
+ * Create a new set containing elements in this set but not in the other set.
250
+ *
251
+ * @param other - Other set
252
+ * @returns New set with difference of elements
253
+ *
254
+ * @example
255
+ * ```typescript
256
+ * const set1 = CborSet.fromArray([1, 2, 3]);
257
+ * const set2 = CborSet.fromArray([2, 3, 4]);
258
+ * const diff = set1.difference(set2);
259
+ * // diff contains [1]
260
+ * ```
261
+ */
262
+ difference(other: CborSet): CborSet {
263
+ const result = new CborSet();
264
+ for (const value of this) {
265
+ const extracted = extractCbor(value) as CborInput;
266
+ if (!other.contains(extracted)) {
267
+ result.insert(extracted);
268
+ }
269
+ }
270
+ return result;
271
+ }
272
+
273
+ /**
274
+ * Check if this set is a subset of another set.
275
+ *
276
+ * @param other - Other set
277
+ * @returns true if all elements of this set are in the other set
278
+ */
279
+ isSubsetOf(other: CborSet): boolean {
280
+ for (const value of this) {
281
+ if (!other.contains(extractCbor(value) as CborInput)) {
282
+ return false;
283
+ }
284
+ }
285
+ return true;
286
+ }
287
+
288
+ /**
289
+ * Check if this set is a superset of another set.
290
+ *
291
+ * @param other - Other set
292
+ * @returns true if all elements of the other set are in this set
293
+ */
294
+ isSupersetOf(other: CborSet): boolean {
295
+ return other.isSubsetOf(this);
296
+ }
297
+
298
+ // =========================================================================
299
+ // Iteration
300
+ // =========================================================================
301
+
302
+ /**
303
+ * Iterate over elements in the set.
304
+ *
305
+ * Elements are returned in deterministic order (by CBOR encoding).
306
+ *
307
+ * @example
308
+ * ```typescript
309
+ * const set = CborSet.fromArray([3, 1, 2]);
310
+ * for (const value of set) {
311
+ * console.log(extractCbor(value));
312
+ * }
313
+ * ```
314
+ */
315
+ *[Symbol.iterator](): Iterator<Cbor> {
316
+ for (const [_, value] of this.#map) {
317
+ yield value;
318
+ }
319
+ }
320
+
321
+ /**
322
+ * Get all values as an array.
323
+ *
324
+ * @returns Array of CBOR values in deterministic order
325
+ *
326
+ * @example
327
+ * ```typescript
328
+ * const set = CborSet.fromArray([3, 1, 2]);
329
+ * const values = set.values();
330
+ * // Values in deterministic order
331
+ * ```
332
+ */
333
+ values(): Cbor[] {
334
+ return Array.from(this);
335
+ }
336
+
337
+ /**
338
+ * Execute a function for each element.
339
+ *
340
+ * @param callback - Function to call for each element
341
+ *
342
+ * @example
343
+ * ```typescript
344
+ * set.forEach(value => {
345
+ * console.log(extractCbor(value));
346
+ * });
347
+ * ```
348
+ */
349
+ forEach(callback: (value: Cbor) => void): void {
350
+ for (const value of this) {
351
+ callback(value);
352
+ }
353
+ }
354
+
355
+ // =========================================================================
356
+ // CborTagged Implementation
357
+ // =========================================================================
358
+
359
+ cborTags(): Tag[] {
360
+ return [createTag(TAG_SET, "set")];
361
+ }
362
+
363
+ untaggedCbor(): Cbor {
364
+ // Encode as an array of values
365
+ const values = this.values();
366
+ return cbor(values);
367
+ }
368
+
369
+ taggedCbor(): Cbor {
370
+ return createTaggedCbor(this);
371
+ }
372
+
373
+ fromUntaggedCbor(c: Cbor): CborSet {
374
+ if (c.type !== MajorType.Array) {
375
+ throw new CborError({ type: "WrongType" });
376
+ }
377
+
378
+ this.clear();
379
+ for (const value of c.value) {
380
+ this.insert(extractCbor(value) as CborInput);
381
+ }
382
+
383
+ return this;
384
+ }
385
+
386
+ fromTaggedCbor(c: Cbor): CborSet {
387
+ const expectedTags = this.cborTags();
388
+ validateTag(c, expectedTags);
389
+ const content = extractTaggedContent(c);
390
+ return this.fromUntaggedCbor(content);
391
+ }
392
+
393
+ /**
394
+ * Decode a CborSet from tagged CBOR (static method).
395
+ *
396
+ * @param cbor - Tagged CBOR value with tag(258)
397
+ * @returns Decoded CborSet instance
398
+ */
399
+ static fromTaggedCborStatic(cbor: Cbor): CborSet {
400
+ return new CborSet().fromTaggedCbor(cbor);
401
+ }
402
+
403
+ // =========================================================================
404
+ // Conversion
405
+ // =========================================================================
406
+
407
+ /**
408
+ * Convert to CBOR array (untagged).
409
+ *
410
+ * @returns CBOR array
411
+ */
412
+ toCbor(): Cbor {
413
+ return this.untaggedCbor();
414
+ }
415
+
416
+ /**
417
+ * Convert to CBOR bytes (tagged).
418
+ *
419
+ * @returns Encoded CBOR bytes
420
+ */
421
+ toBytes(): Uint8Array {
422
+ return cborData(this.taggedCbor());
423
+ }
424
+
425
+ /**
426
+ * Convert to JavaScript Set.
427
+ *
428
+ * @returns JavaScript Set with extracted values
429
+ *
430
+ * @example
431
+ * ```typescript
432
+ * const cborSet = CborSet.fromArray([1, 2, 3]);
433
+ * const jsSet = cborSet.toSet();
434
+ * console.log(jsSet.has(1)); // true
435
+ * ```
436
+ */
437
+ toSet(): Set<unknown> {
438
+ const result = new Set();
439
+ for (const value of this) {
440
+ result.add(extractCbor(value));
441
+ }
442
+ return result;
443
+ }
444
+
445
+ /**
446
+ * Convert to JavaScript Array.
447
+ *
448
+ * @returns Array with extracted values
449
+ */
450
+ toArray(): unknown[] {
451
+ return Array.from(this.toSet());
452
+ }
453
+
454
+ // =========================================================================
455
+ // Display
456
+ // =========================================================================
457
+
458
+ /**
459
+ * Get diagnostic notation for the set.
460
+ *
461
+ * @returns String representation
462
+ *
463
+ * @example
464
+ * ```typescript
465
+ * const set = CborSet.fromArray([1, 2, 3]);
466
+ * console.log(set.diagnostic); // "[1, 2, 3]"
467
+ * ```
468
+ */
469
+ get diagnostic(): string {
470
+ const items = this.values()
471
+ .map((v) => {
472
+ const extracted = extractCbor(v);
473
+ if (typeof extracted === "string") {
474
+ return `"${extracted}"`;
475
+ }
476
+ return String(extracted);
477
+ })
478
+ .join(", ");
479
+ return `[${items}]`;
480
+ }
481
+
482
+ /**
483
+ * Convert to string (same as diagnostic).
484
+ *
485
+ * @returns String representation
486
+ */
487
+ toString(): string {
488
+ return this.diagnostic;
489
+ }
490
+
491
+ /**
492
+ * Convert to JSON (returns array of values).
493
+ *
494
+ * @returns Array for JSON serialization
495
+ */
496
+ toJSON(): unknown[] {
497
+ return this.toArray();
498
+ }
499
+ }
500
+
501
+ // ============================================================================
502
+ // Helper Functions
503
+ // ============================================================================
504
+
505
+ /**
506
+ * Convert a value to CBOR for use in set operations.
507
+ *
508
+ * @internal
509
+ */
510
+ function encodeCborValue(value: CborInput): Cbor {
511
+ if (typeof value === "object" && value !== null && "isCbor" in value && value.isCbor === true) {
512
+ return value as Cbor;
513
+ }
514
+ return cbor(value);
515
+ }
package/src/simple.ts ADDED
@@ -0,0 +1,153 @@
1
+ /**
2
+ * CBOR Simple Values (Major Type 7).
3
+ *
4
+ * @module simple
5
+ */
6
+
7
+ import { MajorType } from "./cbor";
8
+ import { encodeVarInt } from "./varint";
9
+ import { f64CborData } from "./float";
10
+
11
+ /**
12
+ * Represents CBOR simple values (major type 7).
13
+ *
14
+ * In CBOR, simple values are a special category that includes booleans (`true`
15
+ * and `false`), `null`, and floating point numbers.
16
+ *
17
+ * Per Section 2.4 of the dCBOR specification, only these specific simple
18
+ * values are valid in dCBOR. All other major type 7 values (such as undefined
19
+ * or other simple values) are invalid and will be rejected by dCBOR decoders.
20
+ *
21
+ * When encoding floating point values, dCBOR follows specific numeric
22
+ * reduction rules detailed in Section 2.3 of the dCBOR specification,
23
+ * including
24
+ * - Integral floating point values must be reduced to integers when possible
25
+ * - NaN values must be normalized to the canonical form `f97e00`
26
+ */
27
+ export type Simple =
28
+ | { readonly type: "False" }
29
+ | { readonly type: "True" }
30
+ | { readonly type: "Null" }
31
+ | { readonly type: "Float"; readonly value: number };
32
+
33
+ /**
34
+ * Returns the standard name of the simple value as a string.
35
+ *
36
+ * For `False`, `True`, and `Null`, this returns their lowercase string
37
+ * representation. For `Float` values, it returns their numeric representation.
38
+ */
39
+ export const simpleName = (simple: Simple): string => {
40
+ switch (simple.type) {
41
+ case "False":
42
+ return "false";
43
+ case "True":
44
+ return "true";
45
+ case "Null":
46
+ return "null";
47
+ case "Float": {
48
+ const v = simple.value;
49
+ if (Number.isNaN(v)) {
50
+ return "NaN";
51
+ } else if (!Number.isFinite(v)) {
52
+ return v > 0 ? "Infinity" : "-Infinity";
53
+ } else {
54
+ return String(v);
55
+ }
56
+ }
57
+ }
58
+ };
59
+
60
+ /**
61
+ * Checks if the simple value is a floating point number.
62
+ */
63
+ export const isFloat = (simple: Simple): simple is { type: "Float"; value: number } =>
64
+ simple.type === "Float";
65
+
66
+ /**
67
+ * Checks if the simple value is the NaN (Not a Number) representation.
68
+ */
69
+ export const isNaN = (simple: Simple): boolean =>
70
+ simple.type === "Float" && Number.isNaN(simple.value);
71
+
72
+ /**
73
+ * Encodes the simple value to its raw CBOR byte representation.
74
+ *
75
+ * Returns the CBOR bytes that represent this simple value according to the
76
+ * dCBOR deterministic encoding rules:
77
+ * - `False` encodes as `0xf4`
78
+ * - `True` encodes as `0xf5`
79
+ * - `Null` encodes as `0xf6`
80
+ * - `Float` values encode according to the IEEE 754 floating point rules,
81
+ * using the shortest representation that preserves precision.
82
+ */
83
+ export const simpleCborData = (simple: Simple): Uint8Array => {
84
+ switch (simple.type) {
85
+ case "False":
86
+ return encodeVarInt(20, MajorType.Simple);
87
+ case "True":
88
+ return encodeVarInt(21, MajorType.Simple);
89
+ case "Null":
90
+ return encodeVarInt(22, MajorType.Simple);
91
+ case "Float":
92
+ return f64CborData(simple.value);
93
+ }
94
+ };
95
+
96
+ /**
97
+ * Compare two Simple values for equality.
98
+ *
99
+ * Two `Simple` values are equal if they're the same variant. For `Float`
100
+ * variants, the contained floating point values are compared for equality,
101
+ * with NaN values considered equal to each other.
102
+ */
103
+ export const simpleEquals = (a: Simple, b: Simple): boolean => {
104
+ if (a.type !== b.type) return false;
105
+
106
+ switch (a.type) {
107
+ case "False":
108
+ case "True":
109
+ case "Null":
110
+ return true;
111
+ case "Float": {
112
+ const bFloat = b as { type: "Float"; value: number };
113
+ const v1 = a.value;
114
+ const v2 = bFloat.value;
115
+ return v1 === v2 || (Number.isNaN(v1) && Number.isNaN(v2));
116
+ }
117
+ }
118
+ };
119
+
120
+ /**
121
+ * Hash a Simple value.
122
+ *
123
+ * Matches Rust's Hash trait implementation.
124
+ */
125
+ export const simpleHash = (simple: Simple): number => {
126
+ // Simple FNV-1a hash
127
+ let hash = 2166136261;
128
+
129
+ switch (simple.type) {
130
+ case "False":
131
+ hash ^= 0;
132
+ break;
133
+ case "True":
134
+ hash ^= 1;
135
+ break;
136
+ case "Null":
137
+ hash ^= 2;
138
+ break;
139
+ case "Float": {
140
+ // Hash the bit representation of the float
141
+ const buffer = new ArrayBuffer(8);
142
+ const view = new DataView(buffer);
143
+ view.setFloat64(0, simple.value, true);
144
+ for (let i = 0; i < 8; i++) {
145
+ hash ^= view.getUint8(i);
146
+ hash = Math.imul(hash, 16777619);
147
+ }
148
+ break;
149
+ }
150
+ }
151
+
152
+ return hash >>> 0;
153
+ };
package/src/stdlib.ts ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Standard library re-exports and compatibility layer.
3
+ *
4
+ * In Rust, this handles std/no_std feature flags.
5
+ * In TypeScript, this is primarily documentation.
6
+ *
7
+ * @module stdlib
8
+ */
9
+
10
+ import { CborError } from "./error";
11
+
12
+ /**
13
+ * Concatenate multiple byte arrays into one.
14
+ */
15
+ export const concatBytes = (arrays: Uint8Array[]): Uint8Array => {
16
+ const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
17
+ const result = new Uint8Array(totalLength);
18
+ let offset = 0;
19
+ for (const arr of arrays) {
20
+ result.set(arr, offset);
21
+ offset += arr.length;
22
+ }
23
+ return result;
24
+ };
25
+
26
+ /**
27
+ * Check if two byte arrays are equal.
28
+ */
29
+ export const areBytesEqual = (a: Uint8Array, b: Uint8Array): boolean => {
30
+ if (a.length !== b.length) return false;
31
+ for (let i = 0; i < a.length; i++) {
32
+ if (a[i] !== b[i]) return false;
33
+ }
34
+ return true;
35
+ };
36
+
37
+ /**
38
+ * Lexicographically compare two byte arrays.
39
+ * Returns: -1 if a < b, 0 if a == b, 1 if a > b
40
+ */
41
+ export const lexicographicallyCompareBytes = (a: Uint8Array, b: Uint8Array): number => {
42
+ const minLen = Math.min(a.length, b.length);
43
+ for (let i = 0; i < minLen; i++) {
44
+ const aVal = a[i];
45
+ const bVal = b[i];
46
+ if (aVal === undefined || bVal === undefined) {
47
+ throw new CborError({ type: "Custom", message: "Unexpected undefined byte in array" });
48
+ }
49
+ if (aVal < bVal) return -1;
50
+ if (aVal > bVal) return 1;
51
+ }
52
+ if (a.length < b.length) return -1;
53
+ if (a.length > b.length) return 1;
54
+ return 0;
55
+ };