forked from dignifiedquire/pull-length-prefixed
-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathencode.ts
89 lines (72 loc) · 2.72 KB
/
encode.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import * as varint from 'uint8-varint'
import { Uint8ArrayList } from 'uint8arraylist'
import { allocUnsafe } from 'uint8arrays/alloc'
import { MAX_DATA_LENGTH } from './constants.js'
import { InvalidDataLengthError } from './errors.js'
import { isAsyncIterable } from './utils.js'
import type { LengthEncoderFunction } from './index.js'
import type { Source } from 'it-stream-types'
interface EncoderOptions {
lengthEncoder?: LengthEncoderFunction
maxDataLength?: number
}
// Helper function to validate the chunk size against maxDataLength
function validateMaxDataLength (chunk: Uint8Array | Uint8ArrayList, maxDataLength: number): void {
if (chunk.byteLength > maxDataLength) {
throw new InvalidDataLengthError('Message length too long')
}
}
const defaultEncoder: LengthEncoderFunction = (length) => {
const lengthLength = varint.encodingLength(length)
const lengthBuf = allocUnsafe(lengthLength)
varint.encode(length, lengthBuf)
defaultEncoder.bytes = lengthLength
return lengthBuf
}
defaultEncoder.bytes = 0
export function encode (source: Iterable<Uint8ArrayList | Uint8Array>, options?: EncoderOptions): Generator<Uint8Array, void, undefined>
export function encode (source: Source<Uint8ArrayList | Uint8Array>, options?: EncoderOptions): AsyncGenerator<Uint8Array, void, undefined>
export function encode (source: Source<Uint8ArrayList | Uint8Array>, options?: EncoderOptions): Generator<Uint8Array, void, undefined> | AsyncGenerator<Uint8Array, void, undefined> {
options = options ?? {}
const encodeLength = options.lengthEncoder ?? defaultEncoder
const maxDataLength = options?.maxDataLength ?? MAX_DATA_LENGTH
function * maybeYield (chunk: Uint8Array | Uint8ArrayList): Generator<Uint8Array, void, undefined> {
validateMaxDataLength(chunk, maxDataLength)
// length + data
const length = encodeLength(chunk.byteLength)
// yield only Uint8Arrays
if (length instanceof Uint8Array) {
yield length
} else {
yield * length
}
// yield only Uint8Arrays
if (chunk instanceof Uint8Array) {
yield chunk
} else {
yield * chunk
}
}
if (isAsyncIterable(source)) {
return (async function * () {
for await (const chunk of source) {
yield * maybeYield(chunk)
}
})()
}
return (function * () {
for (const chunk of source) {
yield * maybeYield(chunk)
}
})()
}
encode.single = (chunk: Uint8ArrayList | Uint8Array, options?: EncoderOptions) => {
options = options ?? {}
const encodeLength = options.lengthEncoder ?? defaultEncoder
const maxDataLength = options?.maxDataLength ?? MAX_DATA_LENGTH
validateMaxDataLength(chunk, maxDataLength)
return new Uint8ArrayList(
encodeLength(chunk.byteLength),
chunk
)
}