@cloudpss/ubjson 0.4.32 → 0.4.34

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.
Files changed (59) hide show
  1. package/dist/common/constants.d.ts +22 -20
  2. package/dist/common/constants.js +1 -21
  3. package/dist/common/constants.js.map +1 -1
  4. package/dist/common/decoder.d.ts +4 -20
  5. package/dist/common/decoder.js +217 -178
  6. package/dist/common/decoder.js.map +1 -1
  7. package/dist/common/encoder.d.ts +8 -54
  8. package/dist/common/encoder.js +241 -259
  9. package/dist/common/encoder.js.map +1 -1
  10. package/dist/common/string-decoder.d.ts +3 -8
  11. package/dist/common/string-decoder.js +190 -46
  12. package/dist/common/string-decoder.js.map +1 -1
  13. package/dist/common/string-encoder.d.ts +2 -8
  14. package/dist/common/string-encoder.js +8 -44
  15. package/dist/common/string-encoder.js.map +1 -1
  16. package/dist/encoder.js +2 -21
  17. package/dist/encoder.js.map +1 -1
  18. package/dist/index.d.ts +1 -2
  19. package/dist/index.js +2 -4
  20. package/dist/index.js.map +1 -1
  21. package/dist/rxjs/decoder.js +2 -2
  22. package/dist/rxjs/decoder.js.map +1 -1
  23. package/dist/rxjs/index.d.ts +1 -0
  24. package/dist/rxjs/index.js +1 -0
  25. package/dist/rxjs/index.js.map +1 -1
  26. package/dist/stream/index.d.ts +1 -0
  27. package/dist/stream/index.js +2 -1
  28. package/dist/stream/index.js.map +1 -1
  29. package/dist/stream-helper/decoder.d.ts +1 -1
  30. package/dist/stream-helper/decoder.js +1 -1
  31. package/dist/stream-helper/decoder.js.map +1 -1
  32. package/dist/stream-helper/encoder.js +2 -2
  33. package/dist/stream-helper/encoder.js.map +1 -1
  34. package/dist/utils.d.ts +5 -1
  35. package/dist/utils.js +13 -4
  36. package/dist/utils.js.map +1 -1
  37. package/package.json +3 -2
  38. package/src/common/constants.ts +22 -21
  39. package/src/common/decoder.ts +197 -162
  40. package/src/common/encoder.ts +230 -277
  41. package/src/common/string-decoder.ts +173 -41
  42. package/src/common/string-encoder.ts +10 -41
  43. package/src/encoder.ts +2 -16
  44. package/src/index.ts +2 -5
  45. package/src/rxjs/decoder.ts +2 -2
  46. package/src/rxjs/index.ts +1 -0
  47. package/src/stream/index.ts +2 -0
  48. package/src/stream-helper/decoder.ts +1 -1
  49. package/src/stream-helper/encoder.ts +2 -2
  50. package/src/utils.ts +14 -4
  51. package/tests/decode.js +69 -5
  52. package/tests/e2e.js +12 -1
  53. package/tests/encode.js +52 -23
  54. package/tests/rxjs/decode.js +3 -2
  55. package/tests/rxjs/encode.js +5 -8
  56. package/tests/stream/decode.js +2 -1
  57. package/tests/stream/encode.js +4 -5
  58. package/tests/string-encoding.js +77 -25
  59. package/tsconfig.json +3 -1
@@ -1,10 +1,10 @@
1
- import * as constants from './constants.js';
2
- import { StringEncoder } from './string-encoder.js';
1
+ import { constants } from './constants.js';
2
+ import { getStringByteLength, getEncodeInto } from './string-encoder.js';
3
3
 
4
4
  /** 编码至 ubjson */
