@bcts/dcbor 1.0.0-alpha.16 → 1.0.0-alpha.18
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/README.md +1 -1
- package/dist/index.cjs +789 -474
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +160 -23
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +160 -23
- package/dist/index.d.mts.map +1 -1
- package/dist/index.iife.js +789 -474
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +797 -490
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -7
- package/src/bignum.ts +334 -0
- package/src/byte-string.ts +17 -17
- package/src/date.ts +11 -11
- package/src/index.ts +10 -0
- package/src/map.ts +23 -23
- package/src/prelude.ts +3 -0
- package/src/set.ts +9 -9
- package/src/tags-store.ts +17 -17
- package/src/tags.ts +46 -0
package/src/map.ts
CHANGED
|
@@ -44,14 +44,14 @@ export interface MapEntry {
|
|
|
44
44
|
* encoded CBOR representation, ensuring deterministic encoding.
|
|
45
45
|
*/
|
|
46
46
|
export class CborMap {
|
|
47
|
-
|
|
47
|
+
private _dict: SortedMap<MapKey, MapEntry>;
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* Creates a new, empty CBOR Map.
|
|
51
51
|
* Optionally initializes from a JavaScript Map.
|
|
52
52
|
*/
|
|
53
53
|
constructor(map?: Map<unknown, unknown>) {
|
|
54
|
-
this
|
|
54
|
+
this._dict = new SortedMap(null, areBytesEqual, lexicographicallyCompareBytes);
|
|
55
55
|
|
|
56
56
|
if (map !== undefined) {
|
|
57
57
|
for (const [key, value] of map.entries()) {
|
|
@@ -76,7 +76,7 @@ export class CborMap {
|
|
|
76
76
|
const keyCbor = cbor(key);
|
|
77
77
|
const valueCbor = cbor(value);
|
|
78
78
|
const keyData = cborData(keyCbor);
|
|
79
|
-
this
|
|
79
|
+
this._dict.set(keyData, { key: keyCbor, value: valueCbor });
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/**
|
|
@@ -86,7 +86,7 @@ export class CborMap {
|
|
|
86
86
|
this.set(key, value);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
private _makeKey<K extends CborInput>(key: K): MapKey {
|
|
90
90
|
const keyCbor = cbor(key);
|
|
91
91
|
return cborData(keyCbor);
|
|
92
92
|
}
|
|
@@ -97,8 +97,8 @@ export class CborMap {
|
|
|
97
97
|
* Matches Rust's Map::get().
|
|
98
98
|
*/
|
|
99
99
|
get<K extends CborInput, V>(key: K): V | undefined {
|
|
100
|
-
const keyData = this
|
|
101
|
-
const value = this
|
|
100
|
+
const keyData = this._makeKey(key);
|
|
101
|
+
const value = this._dict.get(keyData);
|
|
102
102
|
if (value === undefined) {
|
|
103
103
|
return undefined;
|
|
104
104
|
}
|
|
@@ -124,24 +124,24 @@ export class CborMap {
|
|
|
124
124
|
* Matches Rust's Map::contains_key().
|
|
125
125
|
*/
|
|
126
126
|
containsKey<K extends CborInput>(key: K): boolean {
|
|
127
|
-
const keyData = this
|
|
128
|
-
return this
|
|
127
|
+
const keyData = this._makeKey(key);
|
|
128
|
+
return this._dict.has(keyData);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
delete<K extends CborInput>(key: K): boolean {
|
|
132
|
-
const keyData = this
|
|
133
|
-
const existed = this
|
|
134
|
-
this
|
|
132
|
+
const keyData = this._makeKey(key);
|
|
133
|
+
const existed = this._dict.has(keyData);
|
|
134
|
+
this._dict.delete(keyData);
|
|
135
135
|
return existed;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
has<K extends CborInput>(key: K): boolean {
|
|
139
|
-
const keyData = this
|
|
140
|
-
return this
|
|
139
|
+
const keyData = this._makeKey(key);
|
|
140
|
+
return this._dict.has(keyData);
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
clear(): void {
|
|
144
|
-
this
|
|
144
|
+
this._dict = new SortedMap(null, areBytesEqual, lexicographicallyCompareBytes);
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
/**
|
|
@@ -149,7 +149,7 @@ export class CborMap {
|
|
|
149
149
|
* Matches Rust's Map::len().
|
|
150
150
|
*/
|
|
151
151
|
get length(): number {
|
|
152
|
-
return this
|
|
152
|
+
return this._dict.length;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
/**
|
|
@@ -157,7 +157,7 @@ export class CborMap {
|
|
|
157
157
|
* Also matches Rust's Map::len().
|
|
158
158
|
*/
|
|
159
159
|
get size(): number {
|
|
160
|
-
return this
|
|
160
|
+
return this._dict.length;
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
/**
|
|
@@ -165,7 +165,7 @@ export class CborMap {
|
|
|
165
165
|
* Matches Rust's Map::len().
|
|
166
166
|
*/
|
|
167
167
|
len(): number {
|
|
168
|
-
return this
|
|
168
|
+
return this._dict.length;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
/**
|
|
@@ -173,7 +173,7 @@ export class CborMap {
|
|
|
173
173
|
* Matches Rust's Map::is_empty().
|
|
174
174
|
*/
|
|
175
175
|
isEmpty(): boolean {
|
|
176
|
-
return this
|
|
176
|
+
return this._dict.length === 0;
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
/**
|
|
@@ -181,7 +181,7 @@ export class CborMap {
|
|
|
181
181
|
* Keys are sorted in lexicographic order of their encoded CBOR bytes.
|
|
182
182
|
*/
|
|
183
183
|
get entriesArray(): MapEntry[] {
|
|
184
|
-
return this
|
|
184
|
+
return this._dict.map((value: MapEntry, _key: MapKey) => ({
|
|
185
185
|
key: value.key,
|
|
186
186
|
value: value.value,
|
|
187
187
|
}));
|
|
@@ -213,21 +213,21 @@ export class CborMap {
|
|
|
213
213
|
* Matches Rust's Map::insert_next().
|
|
214
214
|
*/
|
|
215
215
|
setNext<K extends CborInput, V extends CborInput>(key: K, value: V): void {
|
|
216
|
-
const lastEntry = this
|
|
216
|
+
const lastEntry = this._dict.max();
|
|
217
217
|
if (lastEntry === undefined) {
|
|
218
218
|
this.set(key, value);
|
|
219
219
|
return;
|
|
220
220
|
}
|
|
221
221
|
const keyCbor = cbor(key);
|
|
222
222
|
const newKey = cborData(keyCbor);
|
|
223
|
-
if (this
|
|
223
|
+
if (this._dict.has(newKey)) {
|
|
224
224
|
throw new CborError({ type: "DuplicateMapKey" });
|
|
225
225
|
}
|
|
226
|
-
const lastEntryKey = this
|
|
226
|
+
const lastEntryKey = this._makeKey(lastEntry.key);
|
|
227
227
|
if (lexicographicallyCompareBytes(newKey, lastEntryKey) <= 0) {
|
|
228
228
|
throw new CborError({ type: "MisorderedMapKey" });
|
|
229
229
|
}
|
|
230
|
-
this
|
|
230
|
+
this._dict.set(newKey, { key: keyCbor, value: cbor(value) });
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
get debug(): string {
|
package/src/prelude.ts
CHANGED
|
@@ -65,6 +65,9 @@ export type { HexFormatOpts } from "./dump";
|
|
|
65
65
|
export { EdgeType } from "./walk";
|
|
66
66
|
export type { WalkElement, EdgeTypeVariant, Visitor } from "./walk";
|
|
67
67
|
|
|
68
|
+
// BigNum support
|
|
69
|
+
export { biguintToCbor, bigintToCbor, cborToBiguint, cborToBigint } from "./bignum";
|
|
70
|
+
|
|
68
71
|
// Error handling
|
|
69
72
|
export type { Error, Result } from "./error";
|
|
70
73
|
export { Ok, Err, errorMsg, errorToString, CborError } from "./error";
|
package/src/set.ts
CHANGED
|
@@ -47,10 +47,10 @@ import { CborError } from "./error";
|
|
|
47
47
|
* ```
|
|
48
48
|
*/
|
|
49
49
|
export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet> {
|
|
50
|
-
readonly
|
|
50
|
+
private readonly _map: CborMap;
|
|
51
51
|
|
|
52
52
|
constructor() {
|
|
53
|
-
this
|
|
53
|
+
this._map = new CborMap();
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
// =========================================================================
|
|
@@ -127,7 +127,7 @@ export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet
|
|
|
127
127
|
insert(value: CborInput): void {
|
|
128
128
|
const cborValue = encodeCborValue(value);
|
|
129
129
|
// In a set, key and value are the same
|
|
130
|
-
this
|
|
130
|
+
this._map.set(cborValue, cborValue);
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
/**
|
|
@@ -145,7 +145,7 @@ export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet
|
|
|
145
145
|
*/
|
|
146
146
|
contains(value: CborInput): boolean {
|
|
147
147
|
const cborValue = encodeCborValue(value);
|
|
148
|
-
return this
|
|
148
|
+
return this._map.has(cborValue);
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
/**
|
|
@@ -163,14 +163,14 @@ export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet
|
|
|
163
163
|
*/
|
|
164
164
|
delete(value: CborInput): boolean {
|
|
165
165
|
const cborValue = encodeCborValue(value);
|
|
166
|
-
return this
|
|
166
|
+
return this._map.delete(cborValue);
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
/**
|
|
170
170
|
* Remove all elements from the set.
|
|
171
171
|
*/
|
|
172
172
|
clear(): void {
|
|
173
|
-
this
|
|
173
|
+
this._map.clear();
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
/**
|
|
@@ -179,7 +179,7 @@ export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet
|
|
|
179
179
|
* @returns Number of elements
|
|
180
180
|
*/
|
|
181
181
|
get size(): number {
|
|
182
|
-
return this
|
|
182
|
+
return this._map.size;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
/**
|
|
@@ -188,7 +188,7 @@ export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet
|
|
|
188
188
|
* @returns true if set has no elements
|
|
189
189
|
*/
|
|
190
190
|
isEmpty(): boolean {
|
|
191
|
-
return this
|
|
191
|
+
return this._map.size === 0;
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
// =========================================================================
|
|
@@ -313,7 +313,7 @@ export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet
|
|
|
313
313
|
* ```
|
|
314
314
|
*/
|
|
315
315
|
*[Symbol.iterator](): Iterator<Cbor> {
|
|
316
|
-
for (const [_, value] of this
|
|
316
|
+
for (const [_, value] of this._map) {
|
|
317
317
|
yield value;
|
|
318
318
|
}
|
|
319
319
|
}
|
package/src/tags-store.ts
CHANGED
|
@@ -89,9 +89,9 @@ export interface TagsStoreTrait {
|
|
|
89
89
|
* Stores tags with their names and optional summarizer functions.
|
|
90
90
|
*/
|
|
91
91
|
export class TagsStore implements TagsStoreTrait {
|
|
92
|
-
readonly
|
|
93
|
-
readonly
|
|
94
|
-
readonly
|
|
92
|
+
private readonly _tagsByValue = new Map<string, Tag>();
|
|
93
|
+
private readonly _tagsByName = new Map<string, Tag>();
|
|
94
|
+
private readonly _summarizers = new Map<string, CborSummarizer>();
|
|
95
95
|
|
|
96
96
|
constructor() {
|
|
97
97
|
// Start with empty store, matching Rust's Default implementation
|
|
@@ -123,8 +123,8 @@ export class TagsStore implements TagsStoreTrait {
|
|
|
123
123
|
throw new Error(`Tag ${tag.value} must have a non-empty name`);
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
const key = this
|
|
127
|
-
const existing = this
|
|
126
|
+
const key = this._valueKey(tag.value);
|
|
127
|
+
const existing = this._tagsByValue.get(key);
|
|
128
128
|
|
|
129
129
|
// Rust: if old_name != name { panic!(...) }
|
|
130
130
|
if (existing?.name !== undefined && existing.name !== name) {
|
|
@@ -133,8 +133,8 @@ export class TagsStore implements TagsStoreTrait {
|
|
|
133
133
|
);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
this
|
|
137
|
-
this
|
|
136
|
+
this._tagsByValue.set(key, tag);
|
|
137
|
+
this._tagsByName.set(name, tag);
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
/**
|
|
@@ -173,13 +173,13 @@ export class TagsStore implements TagsStoreTrait {
|
|
|
173
173
|
* ```
|
|
174
174
|
*/
|
|
175
175
|
setSummarizer(tagValue: CborNumber, summarizer: CborSummarizer): void {
|
|
176
|
-
const key = this
|
|
177
|
-
this
|
|
176
|
+
const key = this._valueKey(tagValue);
|
|
177
|
+
this._summarizers.set(key, summarizer);
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
assignedNameForTag(tag: Tag): string | undefined {
|
|
181
|
-
const key = this
|
|
182
|
-
const stored = this
|
|
181
|
+
const key = this._valueKey(tag.value);
|
|
182
|
+
const stored = this._tagsByValue.get(key);
|
|
183
183
|
return stored?.name;
|
|
184
184
|
}
|
|
185
185
|
|
|
@@ -188,12 +188,12 @@ export class TagsStore implements TagsStoreTrait {
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
tagForValue(value: CborNumber): Tag | undefined {
|
|
191
|
-
const key = this
|
|
192
|
-
return this
|
|
191
|
+
const key = this._valueKey(value);
|
|
192
|
+
return this._tagsByValue.get(key);
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
tagForName(name: string): Tag | undefined {
|
|
196
|
-
return this
|
|
196
|
+
return this._tagsByName.get(name);
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
nameForValue(value: CborNumber): string {
|
|
@@ -202,8 +202,8 @@ export class TagsStore implements TagsStoreTrait {
|
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
summarizer(tag: CborNumber): CborSummarizer | undefined {
|
|
205
|
-
const key = this
|
|
206
|
-
return this
|
|
205
|
+
const key = this._valueKey(tag);
|
|
206
|
+
return this._summarizers.get(key);
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
/**
|
|
@@ -212,7 +212,7 @@ export class TagsStore implements TagsStoreTrait {
|
|
|
212
212
|
*
|
|
213
213
|
* @private
|
|
214
214
|
*/
|
|
215
|
-
|
|
215
|
+
private _valueKey(value: CborNumber): string {
|
|
216
216
|
return value.toString();
|
|
217
217
|
}
|
|
218
218
|
}
|
package/src/tags.ts
CHANGED
|
@@ -40,6 +40,18 @@ export const TAG_POSITIVE_BIGNUM = 2;
|
|
|
40
40
|
*/
|
|
41
41
|
export const TAG_NEGATIVE_BIGNUM = 3;
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Name for tag 2 (positive bignum).
|
|
45
|
+
* Matches Rust's `TAG_NAME_POSITIVE_BIGNUM`.
|
|
46
|
+
*/
|
|
47
|
+
export const TAG_NAME_POSITIVE_BIGNUM = "positive-bignum";
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Name for tag 3 (negative bignum).
|
|
51
|
+
* Matches Rust's `TAG_NAME_NEGATIVE_BIGNUM`.
|
|
52
|
+
*/
|
|
53
|
+
export const TAG_NAME_NEGATIVE_BIGNUM = "negative-bignum";
|
|
54
|
+
|
|
43
55
|
/**
|
|
44
56
|
* Tag 4: Decimal fraction [exponent, mantissa]
|
|
45
57
|
*/
|
|
@@ -152,6 +164,7 @@ import type { TagsStore, SummarizerResult } from "./tags-store";
|
|
|
152
164
|
import { getGlobalTagsStore } from "./tags-store";
|
|
153
165
|
import { CborDate } from "./date";
|
|
154
166
|
import type { Cbor } from "./cbor";
|
|
167
|
+
import { biguintFromUntaggedCbor, bigintFromNegativeUntaggedCbor } from "./bignum";
|
|
155
168
|
|
|
156
169
|
// Tag constants matching Rust
|
|
157
170
|
export const TAG_DATE = 1;
|
|
@@ -177,6 +190,39 @@ export const registerTagsIn = (tagsStore: TagsStore): void => {
|
|
|
177
190
|
return { ok: false, error: { type: "Custom", message } };
|
|
178
191
|
}
|
|
179
192
|
});
|
|
193
|
+
|
|
194
|
+
// Register bignum tags (matching Rust's #[cfg(feature = "num-bigint")] block)
|
|
195
|
+
const biguintTag = createTag(TAG_POSITIVE_BIGNUM, TAG_NAME_POSITIVE_BIGNUM);
|
|
196
|
+
const bigintTag = createTag(TAG_NEGATIVE_BIGNUM, TAG_NAME_NEGATIVE_BIGNUM);
|
|
197
|
+
tagsStore.insertAll([biguintTag, bigintTag]);
|
|
198
|
+
|
|
199
|
+
// Summarizer for tag 2 (positive bignum)
|
|
200
|
+
tagsStore.setSummarizer(
|
|
201
|
+
TAG_POSITIVE_BIGNUM,
|
|
202
|
+
(untaggedCbor: Cbor, _flat: boolean): SummarizerResult => {
|
|
203
|
+
try {
|
|
204
|
+
const value = biguintFromUntaggedCbor(untaggedCbor);
|
|
205
|
+
return { ok: true, value: `bignum(${value})` };
|
|
206
|
+
} catch (e) {
|
|
207
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
208
|
+
return { ok: false, error: { type: "Custom", message } };
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
// Summarizer for tag 3 (negative bignum)
|
|
214
|
+
tagsStore.setSummarizer(
|
|
215
|
+
TAG_NEGATIVE_BIGNUM,
|
|
216
|
+
(untaggedCbor: Cbor, _flat: boolean): SummarizerResult => {
|
|
217
|
+
try {
|
|
218
|
+
const value = bigintFromNegativeUntaggedCbor(untaggedCbor);
|
|
219
|
+
return { ok: true, value: `bignum(${value})` };
|
|
220
|
+
} catch (e) {
|
|
221
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
222
|
+
return { ok: false, error: { type: "Custom", message } };
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
);
|
|
180
226
|
};
|
|
181
227
|
|
|
182
228
|
/**
|