All files / json-pack/src/cbor CborEncoderStable.ts

97.95% Statements 48/49
100% Branches 12/12
75% Functions 3/4
97.77% Lines 44/45

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 695x 5x 5x     5x 42748x 1390x 58x 22x     5x   4166x 4166x 4166x 4166x 4166x 15091x 15091x 15091x           21374x 21374x 21374x 21374x 21374x 21374x 21374x 21374x 21374x 21374x 21374x 21374x 2x 2x   21374x   20678x 20678x   667x 667x 667x   18x 18x 18x     11x 11x 11x     21374x              
import {sort} from '@jsonjoy.com/util/lib/sort/insertion2';
import {objKeyCmp} from '@jsonjoy.com/util/lib/objKeyCmp';
import {CborEncoder} from './CborEncoder';
import {MAJOR_OVERLAY} from './constants';
 
const strHeaderLength = (strSize: number): 1 | 2 | 3 | 5 => {
  if (strSize <= 23) return 1;
  else if (strSize <= 0xff) return 2;
  else if (strSize <= 0xffff) return 3;
  else return 5;
};
 
export class CborEncoderStable extends CborEncoder {
  public writeObj(obj: Record<string, unknown>): void {
    const keys = Object.keys(obj);
    sort(keys, objKeyCmp);
    const length = keys.length;
    this.writeObjHdr(length);
    for (let i = 0; i < length; i++) {
      const key = keys[i];
      this.writeStr(key);
      this.writeAny(obj[key]);
    }
  }
 
  /** @todo This implementation might be even faster than the default one, verify that. */
  public writeStr(str: string): void {
    const writer = this.writer;
    const length = str.length;
    const maxSize = length * 4;
    writer.ensureCapacity(5 + maxSize);
    const headerLengthGuess = strHeaderLength(length);
    const x0 = writer.x;
    const x1 = x0 + headerLengthGuess;
    writer.x = x1;
    const bytesWritten = writer.utf8(str);
    const uint8 = writer.uint8;
    const headerLength = strHeaderLength(bytesWritten);
    if (headerLength !== headerLengthGuess) {
      const shift = headerLength - headerLengthGuess;
      uint8.copyWithin(x1 + shift, x1, x1 + bytesWritten);
    }
    switch (headerLength) {
      case 1:
        uint8[x0] = MAJOR_OVERLAY.STR + bytesWritten;
        break;
      case 2:
        uint8[x0] = 0x78;
        uint8[x0 + 1] = bytesWritten;
        break;
      case 3: {
        uint8[x0] = 0x79;
        writer.view.setUint16(x0 + 1, bytesWritten);
        break;
      }
      case 5: {
        uint8[x0] = 0x7a;
        writer.view.setUint32(x0 + 1, bytesWritten);
        break;
      }
    }
    writer.x = x0 + headerLength + bytesWritten;
  }
 
  public writeUndef(): void {
    this.writeNull();
  }
}