microcbor 1.1.0 → 1.2.1
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 +50 -9
- package/lib/CBORDecoderStream.d.ts +2 -1
- package/lib/CBORDecoderStream.js +2 -1
- package/lib/CBOREncoderStream.d.ts +1 -1
- package/lib/Decoder.d.ts +5 -2
- package/lib/Decoder.js +23 -6
- package/lib/Encoder.d.ts +2 -26
- package/lib/Encoder.js +8 -6
- package/lib/decodeAsyncIterable.d.ts +10 -4
- package/lib/decodeAsyncIterable.js +51 -7
- package/lib/decodeIterable.d.ts +34 -0
- package/lib/decodeIterable.js +22 -5
- package/lib/encodeAsyncIterable.d.ts +1 -1
- package/lib/encodeIterable.d.ts +1 -1
- package/lib/encodingLength.d.ts +2 -1
- package/lib/encodingLength.js +17 -11
- package/lib/options.d.ts +43 -0
- package/lib/options.js +5 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -68,7 +68,15 @@ console.log(decode(data))
|
|
|
68
68
|
### CBOR Values
|
|
69
69
|
|
|
70
70
|
```ts
|
|
71
|
-
declare type CBORValue =
|
|
71
|
+
declare type CBORValue =
|
|
72
|
+
| undefined
|
|
73
|
+
| null
|
|
74
|
+
| boolean
|
|
75
|
+
| number
|
|
76
|
+
| string
|
|
77
|
+
| Uint8Array
|
|
78
|
+
| CBORArray
|
|
79
|
+
| CBORMap
|
|
72
80
|
|
|
73
81
|
interface CBORArray extends Array<CBORValue> {}
|
|
74
82
|
interface CBORMap {
|
|
@@ -82,6 +90,12 @@ interface CBORMap {
|
|
|
82
90
|
|
|
83
91
|
```ts
|
|
84
92
|
export interface EncodeOptions {
|
|
93
|
+
/**
|
|
94
|
+
* Allow `undefined`
|
|
95
|
+
* @default true
|
|
96
|
+
*/
|
|
97
|
+
allowUndefined?: boolean
|
|
98
|
+
|
|
85
99
|
/**
|
|
86
100
|
* Re-use the same underlying ArrayBuffer for all yielded chunks.
|
|
87
101
|
* If this is enabled, the consumer must copy each chunk content
|
|
@@ -113,7 +127,10 @@ export interface EncodeOptions {
|
|
|
113
127
|
* Calculate the byte length that a value will encode into
|
|
114
128
|
* without actually allocating anything.
|
|
115
129
|
*/
|
|
116
|
-
declare function encodingLength(
|
|
130
|
+
declare function encodingLength(
|
|
131
|
+
value: CBORValue,
|
|
132
|
+
options?: EncodeOptions,
|
|
133
|
+
): number
|
|
117
134
|
```
|
|
118
135
|
|
|
119
136
|
#### `encode`
|
|
@@ -123,7 +140,7 @@ declare function encodingLength(value: CBORValue): number
|
|
|
123
140
|
* Encode a single CBOR value.
|
|
124
141
|
* options.chunkRecycling has no effect here.
|
|
125
142
|
*/
|
|
126
|
-
export function encode(value: CBORValue, options
|
|
143
|
+
export function encode(value: CBORValue, options?: EncodeOptions): Uint8Array
|
|
127
144
|
```
|
|
128
145
|
|
|
129
146
|
#### `encodeIterable`
|
|
@@ -132,7 +149,7 @@ export function encode(value: CBORValue, options: EncodeOptions = {}): Uint8Arra
|
|
|
132
149
|
/** Encode an iterable of CBOR values into an iterable of Uint8Array chunks */
|
|
133
150
|
export function* encodeIterable(
|
|
134
151
|
source: Iterable<CBORValue>,
|
|
135
|
-
options
|
|
152
|
+
options?: EncodeOptions,
|
|
136
153
|
): IterableIterator<Uint8Array>
|
|
137
154
|
|
|
138
155
|
```
|
|
@@ -143,7 +160,7 @@ export function* encodeIterable(
|
|
|
143
160
|
/** Encode an async iterable of CBOR values into an async iterable of Uint8Array chunks */
|
|
144
161
|
export async function* encodeAsyncIterable(
|
|
145
162
|
source: AsyncIterable<CBORValue>,
|
|
146
|
-
options
|
|
163
|
+
options?: EncodeOptions,
|
|
147
164
|
): AsyncIterableIterator<Uint8Array>
|
|
148
165
|
|
|
149
166
|
```
|
|
@@ -156,17 +173,38 @@ export async function* encodeAsyncIterable(
|
|
|
156
173
|
* options.chunkRecycling has no effect here.
|
|
157
174
|
*/
|
|
158
175
|
export class CBOREncoderStream extends TransformStream<CBORValue, Uint8Array> {
|
|
159
|
-
public constructor(options
|
|
176
|
+
public constructor(options?: EncodeOptions)
|
|
160
177
|
}
|
|
161
178
|
```
|
|
162
179
|
|
|
163
180
|
### Decoding
|
|
164
181
|
|
|
182
|
+
#### `DecodeOptions`
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
export interface DecodeOptions {
|
|
186
|
+
/**
|
|
187
|
+
* Allow `undefined`
|
|
188
|
+
* @default true
|
|
189
|
+
*/
|
|
190
|
+
allowUndefined?: boolean
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Minimum bitsize for floating-point numbers: 16, 32, or 64
|
|
194
|
+
* @default 16
|
|
195
|
+
*/
|
|
196
|
+
minFloatSize?: (typeof FloatSize)[keyof typeof FloatSize]
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
165
200
|
#### `decode`
|
|
166
201
|
|
|
167
202
|
```ts
|
|
168
203
|
/** Decode a single CBOR value. */
|
|
169
|
-
export function decode<T extends CBORValue = CBORValue>(
|
|
204
|
+
export function decode<T extends CBORValue = CBORValue>(
|
|
205
|
+
data: Uint8Array,
|
|
206
|
+
options?: DecodeOptions,
|
|
207
|
+
): T
|
|
170
208
|
```
|
|
171
209
|
|
|
172
210
|
#### `decodeIterable`
|
|
@@ -175,8 +213,8 @@ export function decode<T extends CBORValue = CBORValue>(data: Uint8Array): T
|
|
|
175
213
|
/** Decode an iterable of Uint8Array chunks into an iterable of CBOR values */
|
|
176
214
|
export function* decodeIterable<T extends CBORValue = CBORValue>(
|
|
177
215
|
source: Iterable<Uint8Array>,
|
|
216
|
+
options?: DecodeOptions,
|
|
178
217
|
): IterableIterator<T>
|
|
179
|
-
|
|
180
218
|
```
|
|
181
219
|
|
|
182
220
|
#### `decodeAsyncIterable`
|
|
@@ -185,6 +223,7 @@ export function* decodeIterable<T extends CBORValue = CBORValue>(
|
|
|
185
223
|
/** Decode an async iterable of Uint8Array chunks into an async iterable of CBOR values */
|
|
186
224
|
export async function* decodeAsyncIterable<T extends CBORValue = CBORValue>(
|
|
187
225
|
source: AsyncIterable<Uint8Array>,
|
|
226
|
+
options?: DecodeOptions,
|
|
188
227
|
): AsyncIterable<CBORValue>
|
|
189
228
|
```
|
|
190
229
|
|
|
@@ -192,7 +231,9 @@ export async function* decodeAsyncIterable<T extends CBORValue = CBORValue>(
|
|
|
192
231
|
|
|
193
232
|
```ts
|
|
194
233
|
/** Decode a Web Streams API ReadableStream. */
|
|
195
|
-
export class CBORDecoderStream<
|
|
234
|
+
export class CBORDecoderStream<
|
|
235
|
+
T extends CBORValue = CBORValue,
|
|
236
|
+
> extends TransformStream<Uint8Array, T> {
|
|
196
237
|
public constructor()
|
|
197
238
|
}
|
|
198
239
|
```
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { DecodeOptions } from "./options.js";
|
|
1
2
|
import { CBORValue } from "./types.js";
|
|
2
3
|
/** Decode a Web Streams API ReadableStream */
|
|
3
4
|
export declare class CBORDecoderStream<T extends CBORValue = CBORValue> extends TransformStream<Uint8Array, T> {
|
|
4
|
-
constructor();
|
|
5
|
+
constructor(options?: DecodeOptions);
|
|
5
6
|
}
|
package/lib/CBORDecoderStream.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Decoder } from "./decodeAsyncIterable.js";
|
|
2
2
|
/** Decode a Web Streams API ReadableStream */
|
|
3
3
|
export class CBORDecoderStream extends TransformStream {
|
|
4
|
-
constructor() {
|
|
4
|
+
constructor(options = {}) {
|
|
5
5
|
let readableController;
|
|
6
6
|
const readable = new ReadableStream({
|
|
7
7
|
start(controller) {
|
|
@@ -13,6 +13,7 @@ export class CBORDecoderStream extends TransformStream {
|
|
|
13
13
|
const chunks = new WeakMap();
|
|
14
14
|
async function pipe(controller) {
|
|
15
15
|
const decoder = new Decoder(readable.values(), {
|
|
16
|
+
...options,
|
|
16
17
|
onFree: (chunk) => chunks.get(chunk)?.resolve(),
|
|
17
18
|
});
|
|
18
19
|
for await (const value of decoder) {
|
package/lib/Decoder.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { CBORValue } from "./types.js";
|
|
2
|
+
import type { DecodeOptions, FloatSize } from "./options.js";
|
|
2
3
|
export declare class Decoder {
|
|
3
4
|
#private;
|
|
4
5
|
private readonly data;
|
|
5
|
-
|
|
6
|
+
readonly allowUndefined: boolean;
|
|
7
|
+
readonly minFloatSize: (typeof FloatSize)[keyof typeof FloatSize];
|
|
8
|
+
constructor(data: Uint8Array, options?: DecodeOptions);
|
|
6
9
|
getOffset(): number;
|
|
7
10
|
private constant;
|
|
8
11
|
private float16;
|
|
@@ -18,4 +21,4 @@ export declare class Decoder {
|
|
|
18
21
|
decodeValue(): CBORValue;
|
|
19
22
|
}
|
|
20
23
|
/** Decode a single CBOR value */
|
|
21
|
-
export declare function decode<T extends CBORValue = CBORValue>(data: Uint8Array): T;
|
|
24
|
+
export declare function decode<T extends CBORValue = CBORValue>(data: Uint8Array, options?: DecodeOptions): T;
|
package/lib/Decoder.js
CHANGED
|
@@ -13,7 +13,7 @@ var _Decoder_offset, _Decoder_view;
|
|
|
13
13
|
import { getFloat16 } from "fp16";
|
|
14
14
|
import { UnsafeIntegerError, maxSafeInteger, minSafeInteger } from "./utils.js";
|
|
15
15
|
export class Decoder {
|
|
16
|
-
constructor(data) {
|
|
16
|
+
constructor(data, options = {}) {
|
|
17
17
|
this.data = data;
|
|
18
18
|
_Decoder_offset.set(this, void 0);
|
|
19
19
|
_Decoder_view.set(this, void 0);
|
|
@@ -31,6 +31,8 @@ export class Decoder {
|
|
|
31
31
|
this.uint64 = this.constant(8, () => __classPrivateFieldGet(this, _Decoder_view, "f").getBigUint64(__classPrivateFieldGet(this, _Decoder_offset, "f")));
|
|
32
32
|
__classPrivateFieldSet(this, _Decoder_offset, 0, "f");
|
|
33
33
|
__classPrivateFieldSet(this, _Decoder_view, new DataView(data.buffer, data.byteOffset, data.byteLength), "f");
|
|
34
|
+
this.allowUndefined = options.allowUndefined ?? true;
|
|
35
|
+
this.minFloatSize = options.minFloatSize ?? 16;
|
|
34
36
|
}
|
|
35
37
|
getOffset() {
|
|
36
38
|
return __classPrivateFieldGet(this, _Decoder_offset, "f");
|
|
@@ -133,13 +135,28 @@ export class Decoder {
|
|
|
133
135
|
case 22:
|
|
134
136
|
return null;
|
|
135
137
|
case 23:
|
|
136
|
-
|
|
138
|
+
if (this.allowUndefined) {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
throw new TypeError("`undefined` not allowed");
|
|
143
|
+
}
|
|
137
144
|
case 24:
|
|
138
145
|
throw new Error("microcbor does not support decoding unassigned simple values");
|
|
139
146
|
case 25:
|
|
140
|
-
|
|
147
|
+
if (this.minFloatSize <= 16) {
|
|
148
|
+
return this.float16();
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
throw new Error("cannot decode float16 type - below provided minFloatSize");
|
|
152
|
+
}
|
|
141
153
|
case 26:
|
|
142
|
-
|
|
154
|
+
if (this.minFloatSize <= 32) {
|
|
155
|
+
return this.float32();
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
throw new Error("cannot decode float32 type - below provided minFloatSize");
|
|
159
|
+
}
|
|
143
160
|
case 27:
|
|
144
161
|
return this.float64();
|
|
145
162
|
case 31:
|
|
@@ -155,6 +172,6 @@ export class Decoder {
|
|
|
155
172
|
}
|
|
156
173
|
_Decoder_offset = new WeakMap(), _Decoder_view = new WeakMap();
|
|
157
174
|
/** Decode a single CBOR value */
|
|
158
|
-
export function decode(data) {
|
|
159
|
-
return new Decoder(data).decodeValue();
|
|
175
|
+
export function decode(data, options = {}) {
|
|
176
|
+
return new Decoder(data, options).decodeValue();
|
|
160
177
|
}
|
package/lib/Encoder.d.ts
CHANGED
|
@@ -1,33 +1,9 @@
|
|
|
1
1
|
import type { CBORValue } from "./types.js";
|
|
2
|
-
|
|
3
|
-
f16: number;
|
|
4
|
-
f32: number;
|
|
5
|
-
f64: number;
|
|
6
|
-
};
|
|
7
|
-
export interface EncodeOptions {
|
|
8
|
-
/**
|
|
9
|
-
* Re-use the same underlying ArrayBuffer for all yielded chunks.
|
|
10
|
-
* If this is enabled, the consumer must copy each chunk content
|
|
11
|
-
* themselves to a new buffer if they wish to keep it.
|
|
12
|
-
* This mode is useful for efficiently hashing objects without
|
|
13
|
-
* ever allocating memory for the entire encoded result.
|
|
14
|
-
* @default false
|
|
15
|
-
*/
|
|
16
|
-
chunkRecycling?: boolean;
|
|
17
|
-
/**
|
|
18
|
-
* Maximum chunk size
|
|
19
|
-
* @default 4096
|
|
20
|
-
*/
|
|
21
|
-
chunkSize?: number;
|
|
22
|
-
/**
|
|
23
|
-
* Minimum bitsize for floating-point numbers: 16, 32, or 64
|
|
24
|
-
* @default 16
|
|
25
|
-
*/
|
|
26
|
-
minFloatSize?: (typeof FloatSize)[keyof typeof FloatSize];
|
|
27
|
-
}
|
|
2
|
+
import { EncodeOptions, FloatSize } from "./options.js";
|
|
28
3
|
export declare class Encoder {
|
|
29
4
|
#private;
|
|
30
5
|
static defaultChunkSize: number;
|
|
6
|
+
readonly allowUndefined: boolean;
|
|
31
7
|
readonly chunkRecycling: boolean;
|
|
32
8
|
readonly chunkSize: number;
|
|
33
9
|
readonly minFloatSize: (typeof FloatSize)[keyof typeof FloatSize];
|
package/lib/Encoder.js
CHANGED
|
@@ -11,17 +11,14 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
11
11
|
};
|
|
12
12
|
var _Encoder_instances, _Encoder_closed, _Encoder_flush;
|
|
13
13
|
import { Precision, getFloat16Precision, getFloat32Precision, setFloat16 } from "fp16";
|
|
14
|
+
import { FloatSize } from "./options.js";
|
|
14
15
|
import { assert } from "./utils.js";
|
|
15
|
-
export const FloatSize = {
|
|
16
|
-
f16: 16,
|
|
17
|
-
f32: 32,
|
|
18
|
-
f64: 64,
|
|
19
|
-
};
|
|
20
16
|
export class Encoder {
|
|
21
17
|
constructor(options = {}) {
|
|
22
18
|
_Encoder_instances.add(this);
|
|
23
19
|
_Encoder_closed.set(this, void 0);
|
|
24
20
|
this.encoder = new TextEncoder();
|
|
21
|
+
this.allowUndefined = options.allowUndefined ?? true;
|
|
25
22
|
this.minFloatSize = options.minFloatSize ?? 16;
|
|
26
23
|
this.chunkRecycling = options.chunkRecycling ?? false;
|
|
27
24
|
this.chunkSize = options.chunkSize ?? Encoder.defaultChunkSize;
|
|
@@ -175,7 +172,12 @@ export class Encoder {
|
|
|
175
172
|
yield* this.uint8(0xf6);
|
|
176
173
|
}
|
|
177
174
|
else if (value === undefined) {
|
|
178
|
-
|
|
175
|
+
if (this.allowUndefined) {
|
|
176
|
+
yield* this.uint8(0xf7);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
throw new TypeError("`undefined` is not allowed");
|
|
180
|
+
}
|
|
179
181
|
}
|
|
180
182
|
else if (typeof value === "number") {
|
|
181
183
|
yield* this.encodeNumber(value);
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { CBORValue } from "./types.js";
|
|
2
|
+
import { DecodeOptions, FloatSize } from "./options.js";
|
|
3
|
+
export interface AsyncDecodeOptions extends DecodeOptions {
|
|
4
|
+
onFree?: (chunk: Uint8Array) => void;
|
|
5
|
+
}
|
|
2
6
|
export declare class Decoder<T extends CBORValue = CBORValue> implements AsyncIterableIterator<T> {
|
|
7
|
+
readonly allowUndefined: boolean;
|
|
8
|
+
readonly minFloatSize: (typeof FloatSize)[keyof typeof FloatSize];
|
|
3
9
|
private offset;
|
|
4
10
|
private byteLength;
|
|
5
11
|
private readonly chunks;
|
|
@@ -7,9 +13,9 @@ export declare class Decoder<T extends CBORValue = CBORValue> implements AsyncIt
|
|
|
7
13
|
private readonly constantView;
|
|
8
14
|
private readonly iter;
|
|
9
15
|
private readonly onFree?;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
private readonly touchedChunks;
|
|
17
|
+
private readonly freedChunks;
|
|
18
|
+
constructor(source: AsyncIterable<Uint8Array>, options?: AsyncDecodeOptions);
|
|
13
19
|
[Symbol.asyncIterator]: () => this;
|
|
14
20
|
private allocate;
|
|
15
21
|
private fill;
|
|
@@ -34,4 +40,4 @@ export declare class Decoder<T extends CBORValue = CBORValue> implements AsyncIt
|
|
|
34
40
|
private decodeValue;
|
|
35
41
|
}
|
|
36
42
|
/** Decode an async iterable of Uint8Array chunks into an async iterable of CBOR values */
|
|
37
|
-
export declare function decodeAsyncIterable(source: AsyncIterable<Uint8Array
|
|
43
|
+
export declare function decodeAsyncIterable(source: AsyncIterable<Uint8Array>, options?: AsyncDecodeOptions): AsyncIterableIterator<CBORValue>;
|
|
@@ -8,6 +8,8 @@ export class Decoder {
|
|
|
8
8
|
this.chunks = [];
|
|
9
9
|
this.constantBuffer = new ArrayBuffer(8);
|
|
10
10
|
this.constantView = new DataView(this.constantBuffer);
|
|
11
|
+
this.touchedChunks = new WeakSet();
|
|
12
|
+
this.freedChunks = new WeakSet();
|
|
11
13
|
this[_a] = () => this;
|
|
12
14
|
this.constant = (size, f) => {
|
|
13
15
|
return async () => {
|
|
@@ -24,10 +26,22 @@ export class Decoder {
|
|
|
24
26
|
this.uint16 = this.constant(2, (view) => view.getUint16(0));
|
|
25
27
|
this.uint32 = this.constant(4, (view) => view.getUint32(0));
|
|
26
28
|
this.uint64 = this.constant(8, (view) => view.getBigUint64(0));
|
|
27
|
-
this.iter = source[Symbol.asyncIterator]();
|
|
28
29
|
this.onFree = options.onFree;
|
|
30
|
+
this.allowUndefined = options.allowUndefined ?? true;
|
|
31
|
+
this.minFloatSize = options.minFloatSize ?? 16;
|
|
32
|
+
this.iter = source[Symbol.asyncIterator]();
|
|
29
33
|
}
|
|
30
34
|
async allocate(size) {
|
|
35
|
+
// If we need more data, first call onFree for all touched chunks
|
|
36
|
+
// This allows the transform stream to provide more chunks
|
|
37
|
+
if (this.byteLength < size && this.onFree !== undefined) {
|
|
38
|
+
for (const chunk of this.chunks) {
|
|
39
|
+
if (this.touchedChunks.has(chunk) && !this.freedChunks.has(chunk)) {
|
|
40
|
+
this.freedChunks.add(chunk);
|
|
41
|
+
this.onFree(chunk);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
31
45
|
while (this.byteLength < size) {
|
|
32
46
|
const { done, value } = await this.iter.next();
|
|
33
47
|
if (done) {
|
|
@@ -36,6 +50,12 @@ export class Decoder {
|
|
|
36
50
|
else {
|
|
37
51
|
this.chunks.push(value);
|
|
38
52
|
this.byteLength += value.byteLength;
|
|
53
|
+
// If we still need more data after adding this chunk,
|
|
54
|
+
// immediately call onFree to allow the next chunk to flow
|
|
55
|
+
if (this.byteLength < size && this.onFree !== undefined && !this.freedChunks.has(value)) {
|
|
56
|
+
this.freedChunks.add(value);
|
|
57
|
+
this.onFree(value);
|
|
58
|
+
}
|
|
39
59
|
}
|
|
40
60
|
}
|
|
41
61
|
}
|
|
@@ -47,6 +67,10 @@ export class Decoder {
|
|
|
47
67
|
let deleteCount = 0;
|
|
48
68
|
for (let i = 0; byteLength < target.byteLength; i++) {
|
|
49
69
|
const chunk = this.chunks[i];
|
|
70
|
+
// Track which chunks we touched
|
|
71
|
+
if (!this.touchedChunks.has(chunk)) {
|
|
72
|
+
this.touchedChunks.add(chunk);
|
|
73
|
+
}
|
|
50
74
|
const capacity = target.byteLength - byteLength;
|
|
51
75
|
const length = chunk.byteLength - this.offset;
|
|
52
76
|
if (length <= capacity) {
|
|
@@ -65,9 +89,14 @@ export class Decoder {
|
|
|
65
89
|
this.byteLength -= capacity;
|
|
66
90
|
}
|
|
67
91
|
}
|
|
92
|
+
// Call onFree for chunks that are being removed (fully consumed)
|
|
68
93
|
if (this.onFree !== undefined) {
|
|
69
94
|
for (let i = 0; i < deleteCount; i++) {
|
|
70
|
-
this.
|
|
95
|
+
const chunk = this.chunks[i];
|
|
96
|
+
if (!this.freedChunks.has(chunk)) {
|
|
97
|
+
this.freedChunks.add(chunk);
|
|
98
|
+
this.onFree(chunk);
|
|
99
|
+
}
|
|
71
100
|
}
|
|
72
101
|
}
|
|
73
102
|
this.chunks.splice(0, deleteCount);
|
|
@@ -185,13 +214,28 @@ export class Decoder {
|
|
|
185
214
|
case 22:
|
|
186
215
|
return null;
|
|
187
216
|
case 23:
|
|
188
|
-
|
|
217
|
+
if (this.allowUndefined) {
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
throw new TypeError("`undefined` not allowed");
|
|
222
|
+
}
|
|
189
223
|
case 24:
|
|
190
224
|
throw new Error("microcbor does not support decoding unassigned simple values");
|
|
191
225
|
case 25:
|
|
192
|
-
|
|
226
|
+
if (this.minFloatSize <= 16) {
|
|
227
|
+
return this.float16();
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
throw new Error("cannot decode float16 type - below provided minFloatSize");
|
|
231
|
+
}
|
|
193
232
|
case 26:
|
|
194
|
-
|
|
233
|
+
if (this.minFloatSize <= 32) {
|
|
234
|
+
return this.float32();
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
throw new Error("cannot decode float32 type - below provided minFloatSize");
|
|
238
|
+
}
|
|
195
239
|
case 27:
|
|
196
240
|
return await this.float64();
|
|
197
241
|
case 31:
|
|
@@ -207,6 +251,6 @@ export class Decoder {
|
|
|
207
251
|
}
|
|
208
252
|
_a = Symbol.asyncIterator;
|
|
209
253
|
/** Decode an async iterable of Uint8Array chunks into an async iterable of CBOR values */
|
|
210
|
-
export async function* decodeAsyncIterable(source) {
|
|
211
|
-
yield* new Decoder(source);
|
|
254
|
+
export async function* decodeAsyncIterable(source, options = {}) {
|
|
255
|
+
yield* new Decoder(source, options);
|
|
212
256
|
}
|
package/lib/decodeIterable.d.ts
CHANGED
|
@@ -1,3 +1,37 @@
|
|
|
1
1
|
import type { CBORValue } from "./types.js";
|
|
2
|
+
import type { DecodeOptions, FloatSize } from "./options.js";
|
|
3
|
+
export declare class Decoder<T extends CBORValue = CBORValue> implements IterableIterator<T> {
|
|
4
|
+
readonly allowUndefined: boolean;
|
|
5
|
+
readonly minFloatSize: (typeof FloatSize)[keyof typeof FloatSize];
|
|
6
|
+
private offset;
|
|
7
|
+
private byteLength;
|
|
8
|
+
private readonly chunks;
|
|
9
|
+
private readonly constantBuffer;
|
|
10
|
+
private readonly constantView;
|
|
11
|
+
private readonly iter;
|
|
12
|
+
constructor(source: Iterable<Uint8Array>, options?: DecodeOptions);
|
|
13
|
+
[Symbol.iterator]: () => this;
|
|
14
|
+
private allocate;
|
|
15
|
+
private fill;
|
|
16
|
+
private constant;
|
|
17
|
+
private float16;
|
|
18
|
+
private float32;
|
|
19
|
+
private float64;
|
|
20
|
+
private uint8;
|
|
21
|
+
private uint16;
|
|
22
|
+
private uint32;
|
|
23
|
+
private uint64;
|
|
24
|
+
private decodeBytes;
|
|
25
|
+
private decodeString;
|
|
26
|
+
private getArgument;
|
|
27
|
+
next(): {
|
|
28
|
+
done: true;
|
|
29
|
+
value: undefined;
|
|
30
|
+
} | {
|
|
31
|
+
done: false;
|
|
32
|
+
value: T;
|
|
33
|
+
};
|
|
34
|
+
private decodeValue;
|
|
35
|
+
}
|
|
2
36
|
/** Decode an iterable of Uint8Array chunks into an iterable of CBOR values */
|
|
3
37
|
export declare function decodeIterable(source: Iterable<Uint8Array>): IterableIterator<CBORValue>;
|
package/lib/decodeIterable.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
var _a;
|
|
2
2
|
import { getFloat16 } from "fp16";
|
|
3
3
|
import { UnsafeIntegerError, maxSafeInteger, minSafeInteger } from "./utils.js";
|
|
4
|
-
class Decoder {
|
|
5
|
-
constructor(source) {
|
|
4
|
+
export class Decoder {
|
|
5
|
+
constructor(source, options = {}) {
|
|
6
6
|
this.offset = 0;
|
|
7
7
|
this.byteLength = 0;
|
|
8
8
|
this.chunks = [];
|
|
@@ -24,6 +24,8 @@ class Decoder {
|
|
|
24
24
|
this.uint16 = this.constant(2, (view) => view.getUint16(0));
|
|
25
25
|
this.uint32 = this.constant(4, (view) => view.getUint32(0));
|
|
26
26
|
this.uint64 = this.constant(8, (view) => view.getBigUint64(0));
|
|
27
|
+
this.allowUndefined = options.allowUndefined ?? true;
|
|
28
|
+
this.minFloatSize = options.minFloatSize ?? 16;
|
|
27
29
|
this.iter = source[Symbol.iterator]();
|
|
28
30
|
}
|
|
29
31
|
allocate(size) {
|
|
@@ -179,13 +181,28 @@ class Decoder {
|
|
|
179
181
|
case 22:
|
|
180
182
|
return null;
|
|
181
183
|
case 23:
|
|
182
|
-
|
|
184
|
+
if (this.allowUndefined) {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
throw new TypeError("`undefined` not allowed");
|
|
189
|
+
}
|
|
183
190
|
case 24:
|
|
184
191
|
throw new Error("microcbor does not support decoding unassigned simple values");
|
|
185
192
|
case 25:
|
|
186
|
-
|
|
193
|
+
if (this.minFloatSize <= 16) {
|
|
194
|
+
return this.float16();
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
throw new Error("cannot decode float16 type - below provided minFloatSize");
|
|
198
|
+
}
|
|
187
199
|
case 26:
|
|
188
|
-
|
|
200
|
+
if (this.minFloatSize <= 32) {
|
|
201
|
+
return this.float32();
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
throw new Error("cannot decode float32 type - below provided minFloatSize");
|
|
205
|
+
}
|
|
189
206
|
case 27:
|
|
190
207
|
return this.float64();
|
|
191
208
|
case 31:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { CBORValue } from "./types.js";
|
|
2
|
-
import { EncodeOptions } from "./
|
|
2
|
+
import { EncodeOptions } from "./options.js";
|
|
3
3
|
/** Encode an async iterable of CBOR values into an async iterable of Uint8Array chunks */
|
|
4
4
|
export declare function encodeAsyncIterable(source: AsyncIterable<CBORValue>, options?: EncodeOptions): AsyncIterableIterator<Uint8Array>;
|
package/lib/encodeIterable.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { CBORValue } from "./types.js";
|
|
2
|
-
import { EncodeOptions } from "./
|
|
2
|
+
import { EncodeOptions } from "./options.js";
|
|
3
3
|
/** Encode an iterable of CBOR values into an iterable of Uint8Array chunks */
|
|
4
4
|
export declare function encodeIterable(source: Iterable<CBORValue>, options?: EncodeOptions): IterableIterator<Uint8Array>;
|
package/lib/encodingLength.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CBORValue } from "./types.js";
|
|
2
|
+
import { EncodeOptions } from "./options.js";
|
|
2
3
|
/**
|
|
3
4
|
* Calculate the byte length that a value will encode into
|
|
4
5
|
* without actually allocating anything.
|
|
5
6
|
*/
|
|
6
|
-
export declare function encodingLength(value: CBORValue): number;
|
|
7
|
+
export declare function encodingLength(value: CBORValue, options?: EncodeOptions): number;
|
package/lib/encodingLength.js
CHANGED
|
@@ -4,7 +4,7 @@ import { getByteLength } from "./utils.js";
|
|
|
4
4
|
* Calculate the byte length that a value will encode into
|
|
5
5
|
* without actually allocating anything.
|
|
6
6
|
*/
|
|
7
|
-
export function encodingLength(value) {
|
|
7
|
+
export function encodingLength(value, options = {}) {
|
|
8
8
|
if (value === false) {
|
|
9
9
|
return 1;
|
|
10
10
|
}
|
|
@@ -15,10 +15,15 @@ export function encodingLength(value) {
|
|
|
15
15
|
return 1;
|
|
16
16
|
}
|
|
17
17
|
else if (value === undefined) {
|
|
18
|
-
|
|
18
|
+
if (options.allowUndefined ?? true) {
|
|
19
|
+
return 1;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
throw new Error("`undefined` is not allowed");
|
|
23
|
+
}
|
|
19
24
|
}
|
|
20
25
|
else if (typeof value === "number") {
|
|
21
|
-
return numberEncodingLength(value);
|
|
26
|
+
return numberEncodingLength(value, options);
|
|
22
27
|
}
|
|
23
28
|
else if (typeof value === "string") {
|
|
24
29
|
return stringEncodingLength(value);
|
|
@@ -29,7 +34,7 @@ export function encodingLength(value) {
|
|
|
29
34
|
else if (Array.isArray(value)) {
|
|
30
35
|
let length = argumentEncodingLength(value.length);
|
|
31
36
|
for (const element of value) {
|
|
32
|
-
length += encodingLength(element);
|
|
37
|
+
length += encodingLength(element, options);
|
|
33
38
|
}
|
|
34
39
|
return length;
|
|
35
40
|
}
|
|
@@ -39,7 +44,7 @@ export function encodingLength(value) {
|
|
|
39
44
|
for (const key of keys) {
|
|
40
45
|
if (typeof key === "string") {
|
|
41
46
|
length += stringEncodingLength(key);
|
|
42
|
-
length += encodingLength(value[key]);
|
|
47
|
+
length += encodingLength(value[key], options);
|
|
43
48
|
}
|
|
44
49
|
else {
|
|
45
50
|
throw new Error("object keys must be strings");
|
|
@@ -68,18 +73,18 @@ function argumentEncodingLength(argument) {
|
|
|
68
73
|
return 1 + 8;
|
|
69
74
|
}
|
|
70
75
|
}
|
|
71
|
-
function numberEncodingLength(value) {
|
|
76
|
+
function numberEncodingLength(value, options) {
|
|
72
77
|
if (Object.is(value, 0)) {
|
|
73
78
|
return integerEncodingLength(value);
|
|
74
79
|
}
|
|
75
80
|
else if (Object.is(value, -0)) {
|
|
76
|
-
return floatEncodingLength(value);
|
|
81
|
+
return floatEncodingLength(value, options);
|
|
77
82
|
}
|
|
78
83
|
else if (Math.floor(value) === value && Number.MIN_SAFE_INTEGER <= value && value <= Number.MAX_SAFE_INTEGER) {
|
|
79
84
|
return integerEncodingLength(value);
|
|
80
85
|
}
|
|
81
86
|
else {
|
|
82
|
-
return floatEncodingLength(value);
|
|
87
|
+
return floatEncodingLength(value, options);
|
|
83
88
|
}
|
|
84
89
|
}
|
|
85
90
|
function integerEncodingLength(value) {
|
|
@@ -90,11 +95,12 @@ function integerEncodingLength(value) {
|
|
|
90
95
|
return argumentEncodingLength(value);
|
|
91
96
|
}
|
|
92
97
|
}
|
|
93
|
-
function floatEncodingLength(value) {
|
|
94
|
-
|
|
98
|
+
function floatEncodingLength(value, options) {
|
|
99
|
+
const { minFloatSize = 16 } = options;
|
|
100
|
+
if (minFloatSize <= 16 && getFloat16Precision(value) === Precision.Exact) {
|
|
95
101
|
return 1 + 2;
|
|
96
102
|
}
|
|
97
|
-
else if (getFloat32Precision(value) === Precision.Exact) {
|
|
103
|
+
else if (minFloatSize <= 32 && getFloat32Precision(value) === Precision.Exact) {
|
|
98
104
|
return 1 + 4;
|
|
99
105
|
}
|
|
100
106
|
else {
|
package/lib/options.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export declare const FloatSize: {
|
|
2
|
+
f16: number;
|
|
3
|
+
f32: number;
|
|
4
|
+
f64: number;
|
|
5
|
+
};
|
|
6
|
+
export interface EncodeOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Allow `undefined`
|
|
9
|
+
* @default true
|
|
10
|
+
*/
|
|
11
|
+
allowUndefined?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Re-use the same underlying ArrayBuffer for all yielded chunks.
|
|
14
|
+
* If this is enabled, the consumer must copy each chunk content
|
|
15
|
+
* themselves to a new buffer if they wish to keep it.
|
|
16
|
+
* This mode is useful for efficiently hashing objects without
|
|
17
|
+
* ever allocating memory for the entire encoded result.
|
|
18
|
+
* @default false
|
|
19
|
+
*/
|
|
20
|
+
chunkRecycling?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Maximum chunk size
|
|
23
|
+
* @default 4096
|
|
24
|
+
*/
|
|
25
|
+
chunkSize?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Minimum bitsize for floating-point numbers: 16, 32, or 64
|
|
28
|
+
* @default 16
|
|
29
|
+
*/
|
|
30
|
+
minFloatSize?: (typeof FloatSize)[keyof typeof FloatSize];
|
|
31
|
+
}
|
|
32
|
+
export interface DecodeOptions {
|
|
33
|
+
/**
|
|
34
|
+
* Allow `undefined`
|
|
35
|
+
* @default true
|
|
36
|
+
*/
|
|
37
|
+
allowUndefined?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Minimum bitsize for floating-point numbers: 16, 32, or 64
|
|
40
|
+
* @default 16
|
|
41
|
+
*/
|
|
42
|
+
minFloatSize?: (typeof FloatSize)[keyof typeof FloatSize];
|
|
43
|
+
}
|
package/lib/options.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "microcbor",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"lib"
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"homepage": "https://github.com/joeltg/microcbor#readme",
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@ava/typescript": "^
|
|
35
|
+
"@ava/typescript": "^6.0.0",
|
|
36
36
|
"@types/node": "^22.13.9",
|
|
37
37
|
"ava": "^6.2.0",
|
|
38
38
|
"cbor": "^10.0.3",
|