5
5
  export abstract class EncoderBase {
6
- /** 字符串编码 */
7
- protected stringEncoder = new StringEncoder();
6
+ protected readonly stringByteLength = getStringByteLength();
7
+ protected readonly encodeInto = getEncodeInto();
8
8
  /** 当前写指针位置 */
9
9
  protected length = 0;
10
10
  /** 数据 */
@@ -17,305 +17,258 @@ export abstract class EncoderBase {
17
17
  * 确保 buffer 还有 capacity 的空闲空间
18
18
  */
19
19
  protected abstract ensureCapacity(capacity: number): void;
20
+
21
+ /** 编码至 ubjson */
22
+ protected writeValue(): void {
23
+ if (this.value === undefined) {
24
+ this.ensureCapacity(1);
25
+ this.buffer[this.length++] = constants.NO_OP;
26
+ return;
27
+ }
28
+ this.write(this.value);
29
+ }
20
30
  /** 写入一个对象 */
21
- protected write(value: unknown): void {
31
+ private write(value: unknown): void {
22
32
  switch (typeof value) {
23
- case 'undefined':
24
- return this.writeNoOp();
25
- case 'boolean':
26
- return this.writeBoolean(value);
27
- case 'number':
28
- return this.writeNumber(value);
29
33
  case 'string':
30
- if (value.length === 1 && value.charCodeAt(0) < 255) {
31
- // 1 byte string
32
- return this.writeChar(value);
34
+ if (value.length === 1 && value.charCodeAt(0) < 128) {
35
+ // 1 byte ascii char
36
+ this.ensureCapacity(2);
37
+ this.buffer[this.length++] = constants.CHAR;
38
+ this.buffer[this.length++] = value.charCodeAt(0);
39
+ } else {
40
+ this.ensureCapacity(2);
41
+ this.buffer[this.length++] = constants.STRING;
42
+ this.writeStringData(value);
33
43
  }
34
- return this.writeString(value);
44
+ return;
45
+ case 'number':
46
+ // eslint-disable-next-line unicorn/prefer-math-trunc
47
+ if ((value | 0) === value) {
48
+ if (value >= 0 && value <= 255) {
49
+ this.ensureCapacity(2);
50
+ this.buffer[this.length++] = constants.UINT8;
51
+ this.buffer[this.length++] = value;
52
+ } else if (value >= -128 && value <= 127) {
53
+ this.ensureCapacity(2);
54
+ this.buffer[this.length++] = constants.INT8;
55
+ this.buffer[this.length++] = value;
56
+ } else if (value >= -32768 && value <= 32767) {
57
+ this.ensureCapacity(3);
58
+ this.buffer[this.length++] = constants.INT16;
59
+ this.buffer[this.length++] = value >> 8;
60
+ this.buffer[this.length++] = value & 0xff;
61
+ } else {
62
+ this.ensureCapacity(5);
63
+ this.buffer[this.length++] = constants.INT32;
64
+ this.view.setInt32(this.length, value);
65
+ this.length += 4;
66
+ }
67
+ } else if (Number.isNaN(value) || Math.fround(value) === value) {
68
+ // 如果不会损失精度,使用 32 位浮点
69
+ this.ensureCapacity(5);
70
+ this.buffer[this.length++] = constants.FLOAT32;
71
+ this.view.setFloat32(this.length, value);
72
+ this.length += 4;
73
+ } else {
74
+ this.ensureCapacity(9);
75
+ this.buffer[this.length++] = constants.FLOAT64;
76
+ this.view.setFloat64(this.length, value);
77
+ this.length += 8;
78
+ }
79
+ return;
35
80
  case 'object': {
36
81
  if (value === null) {
37
- return this.writeNull();
38
- }
39
- if (Array.isArray(value)) {
40
- return this.writeArray(value);
41
- }
42
- if (ArrayBuffer.isView(value)) {
43
- return this.writeTypedArray(value);
82
+ this.ensureCapacity(1);
83
+ this.buffer[this.length++] = constants.NULL;
84
+ } else if (Array.isArray(value)) {
85
+ this.ensureCapacity(1);
86
+ this.buffer[this.length++] = constants.ARRAY;
87
+ const size = value.length;
88
+ for (let index = 0; index < size; index++) {
89
+ const element = value[index] as unknown;
90
+ // 在数组中 undefined 和 function 也被视作 null 进行序列化
91
+ if (element == null || typeof element == 'function') {
92
+ this.ensureCapacity(1);
93
+ this.buffer[this.length++] = constants.NULL;
94
+ } else {
95
+ this.write(element);
96
+ }
97
+ }
98
+ this.ensureCapacity(1);
99
+ this.buffer[this.length++] = constants.ARRAY_END;
100
+ } else if (!ArrayBuffer.isView(value)) {
101
+ const toJSON = typeof (value as Record<string, unknown>)['toJSON'] == 'function';
102
+ if (toJSON) {
103
+ this.write((value as { toJSON: () => unknown }).toJSON());
104
+ return;
105
+ }
106
+ this.ensureCapacity(1);
107
+ this.buffer[this.length++] = constants.OBJECT;
108
+ // 生成稳定的结果以便 hash 计算
109
+ const keys = Object.keys(value).sort();
110
+ const size = keys.length;
111
+ for (let index = 0; index < size; index++) {
112
+ const key = keys[index];
113
+ const element = (value as Record<string, unknown>)[key];
114
+ if (element === undefined || typeof element == 'function') continue;
115
+ this.writeStringData(key);
116
+ this.write(element);
117
+ }
118
+ this.ensureCapacity(1);
119
+ this.buffer[this.length++] = constants.OBJECT_END;
120
+ } else {
121
+ // ARRAY(1) + TYPE_MARKER(1) + TYPE(1) + COUNT_MARKER(1) + COUNT(MAX5) + DATA
122
+ this.ensureCapacity(9 + value.byteLength);
123
+ this.buffer[this.length++] = constants.ARRAY;
124
+ this.buffer[this.length++] = constants.TYPE_MARKER;
125
+ if (value instanceof Uint8Array || value instanceof Int8Array) {
126
+ // fast path for typed arrays with `BYTES_PER_ELEMENT` of 1
127
+ this.buffer[this.length++] = value instanceof Uint8Array ? constants.UINT8 : constants.INT8;
128
+ this.buffer[this.length++] = constants.COUNT_MARKER;
129
+ this.setLength(value.length);
130
+ this.buffer.set(value, this.length);
131
+ this.length += value.byteLength;
132
+ return;
133
+ }
134
+
135
+ const arrayLength = (value as Int16Array | Int32Array | Float32Array | Float64Array).length;
136
+ const elementSize = (value as Int16Array | Int32Array | Float32Array | Float64Array)
137
+ .BYTES_PER_ELEMENT;
138
+ if (value instanceof Int16Array) {
139
+ this.buffer[this.length++] = constants.INT16;
140
+ this.buffer[this.length++] = constants.COUNT_MARKER;
141
+ this.setLength(arrayLength);
142
+ for (let i = 0; i < arrayLength; i++) {
143
+ this.view.setInt16(this.length, value[i]);
144
+ this.length += elementSize;
145
+ }
146
+ } else if (value instanceof Int32Array) {
147
+ this.buffer[this.length++] = constants.INT32;
148
+ this.buffer[this.length++] = constants.COUNT_MARKER;
149
+ this.setLength(arrayLength);
150
+ for (let i = 0; i < arrayLength; i++) {
151
+ this.view.setInt32(this.length, value[i]);
152
+ this.length += elementSize;
153
+ }
154
+ } else if (value instanceof Float32Array) {
155
+ this.buffer[this.length++] = constants.FLOAT32;
156
+ this.buffer[this.length++] = constants.COUNT_MARKER;
157
+ this.setLength(arrayLength);
158
+ for (let i = 0; i < arrayLength; i++) {
159
+ this.view.setFloat32(this.length, value[i]);
160
+ this.length += elementSize;
161
+ }
162
+ } else if (value instanceof Float64Array) {
163
+ this.buffer[this.length++] = constants.FLOAT64;
164
+ this.buffer[this.length++] = constants.COUNT_MARKER;
165
+ this.setLength(arrayLength);
166
+ for (let i = 0; i < arrayLength; i++) {
167
+ this.view.setFloat64(this.length, value[i]);
168
+ this.length += elementSize;
169
+ }
170
+ } else {
171
+ throw new TypeError(`Unsupported typed array type ${Object.prototype.toString.call(value)}`);
172
+ }
44
173
  }
45
- return this.writeObject(value as Record<string, unknown>);
174
+ return;
46
175
  }
176
+ case 'boolean':
177
+ this.ensureCapacity(1);
178
+ this.buffer[this.length++] = value ? constants.TRUE : constants.FALSE;
179
+ return;
47
180
  default:
48
181
  throw new Error(`Unsupported type ${Object.prototype.toString.call(value)}`);
49
182
  }
50
183
  }
51
- /** 写入 marker */
52
- protected writeMarker(marker: number): void {
53
- this.ensureCapacity(1);
54
- this.view.setUint8(this.length, marker);
55
- this.length += 1;
56
- }
57
-
58
- /** 写入 marker */
59
- protected writeNull(): void {
60
- this.writeMarker(constants.NULL);
61
- }
62
-
63
- /** writeNoOp */
64
- protected writeNoOp(): void {
65
- this.writeMarker(constants.NO_OP);
66
- }
67
-
68
- /** writeBoolean */
69
- protected writeBoolean(value: boolean): void {
70
- this.writeMarker(value ? constants.TRUE : constants.FALSE);
71
- }
72
-
73
- /** writeInt8 */
74
- protected writeInt8(value: number): void {
75
- this.writeMarker(constants.INT8);
76
- this.writeInt8Data(value);
77
- }
78
-
79
- /** writeInt8Data */
80
- protected writeInt8Data(value: number): void {
81
- this.ensureCapacity(1);
82
- this.view.setInt8(this.length, value);
83
- this.length += 1;
84
- }
85
-
86
- /** writeUint8 */
87
- protected writeUint8(value: number): void {
88
- this.writeMarker(constants.UINT8);
89
- this.writeUint8Data(value);
90
- }
91
-
92
- /** writeUint8Data */
93
- protected writeUint8Data(value: number): void {
94
- this.ensureCapacity(1);
95
- this.view.setUint8(this.length, value);
96
- this.length += 1;
97
- }
98
-
99
- /** writeInt16 */
100
- protected writeInt16(value: number): void {
101
- this.writeMarker(constants.INT16);
102
- this.writeInt16Data(value);
103
- }
104
-
105
- /** writeInt16Data */
106
- protected writeInt16Data(value: number): void {
107
- this.ensureCapacity(2);
108
- this.view.setInt16(this.length, value);
109
- this.length += 2;
110
- }
111
-
112
- /** writeInt32 */
113
- protected writeInt32(value: number): void {
114
- this.writeMarker(constants.INT32);
115
- this.writeInt32Data(value);
116
- }
117
-
118
- /** writeInt32Data */
119
- protected writeInt32Data(value: number): void {
120
- this.ensureCapacity(4);
121
- this.view.setInt32(this.length, value);
122
- this.length += 4;
123
- }
124
-
125
- /** writeFloat32 */
126
- protected writeFloat32(value: number): void {
127
- this.writeMarker(constants.FLOAT32);
128
- this.writeFloat32Data(value);
129
- }
130
-
131
- /** writeFloat32Data */
132
- protected writeFloat32Data(value: number): void {
133
- this.ensureCapacity(4);
134
- this.view.setFloat32(this.length, value);
135
- this.length += 4;
136
- }
137
-
138
- /** writeFloat64 */
139
- protected writeFloat64(value: number): void {
140
- this.writeMarker(constants.FLOAT64);
141
- this.writeFloat64Data(value);
142
- }
143
-
144
- /** writeFloat64Data */
145
- protected writeFloat64Data(value: number): void {
146
- this.ensureCapacity(8);
147
- this.view.setFloat64(this.length, value);
148
- this.length += 8;
149
- }
150
-
151
- /** writeChar */
152
- protected writeChar(value: string): void {
153
- this.writeMarker(constants.CHAR);
154
- this.writeCharData(value);
155
- }
156
-
157
- /** writeCharData */
158
- protected writeCharData(value: string): void {
159
- this.ensureCapacity(1);
160
- this.view.setUint8(this.length, value.charCodeAt(0));
161
- this.length += 1;
162
- }
163
-
164
- /** writeString */
165
- protected writeString(value: string): void {
166
- this.writeMarker(constants.STRING);
167
- this.writeStringData(value);
168
- }
169
184
 
170
185
  /** writeStringData */
171
- protected writeStringData(value: string): void {
186
+ private writeStringData(value: string): void {
187
+ const strLength = value.length;
188
+ const maxUsage =
189
+ strLength < 65536
190
+ ? // 对于短字符串,直接计算最大使用空间
191
+ strLength * 3
192
+ : this.stringByteLength(value);
193
+ // 一次性分配 setLength 和 encodeInto 的空间,避免无法回溯
194
+ // 额外分配 3 字节,避免 encodeInto 无法写入最后一个字符
195
+ this.ensureCapacity(maxUsage + 5 + 3);
196
+
197
+ // 预估头部大小
198
+ const headerSize = strLength < 128 ? 2 : strLength < 32768 ? 3 : 5;
199
+ const headerPos = this.length;
200
+ let bufLength;
172
201
  // 优化小字符串
173
- if (value.length < 32 || this.stringEncoder.encodeInto == null) {
174
- const buf = this.stringEncoder.encode(value);
175
- this.writeInt(buf.length);
176
- this.ensureCapacity(buf.length);
177
- this.buffer.set(buf, this.length);
178
- this.length += buf.length;
179
- return;
180
- }
181
- let maxUsage = value.length;
182
- if (value.length < 65536) {
183
- // 对于短字符串,直接计算最大使用空间
184
- maxUsage = value.length * 3;
202
+ if (strLength < 0x40 || !this.encodeInto) {
203
+ let c1, c2;
204
+ let strPosition = headerPos + headerSize;
205
+ const target = this.buffer;
206
+ for (let i = 0; i < strLength; i++) {
207
+ c1 = value.charCodeAt(i);
208
+ if (c1 < 0x80) {
209
+ target[strPosition++] = c1;
210
+ } else if (c1 < 0x800) {
211
+ target[strPosition++] = (c1 >> 6) | 0xc0;
212
+ target[strPosition++] = (c1 & 0x3f) | 0x80;
213
+ } else if ((c1 & 0xfc00) === 0xd800 && ((c2 = value.charCodeAt(i + 1)) & 0xfc00) === 0xdc00) {
214
+ c1 = 0x1_0000 + ((c1 & 0x03ff) << 10) + (c2 & 0x03ff);
215
+ i++;
216
+ target[strPosition++] = (c1 >> 18) | 0xf0;
217
+ target[strPosition++] = ((c1 >> 12) & 0x3f) | 0x80;
218
+ target[strPosition++] = ((c1 >> 6) & 0x3f) | 0x80;
219
+ target[strPosition++] = (c1 & 0x3f) | 0x80;
220
+ } else {
221
+ target[strPosition++] = (c1 >> 12) | 0xe0;
222
+ target[strPosition++] = ((c1 >> 6) & 0x3f) | 0x80;
223
+ target[strPosition++] = (c1 & 0x3f) | 0x80;
224
+ }
225
+ }
226
+ bufLength = strPosition - headerPos - headerSize;
185
227
  } else {
186
- maxUsage = this.stringEncoder.byteLength(value);
228
+ bufLength = this.encodeInto(value, this.buffer, headerPos + headerSize);
187
229
  }
188
- // 一次性分配 writeInt encodeInto 的空间,避免无法回溯
189
- // 额外分配 3 字节,避免 encodeInto 无法写入最后一个字符
190
- this.ensureCapacity(maxUsage + 4 + 3);
191
- const currentPos = this.length;
192
- // 先写入最大大小
193
- const lengthWriter = this.writeInt(maxUsage);
194
- // 写入文本数据
195
- const { written, read } = this.stringEncoder.encodeInto(value, this.buffer.subarray(this.length));
196
- /* c8 ignore next 3 */
197
- if (read !== value.length) {
198
- throw new Error(`Failed to encode string with TextEncoder.encodeInto`);
230
+ if (bufLength < 128) {
231
+ this.buffer[this.length++] = constants.INT8;
232
+ this.buffer[this.length++] = bufLength;
233
+ } else if (bufLength < 32768) {
234
+ if (headerSize < 3) {
235
+ this.buffer.copyWithin(headerPos + 3, headerPos + headerSize, headerPos + headerSize + bufLength);
236
+ }
237
+ this.buffer[this.length++] = constants.INT16;
238
+ this.buffer[this.length++] = bufLength >> 8;
239
+ this.buffer[this.length++] = bufLength & 0xff;
240
+ } else {
241
+ if (headerSize < 5) {
242
+ this.buffer.copyWithin(headerPos + 5, headerPos + headerSize, headerPos + headerSize + bufLength);
243
+ }
244
+ this.buffer[this.length++] = constants.INT32;
245
+ this.view.setInt32(this.length, bufLength);
246
+ this.length += 4;
199
247
  }
200
- // 回溯,写入实际大小
201
- this.length = currentPos;
202
- lengthWriter.call(this, written!);
203
- // 移动指针到写入末尾
204
- this.length += written!;
248
+ this.length += bufLength;
205
249
  }
206
250
 
207
251
  /**
208
- * 写入整形数字,选取合适的大小
209
- * @throws 无法在 int32 范围内表示
252
+ * 写入整形数字,选取合适的大小,需提前分配空间
210
253
  */
211
- protected writeInt(value: number): (this: this, value: number) => void {
254
+ private setLength(value: number): number {
212
255
  // eslint-disable-next-line unicorn/prefer-math-trunc
213
256
  value = value | 0;
214
- if (value >= -128 && value <= 127) {
215
- this.writeInt8(value);
216
- /* eslint-disable-next-line @typescript-eslint/unbound-method */
217
- return this.writeInt8;
257
+ if ((value & 0x7f) === value) {
258
+ this.buffer[this.length++] = constants.INT8;
259
+ this.buffer[this.length++] = value;
260
+ return 1;
218
261
  }
219
262
  // 不使用 uint8 以保持兼容
220
- // if (value >= 0 && value <= 255) {
221
- // this.writeUint8(value);
222
- // /* eslint-disable-next-line @typescript-eslint/unbound-method */
223
- // return this.writeUint8;
224
- // }
225
- if (value >= -32768 && value <= 32767) {
226
- this.writeInt16(value);
227
- /* eslint-disable-next-line @typescript-eslint/unbound-method */
228
- return this.writeInt16;
229
- }
230
- if (value >= -2_147_483_648 && value <= 2_147_483_647) {
231
- this.writeInt32(value);
232
- /* eslint-disable-next-line @typescript-eslint/unbound-method */
233
- return this.writeInt32;
234
- }
235
- /* c8 ignore next 2 */
236
- throw new Error(`Unsupported int value ${value}: out of range`);
237
- }
238
-
239
- /** 写入数字,选取合适的大小 */
240
- protected writeNumber(value: number): void {
241
- if (Number.isInteger(value) && value >= -2_147_483_648 && value <= 2_147_483_647) {
242
- if (value >= 0 && value <= 255) return this.writeUint8(value);
243
- this.writeInt(value);
244
- return;
245
- }
246
- if (!(Number.isNaN(value) || Math.fround(value) === value)) {
247
- return this.writeFloat64(value);
248
- }
249
- // 如果不会损失精度,则使用 32 位浮点
250
- return this.writeFloat32(value);
251
- }
252
-
253
- /** writeObject */
254
- protected writeObject(value: Record<string, unknown>): void {
255
- this.writeMarker(constants.OBJECT);
256
- // 生成稳定的结果以便 hash 计算
257
- for (const key of Object.keys(value).sort()) {
258
- const element = value[key];
259
- if (element === undefined) continue;
260
- this.writeStringData(key);
261
- this.write(element);
262
- }
263
- this.writeMarker(constants.OBJECT_END);
264
- }
265
-
266
- /** writeArray */
267
- protected writeArray(value: unknown[]): void {
268
- this.writeMarker(constants.ARRAY);
269
- for (const v of value) {
270
- // 在数组中 undefined 也被视作 null 进行序列化
271
- if (v == null) this.writeNull();
272
- else this.write(v);
273
- }
274
- this.writeMarker(constants.ARRAY_END);
275
- }
276
-
277
- /** writeArray */
278
- protected writeTypedArray(value: ArrayBufferView): void {
279
- this.writeMarker(constants.ARRAY);
280
- this.writeMarker(constants.TYPE_MARKER);
281
- if (value instanceof Uint8Array || value instanceof Int8Array) {
282
- // fast path for typed arrays with `BYTES_PER_ELEMENT` of 1
283
- this.writeMarker(value instanceof Uint8Array ? constants.UINT8 : constants.INT8);
284
- this.writeMarker(constants.COUNT_MARKER);
285
- this.writeInt(value.length);
286
- this.ensureCapacity(value.byteLength);
287
- this.buffer.set(value, this.length);
288
- this.length += value.byteLength;
289
- return;
290
- }
291
- /** 用于写入的 setter */
292
- let setValue;
293
- if (value instanceof Int16Array) {
294
- this.writeMarker(constants.INT16);
295
- /* eslint-disable-next-line @typescript-eslint/unbound-method */
296
- setValue = this.view.setInt16;
297
- } else if (value instanceof Int32Array) {
298
- this.writeMarker(constants.INT32);
299
- /* eslint-disable-next-line @typescript-eslint/unbound-method */
300
- setValue = this.view.setInt32;
301
- } else if (value instanceof Float32Array) {
302
- this.writeMarker(constants.FLOAT32);
303
- /* eslint-disable-next-line @typescript-eslint/unbound-method */
304
- setValue = this.view.setFloat32;
305
- } else if (value instanceof Float64Array) {
306
- this.writeMarker(constants.FLOAT64);
307
- /* eslint-disable-next-line @typescript-eslint/unbound-method */
308
- setValue = this.view.setFloat64;
309
- } else {
310
- throw new TypeError(`Unsupported typed array type ${Object.prototype.toString.call(value)}`);
311
- }
312
- this.writeMarker(constants.COUNT_MARKER);
313
- this.writeInt(value.length);
314
- this.ensureCapacity(value.byteLength);
315
- // 不要在前面 bind,this.ensureCapacity 有可能导致 this.view 指向新的对象
316
- for (const v of value) {
317
- setValue.call(this.view, this.length, v);
318
- this.length += value.BYTES_PER_ELEMENT;
263
+ if ((value & 0x7fff) === value) {
264
+ this.buffer[this.length++] = constants.INT16;
265
+ this.buffer[this.length++] = value >> 8;
266
+ this.buffer[this.length++] = value & 0xff;
267
+ return 2;
319
268
  }
269
+ this.buffer[this.length++] = constants.INT32;
270
+ this.view.setInt32(this.length, value);
271
+ this.length += 4;
272
+ return 4;
320
273
  }
321
274
  }