@bcts/dcbor 1.0.0-alpha.8 → 1.0.0-beta.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/LICENSE +3 -2
- package/README.md +1 -1
- package/dist/index.cjs +1941 -1497
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +613 -327
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +613 -327
- package/dist/index.d.mts.map +1 -1
- package/dist/index.iife.js +2149 -1754
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +1932 -1511
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -16
- package/src/bignum.ts +347 -0
- package/src/byte-string.ts +21 -17
- package/src/cbor-codable.ts +4 -0
- package/src/cbor-tagged-codable.ts +4 -0
- package/src/cbor-tagged-decodable.ts +33 -5
- package/src/cbor-tagged-encodable.ts +15 -0
- package/src/cbor-tagged.ts +11 -1
- package/src/cbor.ts +73 -18
- package/src/conveniences.ts +23 -5
- package/src/date.ts +35 -28
- package/src/decode.ts +13 -0
- package/src/diag.ts +233 -196
- package/src/dump.ts +18 -7
- package/src/error.ts +4 -0
- package/src/exact.ts +4 -0
- package/src/float.ts +25 -6
- package/src/global.d.ts +4 -0
- package/src/globals.d.ts +5 -0
- package/src/index.ts +65 -13
- package/src/map.ts +27 -23
- package/src/prelude.ts +12 -2
- package/src/set.ts +37 -10
- package/src/simple.ts +15 -2
- package/src/sortable.ts +70 -0
- package/src/stdlib.ts +4 -0
- package/src/string-util.ts +4 -0
- package/src/tag.ts +51 -2
- package/src/tags-store.ts +53 -68
- package/src/tags.ts +68 -6
- package/src/varint.ts +16 -11
- package/src/walk.ts +77 -281
package/src/cbor.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright © 2023-2026 Blockchain Commons, LLC
|
|
3
|
+
* Copyright © 2025-2026 Parity Technologies
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
import { CborMap } from "./map";
|
|
2
8
|
import type { Simple } from "./simple";
|
|
3
9
|
import { simpleCborData, isFloat as isSimpleFloat } from "./simple";
|
|
@@ -11,8 +17,7 @@ import type { ByteString } from "./byte-string";
|
|
|
11
17
|
import type { CborDate } from "./date";
|
|
12
18
|
import { diagnosticOpt } from "./diag";
|
|
13
19
|
import { decodeCbor } from "./decode";
|
|
14
|
-
import type
|
|
15
|
-
import { getGlobalTagsStore } from "./tags-store";
|
|
20
|
+
import { getGlobalTagsStore, type TagsStore } from "./tags-store";
|
|
16
21
|
import type { Visitor } from "./walk";
|
|
17
22
|
import { walk } from "./walk";
|
|
18
23
|
import { CborError } from "./error";
|
|
@@ -250,7 +255,7 @@ export interface CborMethods {
|
|
|
250
255
|
* @param initialState - Initial state for the visitor
|
|
251
256
|
* @param visitor - Visitor function called for each element
|
|
252
257
|
*/
|
|
253
|
-
walk<State>(initialState: State, visitor: Visitor<State>):
|
|
258
|
+
walk<State>(initialState: State, visitor: Visitor<State>): void;
|
|
254
259
|
/**
|
|
255
260
|
* Validate that value has one of the expected tags.
|
|
256
261
|
* @param expectedTags - Array of expected tag values
|
|
@@ -290,6 +295,40 @@ export interface TaggedCborEncodable {
|
|
|
290
295
|
/**
|
|
291
296
|
* Type guard to check if value has taggedCbor method.
|
|
292
297
|
*/
|
|
298
|
+
/**
|
|
299
|
+
* Resolve a numeric/bigint tag value to a `Tag` object, looking up the
|
|
300
|
+
* canonical name from the global tags store (matches Rust's
|
|
301
|
+
* `try_into_tagged_value` returning the stored `Tag`). Falls back to a
|
|
302
|
+
* name-less `{ value }` if no name is registered — never synthesizes a
|
|
303
|
+
* placeholder `tag-${value}` string.
|
|
304
|
+
*/
|
|
305
|
+
const resolveTag = (value: number | bigint): Tag => {
|
|
306
|
+
const stored = getGlobalTagsStore().tagForValue(value);
|
|
307
|
+
if (stored !== undefined) return stored;
|
|
308
|
+
return { value };
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Structural CBOR value equality.
|
|
313
|
+
*
|
|
314
|
+
* Mirrors Rust's `derive(PartialEq) for CBOR`. dCBOR encoding is
|
|
315
|
+
* deterministic, so two CBOR values are equal iff they encode to the
|
|
316
|
+
* same byte sequence — this is the simplest correct comparator.
|
|
317
|
+
*
|
|
318
|
+
* Use this rather than `===` (which compares JS object references) when
|
|
319
|
+
* you need value equality across two `Cbor` instances built independently.
|
|
320
|
+
*/
|
|
321
|
+
export const cborEquals = (a: Cbor, b: Cbor): boolean => {
|
|
322
|
+
if (a === b) return true;
|
|
323
|
+
const aBytes = a.toData();
|
|
324
|
+
const bBytes = b.toData();
|
|
325
|
+
if (aBytes.length !== bBytes.length) return false;
|
|
326
|
+
for (let i = 0; i < aBytes.length; i++) {
|
|
327
|
+
if (aBytes[i] !== bBytes[i]) return false;
|
|
328
|
+
}
|
|
329
|
+
return true;
|
|
330
|
+
};
|
|
331
|
+
|
|
293
332
|
const hasTaggedCbor = (value: unknown): value is TaggedCborEncodable => {
|
|
294
333
|
return (
|
|
295
334
|
typeof value === "object" &&
|
|
@@ -337,6 +376,20 @@ export const cbor = (value: CborInput): Cbor => {
|
|
|
337
376
|
result = { isCbor: true, type: MajorType.Simple, value: { type: "Float", value: Infinity } };
|
|
338
377
|
} else if (value == -Infinity) {
|
|
339
378
|
result = { isCbor: true, type: MajorType.Simple, value: { type: "Float", value: -Infinity } };
|
|
379
|
+
} else if (typeof value === "number" && !Number.isSafeInteger(value)) {
|
|
380
|
+
// Mirrors Rust `f64::exact_from_f64`: any finite, integer-valued
|
|
381
|
+
// float that exceeds the safe-integer range (so adjacent integers
|
|
382
|
+
// can't be distinguished, e.g. `1e21`) cannot be encoded as a
|
|
383
|
+
// canonical integer. Route to Float instead — Rust's `From<f64>
|
|
384
|
+
// for CBOR` does the same fallback.
|
|
385
|
+
result = { isCbor: true, type: MajorType.Simple, value: { type: "Float", value: value } };
|
|
386
|
+
} else if (
|
|
387
|
+
typeof value === "bigint" &&
|
|
388
|
+
(value > 0xffffffffffffffffn || value < -0x10000000000000000n)
|
|
389
|
+
) {
|
|
390
|
+
// bigint outside the [-(2^64), 2^64 - 1] CBOR-encodable integer
|
|
391
|
+
// range. Surface immediately rather than crashing in encodeVarInt.
|
|
392
|
+
throw new CborError({ type: "OutOfRange" });
|
|
340
393
|
} else if (value < 0) {
|
|
341
394
|
// Store the magnitude to encode, matching Rust's representation
|
|
342
395
|
// For a negative value n, CBOR encodes it as -1-n, so we store -n-1
|
|
@@ -642,8 +695,7 @@ export const attachMethods = <T extends Omit<Cbor, keyof CborMethods>>(obj: T):
|
|
|
642
695
|
if (this.type !== MajorType.Tagged) {
|
|
643
696
|
return undefined;
|
|
644
697
|
}
|
|
645
|
-
|
|
646
|
-
return [tag, this.value];
|
|
698
|
+
return [resolveTag(this.tag), this.value];
|
|
647
699
|
},
|
|
648
700
|
asBool(this: Cbor): boolean | undefined {
|
|
649
701
|
if (this.type !== MajorType.Simple) return undefined;
|
|
@@ -720,8 +772,7 @@ export const attachMethods = <T extends Omit<Cbor, keyof CborMethods>>(obj: T):
|
|
|
720
772
|
`Cannot convert CBOR to Tagged: expected Tagged type, got ${getMajorTypeName(this.type)}`,
|
|
721
773
|
);
|
|
722
774
|
}
|
|
723
|
-
|
|
724
|
-
return [tag, this.value];
|
|
775
|
+
return [resolveTag(this.tag), this.value];
|
|
725
776
|
},
|
|
726
777
|
toBool(this: Cbor): boolean {
|
|
727
778
|
const result = this.asBool();
|
|
@@ -762,33 +813,37 @@ export const attachMethods = <T extends Omit<Cbor, keyof CborMethods>>(obj: T):
|
|
|
762
813
|
if (this.type !== MajorType.Tagged) {
|
|
763
814
|
throw new CborError({ type: "WrongType" });
|
|
764
815
|
}
|
|
765
|
-
const
|
|
766
|
-
typeof expectedTag === "object" && "value" in expectedTag
|
|
767
|
-
|
|
816
|
+
const expected: Tag =
|
|
817
|
+
typeof expectedTag === "object" && "value" in expectedTag
|
|
818
|
+
? expectedTag
|
|
819
|
+
: { value: expectedTag };
|
|
820
|
+
if (this.tag !== expected.value) {
|
|
821
|
+
// Mirror Rust `Error::WrongTag(expected, actual)`.
|
|
768
822
|
throw new CborError({
|
|
769
|
-
type: "
|
|
770
|
-
|
|
823
|
+
type: "WrongTag",
|
|
824
|
+
expected,
|
|
825
|
+
actual: { value: this.tag },
|
|
771
826
|
});
|
|
772
827
|
}
|
|
773
828
|
return this.value;
|
|
774
829
|
},
|
|
775
830
|
|
|
776
831
|
// Advanced operations
|
|
777
|
-
walk<State>(this: Cbor, initialState: State, visitor: Visitor<State>):
|
|
778
|
-
|
|
832
|
+
walk<State>(this: Cbor, initialState: State, visitor: Visitor<State>): void {
|
|
833
|
+
walk(this, initialState, visitor);
|
|
779
834
|
},
|
|
780
835
|
validateTag(this: Cbor, expectedTags: Tag[]): Tag {
|
|
781
836
|
if (this.type !== MajorType.Tagged) {
|
|
782
837
|
throw new CborError({ type: "WrongType" });
|
|
783
838
|
}
|
|
784
|
-
const expectedValues = expectedTags.map((t) => t.value);
|
|
785
839
|
const tagValue = this.tag;
|
|
786
840
|
const matchingTag = expectedTags.find((t) => t.value === tagValue);
|
|
787
841
|
if (matchingTag === undefined) {
|
|
788
|
-
|
|
842
|
+
// Mirror Rust `Error::WrongTag(expected, actual)`.
|
|
789
843
|
throw new CborError({
|
|
790
|
-
type: "
|
|
791
|
-
|
|
844
|
+
type: "WrongTag",
|
|
845
|
+
expected: expectedTags[0],
|
|
846
|
+
actual: { value: tagValue },
|
|
792
847
|
});
|
|
793
848
|
}
|
|
794
849
|
return matchingTag;
|
package/src/conveniences.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* Copyright © 2023-2026 Blockchain Commons, LLC
|
|
3
|
+
* Copyright © 2025-2026 Parity Technologies
|
|
4
|
+
*
|
|
5
|
+
*
|
|
2
6
|
* Convenience utilities for working with CBOR values.
|
|
3
7
|
*
|
|
4
8
|
* Provides type-safe helpers for checking types, extracting values,
|
|
@@ -738,17 +742,26 @@ export const getTaggedContent = (cbor: Cbor, tag: number | bigint): Cbor | undef
|
|
|
738
742
|
/**
|
|
739
743
|
* Extract content if has specific tag, throwing if not.
|
|
740
744
|
*
|
|
745
|
+
* Mirrors Rust `try_into_expected_tagged_value`. Throws `{ type: "WrongType" }`
|
|
746
|
+
* if `cbor` is not tagged at all, otherwise `{ type: "WrongTag", expected,
|
|
747
|
+
* actual }` if the tag doesn't match.
|
|
748
|
+
*
|
|
741
749
|
* @param cbor - CBOR value
|
|
742
750
|
* @param tag - Expected tag value
|
|
743
751
|
* @returns Tagged content
|
|
744
|
-
* @throws {CborError} With type 'WrongType' if cbor is not tagged with the expected tag
|
|
745
752
|
*/
|
|
746
753
|
export const expectTaggedContent = (cbor: Cbor, tag: number | bigint): Cbor => {
|
|
747
|
-
|
|
748
|
-
if (content === undefined) {
|
|
754
|
+
if (cbor.type !== MajorType.Tagged) {
|
|
749
755
|
throw new CborError({ type: "WrongType" });
|
|
750
756
|
}
|
|
751
|
-
|
|
757
|
+
if (cbor.tag !== tag) {
|
|
758
|
+
throw new CborError({
|
|
759
|
+
type: "WrongTag",
|
|
760
|
+
expected: { value: tag },
|
|
761
|
+
actual: { value: cbor.tag },
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
return cbor.value;
|
|
752
765
|
};
|
|
753
766
|
|
|
754
767
|
// ============================================================================
|
|
@@ -757,6 +770,7 @@ export const expectTaggedContent = (cbor: Cbor, tag: number | bigint): Cbor => {
|
|
|
757
770
|
// ============================================================================
|
|
758
771
|
|
|
759
772
|
import type { Tag } from "./tag";
|
|
773
|
+
import { getGlobalTagsStore } from "./tags-store";
|
|
760
774
|
|
|
761
775
|
/**
|
|
762
776
|
* Extract tagged value as tuple [Tag, Cbor] if CBOR is tagged.
|
|
@@ -769,7 +783,11 @@ export const asTaggedValue = (cbor: Cbor): [Tag, Cbor] | undefined => {
|
|
|
769
783
|
if (cbor.type !== MajorType.Tagged) {
|
|
770
784
|
return undefined;
|
|
771
785
|
}
|
|
772
|
-
|
|
786
|
+
// Mirrors Rust `try_into_tagged_value` which returns the stored `Tag`.
|
|
787
|
+
// Resolve the canonical name (if any) via the global tags store rather
|
|
788
|
+
// than synthesizing a `tag-${value}` placeholder.
|
|
789
|
+
const resolved = getGlobalTagsStore().tagForValue(cbor.tag);
|
|
790
|
+
const tag: Tag = resolved ?? { value: cbor.tag };
|
|
773
791
|
return [tag, cbor.value];
|
|
774
792
|
};
|
|
775
793
|
|
package/src/date.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* Copyright © 2023-2026 Blockchain Commons, LLC
|
|
3
|
+
* Copyright © 2025-2026 Parity Technologies
|
|
4
|
+
*
|
|
5
|
+
*
|
|
2
6
|
* Date/time support for CBOR with tag(1) encoding.
|
|
3
7
|
*
|
|
4
8
|
* A CBOR-friendly representation of a date and time.
|
|
@@ -67,7 +71,20 @@ import { CborError } from "./error";
|
|
|
67
71
|
* ```
|
|
68
72
|
*/
|
|
69
73
|
export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDecodable<CborDate> {
|
|
70
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Canonical timestamp in seconds since the Unix epoch as a JS `number`
|
|
76
|
+
* (`f64`). dCBOR encodes Date (tag 1) as a numeric value in seconds, so
|
|
77
|
+
* keeping `_seconds` as the source of truth avoids the millisecond-only
|
|
78
|
+
* round-trip precision loss that going through a JS `Date` instance
|
|
79
|
+
* introduced in earlier versions of this port.
|
|
80
|
+
*
|
|
81
|
+
* f64 still bounds the achievable precision (~16 decimal digits, so
|
|
82
|
+
* roughly microseconds for current epoch values); Rust's
|
|
83
|
+
* `chrono::DateTime<Utc>` retains nanoseconds in memory but encodes
|
|
84
|
+
* to the same f64 over the wire, so the *encode/decode round-trip* is
|
|
85
|
+
* byte-identical.
|
|
86
|
+
*/
|
|
87
|
+
private _seconds: number;
|
|
71
88
|
|
|
72
89
|
/**
|
|
73
90
|
* Creates a new `CborDate` from the given JavaScript `Date`.
|
|
@@ -87,7 +104,7 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
87
104
|
*/
|
|
88
105
|
static fromDatetime(dateTime: Date): CborDate {
|
|
89
106
|
const instance = new CborDate();
|
|
90
|
-
instance
|
|
107
|
+
instance._seconds = dateTime.getTime() / 1000;
|
|
91
108
|
return instance;
|
|
92
109
|
}
|
|
93
110
|
|
|
@@ -174,10 +191,9 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
174
191
|
* ```
|
|
175
192
|
*/
|
|
176
193
|
static fromTimestamp(secondsSinceUnixEpoch: number): CborDate {
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
return CborDate.fromDatetime(new Date(milliseconds));
|
|
194
|
+
const instance = new CborDate();
|
|
195
|
+
instance._seconds = secondsSinceUnixEpoch;
|
|
196
|
+
return instance;
|
|
181
197
|
}
|
|
182
198
|
|
|
183
199
|
/**
|
|
@@ -209,7 +225,7 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
209
225
|
// Try parsing as ISO 8601 date string
|
|
210
226
|
const dt = new Date(value);
|
|
211
227
|
if (isNaN(dt.getTime())) {
|
|
212
|
-
throw new CborError({ type: "InvalidDate", message:
|
|
228
|
+
throw new CborError({ type: "InvalidDate", message: "Invalid date string" });
|
|
213
229
|
}
|
|
214
230
|
return CborDate.fromDatetime(dt);
|
|
215
231
|
}
|
|
@@ -265,7 +281,7 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
265
281
|
* ```
|
|
266
282
|
*/
|
|
267
283
|
datetime(): Date {
|
|
268
|
-
return new Date(this
|
|
284
|
+
return new Date(this._seconds * 1000);
|
|
269
285
|
}
|
|
270
286
|
|
|
271
287
|
/**
|
|
@@ -285,9 +301,7 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
285
301
|
* ```
|
|
286
302
|
*/
|
|
287
303
|
timestamp(): number {
|
|
288
|
-
|
|
289
|
-
const msecs = this.#datetime.getTime() % 1000;
|
|
290
|
-
return wholeSecondsSinceUnixEpoch + msecs / 1000.0;
|
|
304
|
+
return this._seconds;
|
|
291
305
|
}
|
|
292
306
|
|
|
293
307
|
/**
|
|
@@ -415,22 +429,17 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
415
429
|
if (cbor.value.type === "Float") {
|
|
416
430
|
timestamp = cbor.value.value;
|
|
417
431
|
} else {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
});
|
|
432
|
+
// Mirrors Rust `f64::try_from(CBOR)` returning `Error::WrongType`
|
|
433
|
+
// for non-numeric / non-Float Simple values.
|
|
434
|
+
throw new CborError({ type: "WrongType" });
|
|
422
435
|
}
|
|
423
436
|
break;
|
|
424
437
|
|
|
425
438
|
default:
|
|
426
|
-
throw new CborError({
|
|
427
|
-
type: "Custom",
|
|
428
|
-
message: "Invalid date CBOR: expected numeric value",
|
|
429
|
-
});
|
|
439
|
+
throw new CborError({ type: "WrongType" });
|
|
430
440
|
}
|
|
431
441
|
|
|
432
|
-
|
|
433
|
-
this.#datetime = date.#datetime;
|
|
442
|
+
this._seconds = timestamp;
|
|
434
443
|
return this;
|
|
435
444
|
}
|
|
436
445
|
|
|
@@ -495,7 +504,7 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
495
504
|
* ```
|
|
496
505
|
*/
|
|
497
506
|
toString(): string {
|
|
498
|
-
const dt = this
|
|
507
|
+
const dt = new Date(this._seconds * 1000);
|
|
499
508
|
// Check only hours, minutes, and seconds (not milliseconds) to match Rust behavior
|
|
500
509
|
const hasTime = dt.getUTCHours() !== 0 || dt.getUTCMinutes() !== 0 || dt.getUTCSeconds() !== 0;
|
|
501
510
|
|
|
@@ -521,7 +530,7 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
521
530
|
* @returns true if dates represent the same moment in time
|
|
522
531
|
*/
|
|
523
532
|
equals(other: CborDate): boolean {
|
|
524
|
-
return this
|
|
533
|
+
return this._seconds === other._seconds;
|
|
525
534
|
}
|
|
526
535
|
|
|
527
536
|
/**
|
|
@@ -531,10 +540,8 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
531
540
|
* @returns -1 if this < other, 0 if equal, 1 if this > other
|
|
532
541
|
*/
|
|
533
542
|
compare(other: CborDate): number {
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
if (thisTime < otherTime) return -1;
|
|
537
|
-
if (thisTime > otherTime) return 1;
|
|
543
|
+
if (this._seconds < other._seconds) return -1;
|
|
544
|
+
if (this._seconds > other._seconds) return 1;
|
|
538
545
|
return 0;
|
|
539
546
|
}
|
|
540
547
|
|
|
@@ -548,6 +555,6 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
548
555
|
}
|
|
549
556
|
|
|
550
557
|
private constructor() {
|
|
551
|
-
this
|
|
558
|
+
this._seconds = Date.now() / 1000;
|
|
552
559
|
}
|
|
553
560
|
}
|
package/src/decode.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright © 2023-2026 Blockchain Commons, LLC
|
|
3
|
+
* Copyright © 2025-2026 Parity Technologies
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
import {
|
|
2
8
|
type Cbor,
|
|
3
9
|
type CborNumber,
|
|
@@ -201,6 +207,13 @@ function decodeCborInternal(data: DataView): { cbor: Cbor; len: number } {
|
|
|
201
207
|
switch (varIntLen) {
|
|
202
208
|
case 3: {
|
|
203
209
|
const f = binary16ToNumber(new Uint8Array(data.buffer, data.byteOffset + 1, 2));
|
|
210
|
+
// dCBOR canonical-encoding check via re-encode-and-compare. JS's
|
|
211
|
+
// `Number` type does not preserve NaN payload bits — every NaN
|
|
212
|
+
// collapses to the same value — so we cannot port Rust's
|
|
213
|
+
// `validate_canonical_f16(n)`'s bit-level check directly.
|
|
214
|
+
// Re-encoding round-trips through the canonicalising encoder,
|
|
215
|
+
// catching every non-canonical NaN, ±Infinity, and
|
|
216
|
+
// integer-reducible float. See float.ts for the encoder rules.
|
|
204
217
|
checkCanonicalEncoding(f, new Uint8Array(data.buffer, data.byteOffset, varIntLen));
|
|
205
218
|
const cborObj = {
|
|
206
219
|
isCbor: true,
|