@andrew_l/tl-pack 0.0.2 → 0.0.4

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.
@@ -1,16 +1,21 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
+ import { TLExtension } from './extension.js';
3
+ export interface BinaryReaderOptions {
4
+ extensions?: TLExtension[];
5
+ }
2
6
  export declare class BinaryReader {
3
7
  private target;
4
8
  private targetView;
5
9
  private _last?;
6
10
  private _dict;
11
+ private extensions;
7
12
  offset: number;
8
13
  length: number;
9
14
  /**
10
15
  * Small utility class to read binary data.
11
16
  * @param data {Buffer}
12
17
  */
13
- constructor(data: Buffer | Uint8Array);
18
+ constructor(data: Buffer | Uint8Array, options?: BinaryReaderOptions);
14
19
  readByte(): number;
15
20
  readInt32(signed?: boolean): number;
16
21
  readInt16(signed?: boolean): number;
@@ -61,6 +66,7 @@ export declare class BinaryReader {
61
66
  * Reads a object.
62
67
  */
63
68
  readObject(): any;
69
+ private readCore;
64
70
  readDictionary(): string | null;
65
71
  readMap(checkConstructor?: boolean): Record<string, any>;
66
72
  decode(value: Buffer | Uint8Array): any;
@@ -5,19 +5,26 @@ export class BinaryReader {
5
5
  targetView;
6
6
  _last;
7
7
  _dict;
8
+ extensions;
8
9
  offset;
9
10
  length;
10
11
  /**
11
12
  * Small utility class to read binary data.
12
13
  * @param data {Buffer}
13
14
  */
14
- constructor(data) {
15
+ constructor(data, options) {
15
16
  this.target = data;
16
17
  this.targetView = new DataView(data.buffer, 0, data.length);
17
18
  this._last = undefined;
18
19
  this._dict = new Map();
19
20
  this.offset = 0;
20
21
  this.length = data.length;
22
+ this.extensions = new Map();
23
+ if (options && options.extensions) {
24
+ options.extensions.forEach((ext) => {
25
+ this.extensions.set(ext.token, ext);
26
+ });
27
+ }
21
28
  }
22
29
  readByte() {
23
30
  this.assertRead(1);
@@ -41,7 +48,7 @@ export class BinaryReader {
41
48
  this._last = this.targetView.getInt16(this.offset, true);
42
49
  }
43
50
  else {
44
- this._last = this.targetView.getUint16(this.offset);
51
+ this._last = this.targetView.getUint16(this.offset, true);
45
52
  }
46
53
  this.offset += 2;
47
54
  return this._last;
@@ -52,7 +59,7 @@ export class BinaryReader {
52
59
  this._last = this.targetView.getInt8(this.offset);
53
60
  }
54
61
  else {
55
- this._last = this.targetView.getInt8(this.offset);
62
+ this._last = this.targetView.getUint8(this.offset);
56
63
  }
57
64
  this.offset += 1;
58
65
  return this._last;
@@ -162,7 +169,20 @@ export class BinaryReader {
162
169
  * Reads a object.
163
170
  */
164
171
  readObject() {
172
+ const offset = this.offset;
165
173
  const constructorId = this.readByte();
174
+ const ext = this.extensions.get(constructorId);
175
+ let value;
176
+ if (ext) {
177
+ value = this.readObject();
178
+ value = ext.decode(value);
179
+ }
180
+ else {
181
+ value = this.readCore(constructorId);
182
+ }
183
+ return value;
184
+ }
185
+ readCore(constructorId) {
166
186
  switch (constructorId) {
167
187
  case CORE_TYPES.None:
168
188
  return this.readObject();
@@ -203,22 +223,27 @@ export class BinaryReader {
203
223
  }
204
224
  readDictionary() {
205
225
  const constructorId = this.readByte();
226
+ let key = null;
206
227
  switch (constructorId) {
207
228
  case CORE_TYPES.DictIndex: {
208
229
  const idx = this.readLength();
209
- return this._dict.get(idx);
230
+ key = this._dict.get(idx);
231
+ break;
210
232
  }
211
233
  case CORE_TYPES.DictValue: {
212
- const key = this.readString();
234
+ key = this.readString();
213
235
  this._dict.set(this._dict.size + 1, key);
214
- return key;
236
+ break;
215
237
  }
216
238
  case CORE_TYPES.None: {
217
- return null;
239
+ key = null;
240
+ break;
241
+ }
242
+ default: {
243
+ this.seek(-1);
218
244
  }
219
245
  }
220
- this.seek(-1);
221
- return null;
246
+ return key;
222
247
  }
223
248
  readMap(checkConstructor = true) {
224
249
  if (checkConstructor && this.readByte() !== CORE_TYPES.Map) {
@@ -1,10 +1,15 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
+ import { TLExtension } from './extension.js';
3
+ export interface BinaryWriterOptions {
4
+ extensions?: TLExtension[];
5
+ }
2
6
  export declare class BinaryWriter {
3
7
  private target;
4
8
  private targetView;
5
9
  private dict;
10
+ private extensions;
6
11
  offset: number;
7
- constructor();
12
+ constructor(options?: BinaryWriterOptions);
8
13
  allocate(size: number): void;
9
14
  makeRoom(end: number): void;
10
15
  get safeEnd(): number;
@@ -25,5 +30,7 @@ export declare class BinaryWriter {
25
30
  writeMap(object: Record<string, any>): void;
26
31
  wireDictionary(value: string): void;
27
32
  encode(value: any): Uint8Array | Buffer;
33
+ private _writeCustom;
28
34
  writeObject(value: any): void;
35
+ private writeCore;
29
36
  }
@@ -21,11 +21,17 @@ export class BinaryWriter {
21
21
  target;
22
22
  targetView;
23
23
  dict;
24
+ extensions;
24
25
  offset;
25
- constructor() {
26
- this.target = Buffer.alloc(0);
26
+ constructor(options) {
27
27
  this.dict = new Map();
28
28
  this.offset = 0;
29
+ this.extensions = new Map();
30
+ if (options && options.extensions) {
31
+ options.extensions.forEach((ext) => {
32
+ this.extensions.set(ext.token, ext);
33
+ });
34
+ }
29
35
  this.target = byteArrayAllocate(8192);
30
36
  this.targetView = new DataView(this.target.buffer, 0, this.target.length);
31
37
  }
@@ -105,7 +111,12 @@ export class BinaryWriter {
105
111
  }
106
112
  writeInt8(value, signed = true) {
107
113
  this.allocate(1);
108
- this.target[this.offset++] = value;
114
+ if (signed) {
115
+ this.target[this.offset++] = value;
116
+ }
117
+ else {
118
+ this.targetView.setUint8(this.offset++, value);
119
+ }
109
120
  }
110
121
  writeFloat(value) {
111
122
  this.allocate(4);
@@ -150,8 +161,6 @@ export class BinaryWriter {
150
161
  this.target[start++] = (bytes >> 16) % 256;
151
162
  }
152
163
  this.offset += bytes;
153
- // this.target.set(bytes, this.offset);
154
- // this.offset += bytes.length;
155
164
  }
156
165
  writeBytes(value) {
157
166
  const length = value.length;
@@ -177,11 +186,18 @@ export class BinaryWriter {
177
186
  const length = value.length;
178
187
  this.writeLength(length);
179
188
  for (let i = 0; i < length; i++) {
180
- this.writeObject(value[i]);
189
+ if (value[i] === undefined) {
190
+ this.writeNull();
191
+ }
192
+ else {
193
+ this.writeObject(value[i]);
194
+ }
181
195
  }
182
196
  }
183
197
  writeMap(object) {
184
198
  for (const key in object) {
199
+ if (object[key] === undefined)
200
+ continue;
185
201
  this.wireDictionary(key);
186
202
  this.writeObject(object[key]);
187
203
  }
@@ -190,14 +206,12 @@ export class BinaryWriter {
190
206
  wireDictionary(value) {
191
207
  if (this.dict.has(value)) {
192
208
  const idx = this.dict.get(value);
193
- this.writeByte(CORE_TYPES.DictIndex);
194
- this.writeLength(idx);
209
+ this.writeCore(CORE_TYPES.DictIndex, idx);
195
210
  }
196
211
  else {
197
212
  const newIndex = this.dict.size + 1;
198
213
  this.dict.set(value, newIndex);
199
- this.writeByte(CORE_TYPES.DictValue);
200
- this.writeString(value);
214
+ this.writeCore(CORE_TYPES.DictValue, value);
201
215
  }
202
216
  }
203
217
  encode(value) {
@@ -207,18 +221,54 @@ export class BinaryWriter {
207
221
  this.offset = start;
208
222
  return this.target.subarray(start, end);
209
223
  }
224
+ _writeCustom(value) {
225
+ for (const ext of this.extensions.values()) {
226
+ const result = ext.encode(value);
227
+ if (result !== undefined) {
228
+ const constructorId = coreType(result);
229
+ if (constructorId === CORE_TYPES.None) {
230
+ throw new TypeError(`Invalid encode extension = ${ext.token} type of ${value}`);
231
+ }
232
+ if (ext.token !== -1) {
233
+ this.writeByte(ext.token);
234
+ }
235
+ this.writeCore(constructorId, result);
236
+ return true;
237
+ }
238
+ }
239
+ return false;
240
+ }
210
241
  writeObject(value) {
211
242
  if (value === undefined)
212
243
  return;
213
244
  const constructorId = coreType(value);
245
+ // console.log('write', {
246
+ // offset: this.offset,
247
+ // constructorId: CORE_TYPES[constructorId],
248
+ // value: String(value),
249
+ // });
214
250
  if (constructorId === CORE_TYPES.None) {
215
- throw new TypeError(`Invalid core type of ${typeof value}`);
251
+ if (this._writeCustom(value)) {
252
+ return;
253
+ }
254
+ throw new TypeError(`Invalid core type of ${value}`);
216
255
  }
256
+ this.writeCore(constructorId, value);
257
+ }
258
+ writeCore(constructorId, value) {
217
259
  if (![CORE_TYPES.BoolFalse, CORE_TYPES.BoolTrue, CORE_TYPES.Null].includes(constructorId)) {
218
260
  this.writeByte(constructorId);
219
261
  }
220
262
  switch (constructorId) {
221
- case CORE_TYPES.BoolFalse:
263
+ case CORE_TYPES.DictIndex: {
264
+ return this.writeLength(value);
265
+ }
266
+ case CORE_TYPES.DictValue: {
267
+ return this.writeString(value);
268
+ }
269
+ case CORE_TYPES.BoolFalse: {
270
+ return this.writeBool(value);
271
+ }
222
272
  case CORE_TYPES.BoolTrue: {
223
273
  return this.writeBool(value);
224
274
  }
@@ -0,0 +1,11 @@
1
+ export type EncodeHandler = (value: any) => string | number | undefined;
2
+ export type DecodeHandler = (value: string | number) => any;
3
+ export interface TLExtension {
4
+ token: number;
5
+ encode: EncodeHandler;
6
+ decode: DecodeHandler;
7
+ }
8
+ export declare function createExtension(token: number, { encode, decode }: {
9
+ encode: EncodeHandler;
10
+ decode: DecodeHandler;
11
+ }): TLExtension;
@@ -0,0 +1,10 @@
1
+ export function createExtension(token, { encode, decode }) {
2
+ if (token !== -1 && (token > 254 || token < 0 || token << 0 !== token)) {
3
+ throw new TypeError('Token must be a 8 bit number');
4
+ }
5
+ return {
6
+ token,
7
+ encode,
8
+ decode,
9
+ };
10
+ }
package/dist/helpers.js CHANGED
@@ -95,11 +95,32 @@ export function coreType(value) {
95
95
  if (Array.isArray(value)) {
96
96
  return CORE_TYPES.Vector;
97
97
  }
98
- // @ts-ignore
99
- if (toString.call(value) === '[object Object]') {
98
+ if (isPlainObject(value)) {
100
99
  return CORE_TYPES.Map;
101
100
  }
102
101
  }
103
102
  }
104
103
  return CORE_TYPES.None;
105
104
  }
105
+ /** @ts-ignore */
106
+ const isObject = (val) => toString.call(val) === '[object Object]';
107
+ function isPlainObject(value) {
108
+ let ctor, prot;
109
+ if (!isObject(value))
110
+ return false;
111
+ // If it has modified constructor
112
+ ctor = value.constructor;
113
+ if (ctor === undefined)
114
+ return true;
115
+ // If it has modified prototype
116
+ prot = ctor.prototype;
117
+ if (isObject(prot) === false)
118
+ return false;
119
+ // If constructor does not have an Object-specific method
120
+ // eslint-disable-next-line no-prototype-builtins
121
+ if (prot.hasOwnProperty('isPrototypeOf') === false) {
122
+ return false;
123
+ }
124
+ // Most likely a plain Object
125
+ return true;
126
+ }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
- export { BinaryWriter } from './BinaryWriter.js';
2
- export { BinaryReader } from './BinaryReader.js';
1
+ export * from './BinaryWriter.js';
2
+ export * from './BinaryReader.js';
3
3
  export * from './constants.js';
4
+ export * from './extension.js';
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
- export { BinaryWriter } from './BinaryWriter.js';
2
- export { BinaryReader } from './BinaryReader.js';
1
+ export * from './BinaryWriter.js';
2
+ export * from './BinaryReader.js';
3
3
  export * from './constants.js';
4
+ export * from './extension.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andrew_l/tl-pack",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "scripts": {