bson 6.2.0 → 6.4.0

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/lib/bson.mjs CHANGED
@@ -95,8 +95,8 @@ class BSONError extends Error {
95
95
  get name() {
96
96
  return 'BSONError';
97
97
  }
98
- constructor(message) {
99
- super(message);
98
+ constructor(message, options) {
99
+ super(message, options);
100
100
  }
101
101
  static isBSONError(value) {
102
102
  return (value != null &&
@@ -125,6 +125,94 @@ class BSONRuntimeError extends BSONError {
125
125
  }
126
126
  }
127
127
 
128
+ const FIRST_BIT = 0x80;
129
+ const FIRST_TWO_BITS = 0xc0;
130
+ const FIRST_THREE_BITS = 0xe0;
131
+ const FIRST_FOUR_BITS = 0xf0;
132
+ const FIRST_FIVE_BITS = 0xf8;
133
+ const TWO_BIT_CHAR = 0xc0;
134
+ const THREE_BIT_CHAR = 0xe0;
135
+ const FOUR_BIT_CHAR = 0xf0;
136
+ const CONTINUING_CHAR = 0x80;
137
+ function validateUtf8(bytes, start, end) {
138
+ let continuation = 0;
139
+ for (let i = start; i < end; i += 1) {
140
+ const byte = bytes[i];
141
+ if (continuation) {
142
+ if ((byte & FIRST_TWO_BITS) !== CONTINUING_CHAR) {
143
+ return false;
144
+ }
145
+ continuation -= 1;
146
+ }
147
+ else if (byte & FIRST_BIT) {
148
+ if ((byte & FIRST_THREE_BITS) === TWO_BIT_CHAR) {
149
+ continuation = 1;
150
+ }
151
+ else if ((byte & FIRST_FOUR_BITS) === THREE_BIT_CHAR) {
152
+ continuation = 2;
153
+ }
154
+ else if ((byte & FIRST_FIVE_BITS) === FOUR_BIT_CHAR) {
155
+ continuation = 3;
156
+ }
157
+ else {
158
+ return false;
159
+ }
160
+ }
161
+ }
162
+ return !continuation;
163
+ }
164
+
165
+ function tryReadBasicLatin(uint8array, start, end) {
166
+ if (uint8array.length === 0) {
167
+ return '';
168
+ }
169
+ const stringByteLength = end - start;
170
+ if (stringByteLength === 0) {
171
+ return '';
172
+ }
173
+ if (stringByteLength > 20) {
174
+ return null;
175
+ }
176
+ if (stringByteLength === 1 && uint8array[start] < 128) {
177
+ return String.fromCharCode(uint8array[start]);
178
+ }
179
+ if (stringByteLength === 2 && uint8array[start] < 128 && uint8array[start + 1] < 128) {
180
+ return String.fromCharCode(uint8array[start]) + String.fromCharCode(uint8array[start + 1]);
181
+ }
182
+ if (stringByteLength === 3 &&
183
+ uint8array[start] < 128 &&
184
+ uint8array[start + 1] < 128 &&
185
+ uint8array[start + 2] < 128) {
186
+ return (String.fromCharCode(uint8array[start]) +
187
+ String.fromCharCode(uint8array[start + 1]) +
188
+ String.fromCharCode(uint8array[start + 2]));
189
+ }
190
+ const latinBytes = [];
191
+ for (let i = start; i < end; i++) {
192
+ const byte = uint8array[i];
193
+ if (byte > 127) {
194
+ return null;
195
+ }
196
+ latinBytes.push(byte);
197
+ }
198
+ return String.fromCharCode(...latinBytes);
199
+ }
200
+ function tryWriteBasicLatin(destination, source, offset) {
201
+ if (source.length === 0)
202
+ return 0;
203
+ if (source.length > 25)
204
+ return null;
205
+ if (destination.length - offset < source.length)
206
+ return null;
207
+ for (let charOffset = 0, destinationOffset = offset; charOffset < source.length; charOffset++, destinationOffset++) {
208
+ const char = source.charCodeAt(charOffset);
209
+ if (char > 127)
210
+ return null;
211
+ destination[destinationOffset] = char;
212
+ }
213
+ return source.length;
214
+ }
215
+
128
216
  function nodejsMathRandomBytes(byteLength) {
129
217
  return nodeJsByteUtils.fromNumberArray(Array.from({ length: byteLength }, () => Math.floor(Math.random() * 256)));
130
218
  }
@@ -156,6 +244,9 @@ const nodeJsByteUtils = {
156
244
  allocate(size) {
157
245
  return Buffer.alloc(size);
158
246
  },
247
+ allocateUnsafe(size) {
248
+ return Buffer.allocUnsafe(size);
249
+ },
159
250
  equals(a, b) {
160
251
  return nodeJsByteUtils.toLocalBufferType(a).equals(b);
161
252
  },
@@ -180,16 +271,32 @@ const nodeJsByteUtils = {
180
271
  toHex(buffer) {
181
272
  return nodeJsByteUtils.toLocalBufferType(buffer).toString('hex');
182
273
  },
183
- fromUTF8(text) {
184
- return Buffer.from(text, 'utf8');
185
- },
186
- toUTF8(buffer, start, end) {
187
- return nodeJsByteUtils.toLocalBufferType(buffer).toString('utf8', start, end);
274
+ toUTF8(buffer, start, end, fatal) {
275
+ const basicLatin = end - start <= 20 ? tryReadBasicLatin(buffer, start, end) : null;
276
+ if (basicLatin != null) {
277
+ return basicLatin;
278
+ }
279
+ const string = nodeJsByteUtils.toLocalBufferType(buffer).toString('utf8', start, end);
280
+ if (fatal) {
281
+ for (let i = 0; i < string.length; i++) {
282
+ if (string.charCodeAt(i) === 0xfffd) {
283
+ if (!validateUtf8(buffer, start, end)) {
284
+ throw new BSONError('Invalid UTF-8 string in BSON document');
285
+ }
286
+ break;
287
+ }
288
+ }
289
+ }
290
+ return string;
188
291
  },
189
292
  utf8ByteLength(input) {
190
293
  return Buffer.byteLength(input, 'utf8');
191
294
  },
192
295
  encodeUTF8Into(buffer, source, byteOffset) {
296
+ const latinBytesWritten = tryWriteBasicLatin(buffer, source, byteOffset);
297
+ if (latinBytesWritten != null) {
298
+ return latinBytesWritten;
299
+ }
193
300
  return nodeJsByteUtils.toLocalBufferType(buffer).write(source, byteOffset, undefined, 'utf8');
194
301
  },
195
302
  randomBytes: nodejsRandomBytes
@@ -245,6 +352,9 @@ const webByteUtils = {
245
352
  }
246
353
  return new Uint8Array(size);
247
354
  },
355
+ allocateUnsafe(size) {
356
+ return webByteUtils.allocate(size);
357
+ },
248
358
  equals(a, b) {
249
359
  if (a.byteLength !== b.byteLength) {
250
360
  return false;
@@ -291,18 +401,27 @@ const webByteUtils = {
291
401
  toHex(uint8array) {
292
402
  return Array.from(uint8array, byte => byte.toString(16).padStart(2, '0')).join('');
293
403
  },
294
- fromUTF8(text) {
295
- return new TextEncoder().encode(text);
296
- },
297
- toUTF8(uint8array, start, end) {
298
- return new TextDecoder('utf8', { fatal: false }).decode(uint8array.slice(start, end));
404
+ toUTF8(uint8array, start, end, fatal) {
405
+ const basicLatin = end - start <= 20 ? tryReadBasicLatin(uint8array, start, end) : null;
406
+ if (basicLatin != null) {
407
+ return basicLatin;
408
+ }
409
+ if (fatal) {
410
+ try {
411
+ return new TextDecoder('utf8', { fatal }).decode(uint8array.slice(start, end));
412
+ }
413
+ catch (cause) {
414
+ throw new BSONError('Invalid UTF-8 string in BSON document', { cause });
415
+ }
416
+ }
417
+ return new TextDecoder('utf8', { fatal }).decode(uint8array.slice(start, end));
299
418
  },
300
419
  utf8ByteLength(input) {
301
- return webByteUtils.fromUTF8(input).byteLength;
420
+ return new TextEncoder().encode(input).byteLength;
302
421
  },
303
- encodeUTF8Into(buffer, source, byteOffset) {
304
- const bytes = webByteUtils.fromUTF8(source);
305
- buffer.set(bytes, byteOffset);
422
+ encodeUTF8Into(uint8array, source, byteOffset) {
423
+ const bytes = new TextEncoder().encode(source);
424
+ uint8array.set(bytes, byteOffset);
306
425
  return bytes.byteLength;
307
426
  },
308
427
  randomBytes: webRandomBytes
@@ -310,11 +429,6 @@ const webByteUtils = {
310
429
 
311
430
  const hasGlobalBuffer = typeof Buffer === 'function' && Buffer.prototype?._isBuffer !== true;
312
431
  const ByteUtils = hasGlobalBuffer ? nodeJsByteUtils : webByteUtils;
313
- class BSONDataView extends DataView {
314
- static fromUint8Array(input) {
315
- return new DataView(input.buffer, input.byteOffset, input.byteLength);
316
- }
317
- }
318
432
 
319
433
  class BSONValue {
320
434
  get [Symbol.for('@@mdb.bson.version')]() {
@@ -416,8 +530,8 @@ class Binary extends BSONValue {
416
530
  if (encoding === 'base64')
417
531
  return ByteUtils.toBase64(this.buffer);
418
532
  if (encoding === 'utf8' || encoding === 'utf-8')
419
- return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength);
420
- return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength);
533
+ return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength, false);
534
+ return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength, false);
421
535
  }
422
536
  toExtendedJSON(options) {
423
537
  options = options || {};
@@ -1734,7 +1848,7 @@ class Decimal128 extends BSONValue {
1734
1848
  if (isNegative) {
1735
1849
  dec.high = dec.high.or(Long.fromString('9223372036854775808'));
1736
1850
  }
1737
- const buffer = ByteUtils.allocate(16);
1851
+ const buffer = ByteUtils.allocateUnsafe(16);
1738
1852
  index = 0;
1739
1853
  buffer[index++] = dec.low.low & 0xff;
1740
1854
  buffer[index++] = (dec.low.low >> 8) & 0xff;
@@ -2007,9 +2121,99 @@ class MinKey extends BSONValue {
2007
2121
  }
2008
2122
  }
2009
2123
 
2124
+ const FLOAT = new Float64Array(1);
2125
+ const FLOAT_BYTES = new Uint8Array(FLOAT.buffer, 0, 8);
2126
+ const NumberUtils = {
2127
+ getInt32LE(source, offset) {
2128
+ return (source[offset] |
2129
+ (source[offset + 1] << 8) |
2130
+ (source[offset + 2] << 16) |
2131
+ (source[offset + 3] << 24));
2132
+ },
2133
+ getUint32LE(source, offset) {
2134
+ return (source[offset] +
2135
+ source[offset + 1] * 256 +
2136
+ source[offset + 2] * 65536 +
2137
+ source[offset + 3] * 16777216);
2138
+ },
2139
+ getUint32BE(source, offset) {
2140
+ return (source[offset + 3] +
2141
+ source[offset + 2] * 256 +
2142
+ source[offset + 1] * 65536 +
2143
+ source[offset] * 16777216);
2144
+ },
2145
+ getBigInt64LE(source, offset) {
2146
+ const lo = NumberUtils.getUint32LE(source, offset);
2147
+ const hi = NumberUtils.getUint32LE(source, offset + 4);
2148
+ return (BigInt(hi) << BigInt(32)) + BigInt(lo);
2149
+ },
2150
+ getFloat64LE(source, offset) {
2151
+ FLOAT_BYTES[0] = source[offset];
2152
+ FLOAT_BYTES[1] = source[offset + 1];
2153
+ FLOAT_BYTES[2] = source[offset + 2];
2154
+ FLOAT_BYTES[3] = source[offset + 3];
2155
+ FLOAT_BYTES[4] = source[offset + 4];
2156
+ FLOAT_BYTES[5] = source[offset + 5];
2157
+ FLOAT_BYTES[6] = source[offset + 6];
2158
+ FLOAT_BYTES[7] = source[offset + 7];
2159
+ return FLOAT[0];
2160
+ },
2161
+ setInt32BE(destination, offset, value) {
2162
+ destination[offset + 3] = value;
2163
+ value >>>= 8;
2164
+ destination[offset + 2] = value;
2165
+ value >>>= 8;
2166
+ destination[offset + 1] = value;
2167
+ value >>>= 8;
2168
+ destination[offset] = value;
2169
+ return 4;
2170
+ },
2171
+ setInt32LE(destination, offset, value) {
2172
+ destination[offset] = value;
2173
+ value >>>= 8;
2174
+ destination[offset + 1] = value;
2175
+ value >>>= 8;
2176
+ destination[offset + 2] = value;
2177
+ value >>>= 8;
2178
+ destination[offset + 3] = value;
2179
+ return 4;
2180
+ },
2181
+ setBigInt64LE(destination, offset, value) {
2182
+ const mask32bits = BigInt(4294967295);
2183
+ let lo = Number(value & mask32bits);
2184
+ destination[offset] = lo;
2185
+ lo >>= 8;
2186
+ destination[offset + 1] = lo;
2187
+ lo >>= 8;
2188
+ destination[offset + 2] = lo;
2189
+ lo >>= 8;
2190
+ destination[offset + 3] = lo;
2191
+ let hi = Number((value >> BigInt(32)) & mask32bits);
2192
+ destination[offset + 4] = hi;
2193
+ hi >>= 8;
2194
+ destination[offset + 5] = hi;
2195
+ hi >>= 8;
2196
+ destination[offset + 6] = hi;
2197
+ hi >>= 8;
2198
+ destination[offset + 7] = hi;
2199
+ return 8;
2200
+ },
2201
+ setFloat64LE(destination, offset, value) {
2202
+ FLOAT[0] = value;
2203
+ destination[offset] = FLOAT_BYTES[0];
2204
+ destination[offset + 1] = FLOAT_BYTES[1];
2205
+ destination[offset + 2] = FLOAT_BYTES[2];
2206
+ destination[offset + 3] = FLOAT_BYTES[3];
2207
+ destination[offset + 4] = FLOAT_BYTES[4];
2208
+ destination[offset + 5] = FLOAT_BYTES[5];
2209
+ destination[offset + 6] = FLOAT_BYTES[6];
2210
+ destination[offset + 7] = FLOAT_BYTES[7];
2211
+ return 8;
2212
+ }
2213
+ };
2214
+
2010
2215
  const checkForHexRegExp = new RegExp('^[0-9a-fA-F]{24}$');
2011
2216
  let PROCESS_UNIQUE = null;
2012
- const kId = Symbol('id');
2013
2217
  class ObjectId extends BSONValue {
2014
2218
  get _bsontype() {
2015
2219
  return 'ObjectId';
@@ -2032,14 +2236,14 @@ class ObjectId extends BSONValue {
2032
2236
  workingId = inputId;
2033
2237
  }
2034
2238
  if (workingId == null || typeof workingId === 'number') {
2035
- this[kId] = ObjectId.generate(typeof workingId === 'number' ? workingId : undefined);
2239
+ this.buffer = ObjectId.generate(typeof workingId === 'number' ? workingId : undefined);
2036
2240
  }
2037
2241
  else if (ArrayBuffer.isView(workingId) && workingId.byteLength === 12) {
2038
- this[kId] = ByteUtils.toLocalBufferType(workingId);
2242
+ this.buffer = ByteUtils.toLocalBufferType(workingId);
2039
2243
  }
2040
2244
  else if (typeof workingId === 'string') {
2041
2245
  if (workingId.length === 24 && checkForHexRegExp.test(workingId)) {
2042
- this[kId] = ByteUtils.fromHex(workingId);
2246
+ this.buffer = ByteUtils.fromHex(workingId);
2043
2247
  }
2044
2248
  else {
2045
2249
  throw new BSONError('input must be a 24 character hex string, 12 byte Uint8Array, or an integer');
@@ -2053,10 +2257,10 @@ class ObjectId extends BSONValue {
2053
2257
  }
2054
2258
  }
2055
2259
  get id() {
2056
- return this[kId];
2260
+ return this.buffer;
2057
2261
  }
2058
2262
  set id(value) {
2059
- this[kId] = value;
2263
+ this.buffer = value;
2060
2264
  if (ObjectId.cacheHexString) {
2061
2265
  this.__id = ByteUtils.toHex(value);
2062
2266
  }
@@ -2079,8 +2283,8 @@ class ObjectId extends BSONValue {
2079
2283
  time = Math.floor(Date.now() / 1000);
2080
2284
  }
2081
2285
  const inc = ObjectId.getInc();
2082
- const buffer = ByteUtils.allocate(12);
2083
- BSONDataView.fromUint8Array(buffer).setUint32(0, time, false);
2286
+ const buffer = ByteUtils.allocateUnsafe(12);
2287
+ NumberUtils.setInt32BE(buffer, 0, time);
2084
2288
  if (PROCESS_UNIQUE === null) {
2085
2289
  PROCESS_UNIQUE = ByteUtils.randomBytes(5);
2086
2290
  }
@@ -2115,7 +2319,7 @@ class ObjectId extends BSONValue {
2115
2319
  return false;
2116
2320
  }
2117
2321
  if (ObjectId.is(otherId)) {
2118
- return this[kId][11] === otherId[kId][11] && ByteUtils.equals(this[kId], otherId[kId]);
2322
+ return (this.buffer[11] === otherId.buffer[11] && ByteUtils.equals(this.buffer, otherId.buffer));
2119
2323
  }
2120
2324
  if (typeof otherId === 'string') {
2121
2325
  return otherId.toLowerCase() === this.toHexString();
@@ -2129,16 +2333,33 @@ class ObjectId extends BSONValue {
2129
2333
  }
2130
2334
  getTimestamp() {
2131
2335
  const timestamp = new Date();
2132
- const time = BSONDataView.fromUint8Array(this.id).getUint32(0, false);
2336
+ const time = NumberUtils.getUint32BE(this.buffer, 0);
2133
2337
  timestamp.setTime(Math.floor(time) * 1000);
2134
2338
  return timestamp;
2135
2339
  }
2136
2340
  static createPk() {
2137
2341
  return new ObjectId();
2138
2342
  }
2343
+ serializeInto(uint8array, index) {
2344
+ uint8array[index] = this.buffer[0];
2345
+ uint8array[index + 1] = this.buffer[1];
2346
+ uint8array[index + 2] = this.buffer[2];
2347
+ uint8array[index + 3] = this.buffer[3];
2348
+ uint8array[index + 4] = this.buffer[4];
2349
+ uint8array[index + 5] = this.buffer[5];
2350
+ uint8array[index + 6] = this.buffer[6];
2351
+ uint8array[index + 7] = this.buffer[7];
2352
+ uint8array[index + 8] = this.buffer[8];
2353
+ uint8array[index + 9] = this.buffer[9];
2354
+ uint8array[index + 10] = this.buffer[10];
2355
+ uint8array[index + 11] = this.buffer[11];
2356
+ return 12;
2357
+ }
2139
2358
  static createFromTime(time) {
2140
- const buffer = ByteUtils.fromNumberArray([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
2141
- BSONDataView.fromUint8Array(buffer).setUint32(0, time, false);
2359
+ const buffer = ByteUtils.allocate(12);
2360
+ for (let i = 11; i >= 4; i--)
2361
+ buffer[i] = 0;
2362
+ NumberUtils.setInt32BE(buffer, 0, time);
2142
2363
  return new ObjectId(buffer);
2143
2364
  }
2144
2365
  static createFromHexString(hexString) {
@@ -2505,52 +2726,12 @@ class Timestamp extends LongWithoutOverridesClass {
2505
2726
  }
2506
2727
  Timestamp.MAX_VALUE = Long.MAX_UNSIGNED_VALUE;
2507
2728
 
2508
- const FIRST_BIT = 0x80;
2509
- const FIRST_TWO_BITS = 0xc0;
2510
- const FIRST_THREE_BITS = 0xe0;
2511
- const FIRST_FOUR_BITS = 0xf0;
2512
- const FIRST_FIVE_BITS = 0xf8;
2513
- const TWO_BIT_CHAR = 0xc0;
2514
- const THREE_BIT_CHAR = 0xe0;
2515
- const FOUR_BIT_CHAR = 0xf0;
2516
- const CONTINUING_CHAR = 0x80;
2517
- function validateUtf8(bytes, start, end) {
2518
- let continuation = 0;
2519
- for (let i = start; i < end; i += 1) {
2520
- const byte = bytes[i];
2521
- if (continuation) {
2522
- if ((byte & FIRST_TWO_BITS) !== CONTINUING_CHAR) {
2523
- return false;
2524
- }
2525
- continuation -= 1;
2526
- }
2527
- else if (byte & FIRST_BIT) {
2528
- if ((byte & FIRST_THREE_BITS) === TWO_BIT_CHAR) {
2529
- continuation = 1;
2530
- }
2531
- else if ((byte & FIRST_FOUR_BITS) === THREE_BIT_CHAR) {
2532
- continuation = 2;
2533
- }
2534
- else if ((byte & FIRST_FIVE_BITS) === FOUR_BIT_CHAR) {
2535
- continuation = 3;
2536
- }
2537
- else {
2538
- return false;
2539
- }
2540
- }
2541
- }
2542
- return !continuation;
2543
- }
2544
-
2545
2729
  const JS_INT_MAX_LONG = Long.fromNumber(JS_INT_MAX);
2546
2730
  const JS_INT_MIN_LONG = Long.fromNumber(JS_INT_MIN);
2547
2731
  function internalDeserialize(buffer, options, isArray) {
2548
2732
  options = options == null ? {} : options;
2549
2733
  const index = options && options.index ? options.index : 0;
2550
- const size = buffer[index] |
2551
- (buffer[index + 1] << 8) |
2552
- (buffer[index + 2] << 16) |
2553
- (buffer[index + 3] << 24);
2734
+ const size = NumberUtils.getInt32LE(buffer, index);
2554
2735
  if (size < 5) {
2555
2736
  throw new BSONError(`bson size must be >= 5, is ${size}`);
2556
2737
  }
@@ -2586,7 +2767,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2586
2767
  const validation = options.validation == null ? { utf8: true } : options.validation;
2587
2768
  let globalUTFValidation = true;
2588
2769
  let validationSetting;
2589
- const utf8KeysSet = new Set();
2770
+ let utf8KeysSet;
2590
2771
  const utf8ValidatedKeys = validation.utf8;
2591
2772
  if (typeof utf8ValidatedKeys === 'boolean') {
2592
2773
  validationSetting = utf8ValidatedKeys;
@@ -2608,6 +2789,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2608
2789
  }
2609
2790
  }
2610
2791
  if (!globalUTFValidation) {
2792
+ utf8KeysSet = new Set();
2611
2793
  for (const key of Object.keys(utf8ValidatedKeys)) {
2612
2794
  utf8KeysSet.add(key);
2613
2795
  }
@@ -2615,14 +2797,14 @@ function deserializeObject(buffer, index, options, isArray = false) {
2615
2797
  const startIndex = index;
2616
2798
  if (buffer.length < 5)
2617
2799
  throw new BSONError('corrupt bson message < 5 bytes long');
2618
- const size = buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24);
2800
+ const size = NumberUtils.getInt32LE(buffer, index);
2801
+ index += 4;
2619
2802
  if (size < 5 || size > buffer.length)
2620
2803
  throw new BSONError('corrupt bson message');
2621
2804
  const object = isArray ? [] : {};
2622
2805
  let arrayIndex = 0;
2623
2806
  const done = false;
2624
2807
  let isPossibleDBRef = isArray ? false : null;
2625
- const dataview = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
2626
2808
  while (!done) {
2627
2809
  const elementType = buffer[index++];
2628
2810
  if (elementType === 0)
@@ -2633,9 +2815,9 @@ function deserializeObject(buffer, index, options, isArray = false) {
2633
2815
  }
2634
2816
  if (i >= buffer.byteLength)
2635
2817
  throw new BSONError('Bad BSON Document: illegal CString');
2636
- const name = isArray ? arrayIndex++ : ByteUtils.toUTF8(buffer, index, i);
2818
+ const name = isArray ? arrayIndex++ : ByteUtils.toUTF8(buffer, index, i, false);
2637
2819
  let shouldValidateKey = true;
2638
- if (globalUTFValidation || utf8KeysSet.has(name)) {
2820
+ if (globalUTFValidation || utf8KeysSet?.has(name)) {
2639
2821
  shouldValidateKey = validationSetting;
2640
2822
  }
2641
2823
  else {
@@ -2647,51 +2829,41 @@ function deserializeObject(buffer, index, options, isArray = false) {
2647
2829
  let value;
2648
2830
  index = i + 1;
2649
2831
  if (elementType === BSON_DATA_STRING) {
2650
- const stringSize = buffer[index++] |
2651
- (buffer[index++] << 8) |
2652
- (buffer[index++] << 16) |
2653
- (buffer[index++] << 24);
2832
+ const stringSize = NumberUtils.getInt32LE(buffer, index);
2833
+ index += 4;
2654
2834
  if (stringSize <= 0 ||
2655
2835
  stringSize > buffer.length - index ||
2656
2836
  buffer[index + stringSize - 1] !== 0) {
2657
2837
  throw new BSONError('bad string length in bson');
2658
2838
  }
2659
- value = getValidatedString(buffer, index, index + stringSize - 1, shouldValidateKey);
2839
+ value = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
2660
2840
  index = index + stringSize;
2661
2841
  }
2662
2842
  else if (elementType === BSON_DATA_OID) {
2663
- const oid = ByteUtils.allocate(12);
2664
- oid.set(buffer.subarray(index, index + 12));
2843
+ const oid = ByteUtils.allocateUnsafe(12);
2844
+ for (let i = 0; i < 12; i++)
2845
+ oid[i] = buffer[index + i];
2665
2846
  value = new ObjectId(oid);
2666
2847
  index = index + 12;
2667
2848
  }
2668
2849
  else if (elementType === BSON_DATA_INT && promoteValues === false) {
2669
- value = new Int32(buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24));
2850
+ value = new Int32(NumberUtils.getInt32LE(buffer, index));
2851
+ index += 4;
2670
2852
  }
2671
2853
  else if (elementType === BSON_DATA_INT) {
2672
- value =
2673
- buffer[index++] |
2674
- (buffer[index++] << 8) |
2675
- (buffer[index++] << 16) |
2676
- (buffer[index++] << 24);
2677
- }
2678
- else if (elementType === BSON_DATA_NUMBER && promoteValues === false) {
2679
- value = new Double(dataview.getFloat64(index, true));
2680
- index = index + 8;
2854
+ value = NumberUtils.getInt32LE(buffer, index);
2855
+ index += 4;
2681
2856
  }
2682
2857
  else if (elementType === BSON_DATA_NUMBER) {
2683
- value = dataview.getFloat64(index, true);
2684
- index = index + 8;
2858
+ value = NumberUtils.getFloat64LE(buffer, index);
2859
+ index += 8;
2860
+ if (promoteValues === false)
2861
+ value = new Double(value);
2685
2862
  }
2686
2863
  else if (elementType === BSON_DATA_DATE) {
2687
- const lowBits = buffer[index++] |
2688
- (buffer[index++] << 8) |
2689
- (buffer[index++] << 16) |
2690
- (buffer[index++] << 24);
2691
- const highBits = buffer[index++] |
2692
- (buffer[index++] << 8) |
2693
- (buffer[index++] << 16) |
2694
- (buffer[index++] << 24);
2864
+ const lowBits = NumberUtils.getInt32LE(buffer, index);
2865
+ const highBits = NumberUtils.getInt32LE(buffer, index + 4);
2866
+ index += 8;
2695
2867
  value = new Date(new Long(lowBits, highBits).toNumber());
2696
2868
  }
2697
2869
  else if (elementType === BSON_DATA_BOOLEAN) {
@@ -2701,10 +2873,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2701
2873
  }
2702
2874
  else if (elementType === BSON_DATA_OBJECT) {
2703
2875
  const _index = index;
2704
- const objectSize = buffer[index] |
2705
- (buffer[index + 1] << 8) |
2706
- (buffer[index + 2] << 16) |
2707
- (buffer[index + 3] << 24);
2876
+ const objectSize = NumberUtils.getInt32LE(buffer, index);
2708
2877
  if (objectSize <= 0 || objectSize > buffer.length - index)
2709
2878
  throw new BSONError('bad embedded document length in bson');
2710
2879
  if (raw) {
@@ -2721,10 +2890,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2721
2890
  }
2722
2891
  else if (elementType === BSON_DATA_ARRAY) {
2723
2892
  const _index = index;
2724
- const objectSize = buffer[index] |
2725
- (buffer[index + 1] << 8) |
2726
- (buffer[index + 2] << 16) |
2727
- (buffer[index + 3] << 24);
2893
+ const objectSize = NumberUtils.getInt32LE(buffer, index);
2728
2894
  let arrayOptions = options;
2729
2895
  const stopIndex = index + objectSize;
2730
2896
  if (fieldsAsRaw && fieldsAsRaw[name]) {
@@ -2747,40 +2913,36 @@ function deserializeObject(buffer, index, options, isArray = false) {
2747
2913
  value = null;
2748
2914
  }
2749
2915
  else if (elementType === BSON_DATA_LONG) {
2750
- const dataview = BSONDataView.fromUint8Array(buffer.subarray(index, index + 8));
2751
- const lowBits = buffer[index++] |
2752
- (buffer[index++] << 8) |
2753
- (buffer[index++] << 16) |
2754
- (buffer[index++] << 24);
2755
- const highBits = buffer[index++] |
2756
- (buffer[index++] << 8) |
2757
- (buffer[index++] << 16) |
2758
- (buffer[index++] << 24);
2759
- const long = new Long(lowBits, highBits);
2760
2916
  if (useBigInt64) {
2761
- value = dataview.getBigInt64(0, true);
2762
- }
2763
- else if (promoteLongs && promoteValues === true) {
2764
- value =
2765
- long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG)
2766
- ? long.toNumber()
2767
- : long;
2917
+ value = NumberUtils.getBigInt64LE(buffer, index);
2918
+ index += 8;
2768
2919
  }
2769
2920
  else {
2770
- value = long;
2921
+ const lowBits = NumberUtils.getInt32LE(buffer, index);
2922
+ const highBits = NumberUtils.getInt32LE(buffer, index + 4);
2923
+ index += 8;
2924
+ const long = new Long(lowBits, highBits);
2925
+ if (promoteLongs && promoteValues === true) {
2926
+ value =
2927
+ long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG)
2928
+ ? long.toNumber()
2929
+ : long;
2930
+ }
2931
+ else {
2932
+ value = long;
2933
+ }
2771
2934
  }
2772
2935
  }
2773
2936
  else if (elementType === BSON_DATA_DECIMAL128) {
2774
- const bytes = ByteUtils.allocate(16);
2775
- bytes.set(buffer.subarray(index, index + 16), 0);
2937
+ const bytes = ByteUtils.allocateUnsafe(16);
2938
+ for (let i = 0; i < 16; i++)
2939
+ bytes[i] = buffer[index + i];
2776
2940
  index = index + 16;
2777
2941
  value = new Decimal128(bytes);
2778
2942
  }
2779
2943
  else if (elementType === BSON_DATA_BINARY) {
2780
- let binarySize = buffer[index++] |
2781
- (buffer[index++] << 8) |
2782
- (buffer[index++] << 16) |
2783
- (buffer[index++] << 24);
2944
+ let binarySize = NumberUtils.getInt32LE(buffer, index);
2945
+ index += 4;
2784
2946
  const totalBinarySize = binarySize;
2785
2947
  const subType = buffer[index++];
2786
2948
  if (binarySize < 0)
@@ -2789,11 +2951,8 @@ function deserializeObject(buffer, index, options, isArray = false) {
2789
2951
  throw new BSONError('Binary type size larger than document size');
2790
2952
  if (buffer['slice'] != null) {
2791
2953
  if (subType === Binary.SUBTYPE_BYTE_ARRAY) {
2792
- binarySize =
2793
- buffer[index++] |
2794
- (buffer[index++] << 8) |
2795
- (buffer[index++] << 16) |
2796
- (buffer[index++] << 24);
2954
+ binarySize = NumberUtils.getInt32LE(buffer, index);
2955
+ index += 4;
2797
2956
  if (binarySize < 0)
2798
2957
  throw new BSONError('Negative binary type element size found for subtype 0x02');
2799
2958
  if (binarySize > totalBinarySize - 4)
@@ -2812,13 +2971,9 @@ function deserializeObject(buffer, index, options, isArray = false) {
2812
2971
  }
2813
2972
  }
2814
2973
  else {
2815
- const _buffer = ByteUtils.allocate(binarySize);
2816
2974
  if (subType === Binary.SUBTYPE_BYTE_ARRAY) {
2817
- binarySize =
2818
- buffer[index++] |
2819
- (buffer[index++] << 8) |
2820
- (buffer[index++] << 16) |
2821
- (buffer[index++] << 24);
2975
+ binarySize = NumberUtils.getInt32LE(buffer, index);
2976
+ index += 4;
2822
2977
  if (binarySize < 0)
2823
2978
  throw new BSONError('Negative binary type element size found for subtype 0x02');
2824
2979
  if (binarySize > totalBinarySize - 4)
@@ -2826,11 +2981,11 @@ function deserializeObject(buffer, index, options, isArray = false) {
2826
2981
  if (binarySize < totalBinarySize - 4)
2827
2982
  throw new BSONError('Binary type with subtype 0x02 contains too short binary size');
2828
2983
  }
2829
- for (i = 0; i < binarySize; i++) {
2830
- _buffer[i] = buffer[index + i];
2831
- }
2832
2984
  if (promoteBuffers && promoteValues) {
2833
- value = _buffer;
2985
+ value = ByteUtils.allocateUnsafe(binarySize);
2986
+ for (i = 0; i < binarySize; i++) {
2987
+ value[i] = buffer[index + i];
2988
+ }
2834
2989
  }
2835
2990
  else {
2836
2991
  value = new Binary(buffer.slice(index, index + binarySize), subType);
@@ -2848,7 +3003,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2848
3003
  }
2849
3004
  if (i >= buffer.length)
2850
3005
  throw new BSONError('Bad BSON Document: illegal CString');
2851
- const source = ByteUtils.toUTF8(buffer, index, i);
3006
+ const source = ByteUtils.toUTF8(buffer, index, i, false);
2852
3007
  index = i + 1;
2853
3008
  i = index;
2854
3009
  while (buffer[i] !== 0x00 && i < buffer.length) {
@@ -2856,7 +3011,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2856
3011
  }
2857
3012
  if (i >= buffer.length)
2858
3013
  throw new BSONError('Bad BSON Document: illegal CString');
2859
- const regExpOptions = ByteUtils.toUTF8(buffer, index, i);
3014
+ const regExpOptions = ByteUtils.toUTF8(buffer, index, i, false);
2860
3015
  index = i + 1;
2861
3016
  const optionsArray = new Array(regExpOptions.length);
2862
3017
  for (i = 0; i < regExpOptions.length; i++) {
@@ -2881,7 +3036,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2881
3036
  }
2882
3037
  if (i >= buffer.length)
2883
3038
  throw new BSONError('Bad BSON Document: illegal CString');
2884
- const source = ByteUtils.toUTF8(buffer, index, i);
3039
+ const source = ByteUtils.toUTF8(buffer, index, i, false);
2885
3040
  index = i + 1;
2886
3041
  i = index;
2887
3042
  while (buffer[i] !== 0x00 && i < buffer.length) {
@@ -2889,34 +3044,28 @@ function deserializeObject(buffer, index, options, isArray = false) {
2889
3044
  }
2890
3045
  if (i >= buffer.length)
2891
3046
  throw new BSONError('Bad BSON Document: illegal CString');
2892
- const regExpOptions = ByteUtils.toUTF8(buffer, index, i);
3047
+ const regExpOptions = ByteUtils.toUTF8(buffer, index, i, false);
2893
3048
  index = i + 1;
2894
3049
  value = new BSONRegExp(source, regExpOptions);
2895
3050
  }
2896
3051
  else if (elementType === BSON_DATA_SYMBOL) {
2897
- const stringSize = buffer[index++] |
2898
- (buffer[index++] << 8) |
2899
- (buffer[index++] << 16) |
2900
- (buffer[index++] << 24);
3052
+ const stringSize = NumberUtils.getInt32LE(buffer, index);
3053
+ index += 4;
2901
3054
  if (stringSize <= 0 ||
2902
3055
  stringSize > buffer.length - index ||
2903
3056
  buffer[index + stringSize - 1] !== 0) {
2904
3057
  throw new BSONError('bad string length in bson');
2905
3058
  }
2906
- const symbol = getValidatedString(buffer, index, index + stringSize - 1, shouldValidateKey);
3059
+ const symbol = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
2907
3060
  value = promoteValues ? symbol : new BSONSymbol(symbol);
2908
3061
  index = index + stringSize;
2909
3062
  }
2910
3063
  else if (elementType === BSON_DATA_TIMESTAMP) {
2911
- const i = buffer[index++] +
2912
- buffer[index++] * (1 << 8) +
2913
- buffer[index++] * (1 << 16) +
2914
- buffer[index++] * (1 << 24);
2915
- const t = buffer[index++] +
2916
- buffer[index++] * (1 << 8) +
2917
- buffer[index++] * (1 << 16) +
2918
- buffer[index++] * (1 << 24);
2919
- value = new Timestamp({ i, t });
3064
+ value = new Timestamp({
3065
+ i: NumberUtils.getUint32LE(buffer, index),
3066
+ t: NumberUtils.getUint32LE(buffer, index + 4)
3067
+ });
3068
+ index += 8;
2920
3069
  }
2921
3070
  else if (elementType === BSON_DATA_MIN_KEY) {
2922
3071
  value = new MinKey();
@@ -2925,43 +3074,34 @@ function deserializeObject(buffer, index, options, isArray = false) {
2925
3074
  value = new MaxKey();
2926
3075
  }
2927
3076
  else if (elementType === BSON_DATA_CODE) {
2928
- const stringSize = buffer[index++] |
2929
- (buffer[index++] << 8) |
2930
- (buffer[index++] << 16) |
2931
- (buffer[index++] << 24);
3077
+ const stringSize = NumberUtils.getInt32LE(buffer, index);
3078
+ index += 4;
2932
3079
  if (stringSize <= 0 ||
2933
3080
  stringSize > buffer.length - index ||
2934
3081
  buffer[index + stringSize - 1] !== 0) {
2935
3082
  throw new BSONError('bad string length in bson');
2936
3083
  }
2937
- const functionString = getValidatedString(buffer, index, index + stringSize - 1, shouldValidateKey);
3084
+ const functionString = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
2938
3085
  value = new Code(functionString);
2939
3086
  index = index + stringSize;
2940
3087
  }
2941
3088
  else if (elementType === BSON_DATA_CODE_W_SCOPE) {
2942
- const totalSize = buffer[index++] |
2943
- (buffer[index++] << 8) |
2944
- (buffer[index++] << 16) |
2945
- (buffer[index++] << 24);
3089
+ const totalSize = NumberUtils.getInt32LE(buffer, index);
3090
+ index += 4;
2946
3091
  if (totalSize < 4 + 4 + 4 + 1) {
2947
3092
  throw new BSONError('code_w_scope total size shorter minimum expected length');
2948
3093
  }
2949
- const stringSize = buffer[index++] |
2950
- (buffer[index++] << 8) |
2951
- (buffer[index++] << 16) |
2952
- (buffer[index++] << 24);
3094
+ const stringSize = NumberUtils.getInt32LE(buffer, index);
3095
+ index += 4;
2953
3096
  if (stringSize <= 0 ||
2954
3097
  stringSize > buffer.length - index ||
2955
3098
  buffer[index + stringSize - 1] !== 0) {
2956
3099
  throw new BSONError('bad string length in bson');
2957
3100
  }
2958
- const functionString = getValidatedString(buffer, index, index + stringSize - 1, shouldValidateKey);
3101
+ const functionString = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
2959
3102
  index = index + stringSize;
2960
3103
  const _index = index;
2961
- const objectSize = buffer[index] |
2962
- (buffer[index + 1] << 8) |
2963
- (buffer[index + 2] << 16) |
2964
- (buffer[index + 3] << 24);
3104
+ const objectSize = NumberUtils.getInt32LE(buffer, index);
2965
3105
  const scopeObject = deserializeObject(buffer, _index, options, false);
2966
3106
  index = index + objectSize;
2967
3107
  if (totalSize < 4 + 4 + objectSize + stringSize) {
@@ -2973,10 +3113,8 @@ function deserializeObject(buffer, index, options, isArray = false) {
2973
3113
  value = new Code(functionString, scopeObject);
2974
3114
  }
2975
3115
  else if (elementType === BSON_DATA_DBPOINTER) {
2976
- const stringSize = buffer[index++] |
2977
- (buffer[index++] << 8) |
2978
- (buffer[index++] << 16) |
2979
- (buffer[index++] << 24);
3116
+ const stringSize = NumberUtils.getInt32LE(buffer, index);
3117
+ index += 4;
2980
3118
  if (stringSize <= 0 ||
2981
3119
  stringSize > buffer.length - index ||
2982
3120
  buffer[index + stringSize - 1] !== 0)
@@ -2986,10 +3124,11 @@ function deserializeObject(buffer, index, options, isArray = false) {
2986
3124
  throw new BSONError('Invalid UTF-8 string in BSON document');
2987
3125
  }
2988
3126
  }
2989
- const namespace = ByteUtils.toUTF8(buffer, index, index + stringSize - 1);
3127
+ const namespace = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, false);
2990
3128
  index = index + stringSize;
2991
- const oidBuffer = ByteUtils.allocate(12);
2992
- oidBuffer.set(buffer.subarray(index, index + 12), 0);
3129
+ const oidBuffer = ByteUtils.allocateUnsafe(12);
3130
+ for (let i = 0; i < 12; i++)
3131
+ oidBuffer[i] = buffer[index + i];
2993
3132
  const oid = new ObjectId(oidBuffer);
2994
3133
  index = index + 12;
2995
3134
  value = new DBRef(namespace, oid);
@@ -3025,20 +3164,6 @@ function deserializeObject(buffer, index, options, isArray = false) {
3025
3164
  }
3026
3165
  return object;
3027
3166
  }
3028
- function getValidatedString(buffer, start, end, shouldValidateUtf8) {
3029
- const value = ByteUtils.toUTF8(buffer, start, end);
3030
- if (shouldValidateUtf8) {
3031
- for (let i = 0; i < value.length; i++) {
3032
- if (value.charCodeAt(i) === 0xfffd) {
3033
- if (!validateUtf8(buffer, start, end)) {
3034
- throw new BSONError('Invalid UTF-8 string in BSON document');
3035
- }
3036
- break;
3037
- }
3038
- }
3039
- }
3040
- return value;
3041
- }
3042
3167
 
3043
3168
  const regexp = /\x00/;
3044
3169
  const ignoreKeys = new Set(['$db', '$ref', '$id', '$clusterTime']);
@@ -3048,17 +3173,11 @@ function serializeString(buffer, key, value, index) {
3048
3173
  index = index + numberOfWrittenBytes + 1;
3049
3174
  buffer[index - 1] = 0;
3050
3175
  const size = ByteUtils.encodeUTF8Into(buffer, value, index + 4);
3051
- buffer[index + 3] = ((size + 1) >> 24) & 0xff;
3052
- buffer[index + 2] = ((size + 1) >> 16) & 0xff;
3053
- buffer[index + 1] = ((size + 1) >> 8) & 0xff;
3054
- buffer[index] = (size + 1) & 0xff;
3176
+ NumberUtils.setInt32LE(buffer, index, size + 1);
3055
3177
  index = index + 4 + size;
3056
3178
  buffer[index++] = 0;
3057
3179
  return index;
3058
3180
  }
3059
- const NUMBER_SPACE = new DataView(new ArrayBuffer(8), 0, 8);
3060
- const FOUR_BYTE_VIEW_ON_NUMBER = new Uint8Array(NUMBER_SPACE.buffer, 0, 4);
3061
- const EIGHT_BYTE_VIEW_ON_NUMBER = new Uint8Array(NUMBER_SPACE.buffer, 0, 8);
3062
3181
  function serializeNumber(buffer, key, value, index) {
3063
3182
  const isNegativeZero = Object.is(value, -0);
3064
3183
  const type = !isNegativeZero &&
@@ -3067,19 +3186,16 @@ function serializeNumber(buffer, key, value, index) {
3067
3186
  value >= BSON_INT32_MIN
3068
3187
  ? BSON_DATA_INT
3069
3188
  : BSON_DATA_NUMBER;
3070
- if (type === BSON_DATA_INT) {
3071
- NUMBER_SPACE.setInt32(0, value, true);
3072
- }
3073
- else {
3074
- NUMBER_SPACE.setFloat64(0, value, true);
3075
- }
3076
- const bytes = type === BSON_DATA_INT ? FOUR_BYTE_VIEW_ON_NUMBER : EIGHT_BYTE_VIEW_ON_NUMBER;
3077
3189
  buffer[index++] = type;
3078
3190
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3079
3191
  index = index + numberOfWrittenBytes;
3080
3192
  buffer[index++] = 0x00;
3081
- buffer.set(bytes, index);
3082
- index += bytes.byteLength;
3193
+ if (type === BSON_DATA_INT) {
3194
+ index += NumberUtils.setInt32LE(buffer, index, value);
3195
+ }
3196
+ else {
3197
+ index += NumberUtils.setFloat64LE(buffer, index, value);
3198
+ }
3083
3199
  return index;
3084
3200
  }
3085
3201
  function serializeBigInt(buffer, key, value, index) {
@@ -3087,9 +3203,7 @@ function serializeBigInt(buffer, key, value, index) {
3087
3203
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3088
3204
  index += numberOfWrittenBytes;
3089
3205
  buffer[index++] = 0;
3090
- NUMBER_SPACE.setBigInt64(0, value, true);
3091
- buffer.set(EIGHT_BYTE_VIEW_ON_NUMBER, index);
3092
- index += EIGHT_BYTE_VIEW_ON_NUMBER.byteLength;
3206
+ index += NumberUtils.setBigInt64LE(buffer, index, value);
3093
3207
  return index;
3094
3208
  }
3095
3209
  function serializeNull(buffer, key, _, index) {
@@ -3115,14 +3229,8 @@ function serializeDate(buffer, key, value, index) {
3115
3229
  const dateInMilis = Long.fromNumber(value.getTime());
3116
3230
  const lowBits = dateInMilis.getLowBits();
3117
3231
  const highBits = dateInMilis.getHighBits();
3118
- buffer[index++] = lowBits & 0xff;
3119
- buffer[index++] = (lowBits >> 8) & 0xff;
3120
- buffer[index++] = (lowBits >> 16) & 0xff;
3121
- buffer[index++] = (lowBits >> 24) & 0xff;
3122
- buffer[index++] = highBits & 0xff;
3123
- buffer[index++] = (highBits >> 8) & 0xff;
3124
- buffer[index++] = (highBits >> 16) & 0xff;
3125
- buffer[index++] = (highBits >> 24) & 0xff;
3232
+ index += NumberUtils.setInt32LE(buffer, index, lowBits);
3233
+ index += NumberUtils.setInt32LE(buffer, index, highBits);
3126
3234
  return index;
3127
3235
  }
3128
3236
  function serializeRegExp(buffer, key, value, index) {
@@ -3179,15 +3287,7 @@ function serializeObjectId(buffer, key, value, index) {
3179
3287
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3180
3288
  index = index + numberOfWrittenBytes;
3181
3289
  buffer[index++] = 0;
3182
- const idValue = value.id;
3183
- if (isUint8Array(idValue)) {
3184
- for (let i = 0; i < 12; i++) {
3185
- buffer[index++] = idValue[i];
3186
- }
3187
- }
3188
- else {
3189
- throw new BSONError('object [' + JSON.stringify(value) + '] is not a valid ObjectId');
3190
- }
3290
+ index += value.serializeInto(buffer, index);
3191
3291
  return index;
3192
3292
  }
3193
3293
  function serializeBuffer(buffer, key, value, index) {
@@ -3196,12 +3296,15 @@ function serializeBuffer(buffer, key, value, index) {
3196
3296
  index = index + numberOfWrittenBytes;
3197
3297
  buffer[index++] = 0;
3198
3298
  const size = value.length;
3199
- buffer[index++] = size & 0xff;
3200
- buffer[index++] = (size >> 8) & 0xff;
3201
- buffer[index++] = (size >> 16) & 0xff;
3202
- buffer[index++] = (size >> 24) & 0xff;
3299
+ index += NumberUtils.setInt32LE(buffer, index, size);
3203
3300
  buffer[index++] = BSON_BINARY_SUBTYPE_DEFAULT;
3204
- buffer.set(value, index);
3301
+ if (size <= 16) {
3302
+ for (let i = 0; i < size; i++)
3303
+ buffer[index + i] = value[i];
3304
+ }
3305
+ else {
3306
+ buffer.set(value, index);
3307
+ }
3205
3308
  index = index + size;
3206
3309
  return index;
3207
3310
  }
@@ -3223,7 +3326,8 @@ function serializeDecimal128(buffer, key, value, index) {
3223
3326
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3224
3327
  index = index + numberOfWrittenBytes;
3225
3328
  buffer[index++] = 0;
3226
- buffer.set(value.bytes.subarray(0, 16), index);
3329
+ for (let i = 0; i < 16; i++)
3330
+ buffer[index + i] = value.bytes[i];
3227
3331
  return index + 16;
3228
3332
  }
3229
3333
  function serializeLong(buffer, key, value, index) {
@@ -3234,14 +3338,8 @@ function serializeLong(buffer, key, value, index) {
3234
3338
  buffer[index++] = 0;
3235
3339
  const lowBits = value.getLowBits();
3236
3340
  const highBits = value.getHighBits();
3237
- buffer[index++] = lowBits & 0xff;
3238
- buffer[index++] = (lowBits >> 8) & 0xff;
3239
- buffer[index++] = (lowBits >> 16) & 0xff;
3240
- buffer[index++] = (lowBits >> 24) & 0xff;
3241
- buffer[index++] = highBits & 0xff;
3242
- buffer[index++] = (highBits >> 8) & 0xff;
3243
- buffer[index++] = (highBits >> 16) & 0xff;
3244
- buffer[index++] = (highBits >> 24) & 0xff;
3341
+ index += NumberUtils.setInt32LE(buffer, index, lowBits);
3342
+ index += NumberUtils.setInt32LE(buffer, index, highBits);
3245
3343
  return index;
3246
3344
  }
3247
3345
  function serializeInt32(buffer, key, value, index) {
@@ -3250,10 +3348,7 @@ function serializeInt32(buffer, key, value, index) {
3250
3348
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3251
3349
  index = index + numberOfWrittenBytes;
3252
3350
  buffer[index++] = 0;
3253
- buffer[index++] = value & 0xff;
3254
- buffer[index++] = (value >> 8) & 0xff;
3255
- buffer[index++] = (value >> 16) & 0xff;
3256
- buffer[index++] = (value >> 24) & 0xff;
3351
+ index += NumberUtils.setInt32LE(buffer, index, value);
3257
3352
  return index;
3258
3353
  }
3259
3354
  function serializeDouble(buffer, key, value, index) {
@@ -3261,9 +3356,7 @@ function serializeDouble(buffer, key, value, index) {
3261
3356
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3262
3357
  index = index + numberOfWrittenBytes;
3263
3358
  buffer[index++] = 0;
3264
- NUMBER_SPACE.setFloat64(0, value.value, true);
3265
- buffer.set(EIGHT_BYTE_VIEW_ON_NUMBER, index);
3266
- index = index + 8;
3359
+ index += NumberUtils.setFloat64LE(buffer, index, value.value);
3267
3360
  return index;
3268
3361
  }
3269
3362
  function serializeFunction(buffer, key, value, index) {
@@ -3273,10 +3366,7 @@ function serializeFunction(buffer, key, value, index) {
3273
3366
  buffer[index++] = 0;
3274
3367
  const functionString = value.toString();
3275
3368
  const size = ByteUtils.encodeUTF8Into(buffer, functionString, index + 4) + 1;
3276
- buffer[index] = size & 0xff;
3277
- buffer[index + 1] = (size >> 8) & 0xff;
3278
- buffer[index + 2] = (size >> 16) & 0xff;
3279
- buffer[index + 3] = (size >> 24) & 0xff;
3369
+ NumberUtils.setInt32LE(buffer, index, size);
3280
3370
  index = index + 4 + size - 1;
3281
3371
  buffer[index++] = 0;
3282
3372
  return index;
@@ -3291,19 +3381,13 @@ function serializeCode(buffer, key, value, index, checkKeys = false, depth = 0,
3291
3381
  const functionString = value.code;
3292
3382
  index = index + 4;
3293
3383
  const codeSize = ByteUtils.encodeUTF8Into(buffer, functionString, index + 4) + 1;
3294
- buffer[index] = codeSize & 0xff;
3295
- buffer[index + 1] = (codeSize >> 8) & 0xff;
3296
- buffer[index + 2] = (codeSize >> 16) & 0xff;
3297
- buffer[index + 3] = (codeSize >> 24) & 0xff;
3384
+ NumberUtils.setInt32LE(buffer, index, codeSize);
3298
3385
  buffer[index + 4 + codeSize - 1] = 0;
3299
3386
  index = index + codeSize + 4;
3300
3387
  const endIndex = serializeInto(buffer, value.scope, checkKeys, index, depth + 1, serializeFunctions, ignoreUndefined, path);
3301
3388
  index = endIndex - 1;
3302
3389
  const totalSize = endIndex - startIndex;
3303
- buffer[startIndex++] = totalSize & 0xff;
3304
- buffer[startIndex++] = (totalSize >> 8) & 0xff;
3305
- buffer[startIndex++] = (totalSize >> 16) & 0xff;
3306
- buffer[startIndex++] = (totalSize >> 24) & 0xff;
3390
+ startIndex += NumberUtils.setInt32LE(buffer, startIndex, totalSize);
3307
3391
  buffer[index++] = 0;
3308
3392
  }
3309
3393
  else {
@@ -3313,10 +3397,7 @@ function serializeCode(buffer, key, value, index, checkKeys = false, depth = 0,
3313
3397
  buffer[index++] = 0;
3314
3398
  const functionString = value.code.toString();
3315
3399
  const size = ByteUtils.encodeUTF8Into(buffer, functionString, index + 4) + 1;
3316
- buffer[index] = size & 0xff;
3317
- buffer[index + 1] = (size >> 8) & 0xff;
3318
- buffer[index + 2] = (size >> 16) & 0xff;
3319
- buffer[index + 3] = (size >> 24) & 0xff;
3400
+ NumberUtils.setInt32LE(buffer, index, size);
3320
3401
  index = index + 4 + size - 1;
3321
3402
  buffer[index++] = 0;
3322
3403
  }
@@ -3331,19 +3412,19 @@ function serializeBinary(buffer, key, value, index) {
3331
3412
  let size = value.position;
3332
3413
  if (value.sub_type === Binary.SUBTYPE_BYTE_ARRAY)
3333
3414
  size = size + 4;
3334
- buffer[index++] = size & 0xff;
3335
- buffer[index++] = (size >> 8) & 0xff;
3336
- buffer[index++] = (size >> 16) & 0xff;
3337
- buffer[index++] = (size >> 24) & 0xff;
3415
+ index += NumberUtils.setInt32LE(buffer, index, size);
3338
3416
  buffer[index++] = value.sub_type;
3339
3417
  if (value.sub_type === Binary.SUBTYPE_BYTE_ARRAY) {
3340
3418
  size = size - 4;
3341
- buffer[index++] = size & 0xff;
3342
- buffer[index++] = (size >> 8) & 0xff;
3343
- buffer[index++] = (size >> 16) & 0xff;
3344
- buffer[index++] = (size >> 24) & 0xff;
3419
+ index += NumberUtils.setInt32LE(buffer, index, size);
3420
+ }
3421
+ if (size <= 16) {
3422
+ for (let i = 0; i < size; i++)
3423
+ buffer[index + i] = data[i];
3424
+ }
3425
+ else {
3426
+ buffer.set(data, index);
3345
3427
  }
3346
- buffer.set(data, index);
3347
3428
  index = index + value.position;
3348
3429
  return index;
3349
3430
  }
@@ -3353,12 +3434,9 @@ function serializeSymbol(buffer, key, value, index) {
3353
3434
  index = index + numberOfWrittenBytes;
3354
3435
  buffer[index++] = 0;
3355
3436
  const size = ByteUtils.encodeUTF8Into(buffer, value.value, index + 4) + 1;
3356
- buffer[index] = size & 0xff;
3357
- buffer[index + 1] = (size >> 8) & 0xff;
3358
- buffer[index + 2] = (size >> 16) & 0xff;
3359
- buffer[index + 3] = (size >> 24) & 0xff;
3437
+ NumberUtils.setInt32LE(buffer, index, size);
3360
3438
  index = index + 4 + size - 1;
3361
- buffer[index++] = 0x00;
3439
+ buffer[index++] = 0;
3362
3440
  return index;
3363
3441
  }
3364
3442
  function serializeDBRef(buffer, key, value, index, depth, serializeFunctions, path) {
@@ -3377,10 +3455,7 @@ function serializeDBRef(buffer, key, value, index, depth, serializeFunctions, pa
3377
3455
  output = Object.assign(output, value.fields);
3378
3456
  const endIndex = serializeInto(buffer, output, false, index, depth + 1, serializeFunctions, true, path);
3379
3457
  const size = endIndex - startIndex;
3380
- buffer[startIndex++] = size & 0xff;
3381
- buffer[startIndex++] = (size >> 8) & 0xff;
3382
- buffer[startIndex++] = (size >> 16) & 0xff;
3383
- buffer[startIndex++] = (size >> 24) & 0xff;
3458
+ startIndex += NumberUtils.setInt32LE(buffer, index, size);
3384
3459
  return endIndex;
3385
3460
  }
3386
3461
  function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializeFunctions, ignoreUndefined, path) {
@@ -3516,7 +3591,7 @@ function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializ
3516
3591
  if ('$' === key[0]) {
3517
3592
  throw new BSONError('key ' + key + " must not start with '$'");
3518
3593
  }
3519
- else if (~key.indexOf('.')) {
3594
+ else if (key.includes('.')) {
3520
3595
  throw new BSONError('key ' + key + " must not contain '.'");
3521
3596
  }
3522
3597
  }
@@ -3614,7 +3689,7 @@ function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializ
3614
3689
  if ('$' === key[0]) {
3615
3690
  throw new BSONError('key ' + key + " must not start with '$'");
3616
3691
  }
3617
- else if (~key.indexOf('.')) {
3692
+ else if (key.includes('.')) {
3618
3693
  throw new BSONError('key ' + key + " must not contain '.'");
3619
3694
  }
3620
3695
  }
@@ -3698,10 +3773,7 @@ function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializ
3698
3773
  path.delete(object);
3699
3774
  buffer[index++] = 0x00;
3700
3775
  const size = index - startingIndex;
3701
- buffer[startingIndex++] = size & 0xff;
3702
- buffer[startingIndex++] = (size >> 8) & 0xff;
3703
- buffer[startingIndex++] = (size >> 16) & 0xff;
3704
- buffer[startingIndex++] = (size >> 24) & 0xff;
3776
+ startingIndex += NumberUtils.setInt32LE(buffer, startingIndex, size);
3705
3777
  return index;
3706
3778
  }
3707
3779
 
@@ -4031,7 +4103,7 @@ function serialize(object, options = {}) {
4031
4103
  buffer = ByteUtils.allocate(minInternalBufferSize);
4032
4104
  }
4033
4105
  const serializationIndex = serializeInto(buffer, object, checkKeys, 0, 0, serializeFunctions, ignoreUndefined, null);
4034
- const finishedBuffer = ByteUtils.allocate(serializationIndex);
4106
+ const finishedBuffer = ByteUtils.allocateUnsafe(serializationIndex);
4035
4107
  finishedBuffer.set(buffer.subarray(0, serializationIndex), 0);
4036
4108
  return finishedBuffer;
4037
4109
  }
@@ -4058,10 +4130,7 @@ function deserializeStream(data, startIndex, numberOfDocuments, documents, docSt
4058
4130
  const bufferData = ByteUtils.toLocalBufferType(data);
4059
4131
  let index = startIndex;
4060
4132
  for (let i = 0; i < numberOfDocuments; i++) {
4061
- const size = bufferData[index] |
4062
- (bufferData[index + 1] << 8) |
4063
- (bufferData[index + 2] << 16) |
4064
- (bufferData[index + 3] << 24);
4133
+ const size = NumberUtils.getInt32LE(bufferData, index);
4065
4134
  internalOptions.index = index;
4066
4135
  documents[docStartIndex + i] = internalDeserialize(bufferData, internalOptions);
4067
4136
  index = index + size;