All files / buffers/src Reader.ts

100% Statements 67/67
100% Branches 12/12
100% Functions 22/22
100% Lines 65/65

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 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 1634x     4x   1211x 1211x 1211x 1211x       7x 7x 7x       42x             25x             6x       42x       15x 15x 15x 15x 15x       6x 6x 6x 6x                             1059x 1059x 1059x 1059x                       27x 27x 27x       1000083x         4x             2010x 2010x 2010x 2010x       3x 3x 3x       1007x 1007x 1007x       3x 3x 3x       4x 4x 4x       3x 3x 3x       4x 4x 4x       4x 4x 4x       20x 20x 20x       10x 10x 10x 100124x 10x 10x      
import {decodeUtf8} from './utf8/decodeUtf8';
import type {IReader, IReaderResettable} from './types';
 
export class Reader implements IReader, IReaderResettable {
  constructor(
    public uint8: Uint8Array = new Uint8Array([]),
    public view: DataView = new DataView(uint8.buffer as ArrayBuffer, uint8.byteOffset, uint8.length),
    public x: number = 0,
    public end: number = uint8.length,
  ) {}
 
  public reset(uint8: Uint8Array): void {
    this.x = 0;
    this.uint8 = uint8;
    this.view = new DataView(uint8.buffer as ArrayBuffer, uint8.byteOffset, uint8.length);
  }
 
  public size(): number {
    return this.end - this.x;
  }
 
  /**
   * Get current byte value without advancing the cursor.
   */
  public peek(): number {
    return this.view.getUint8(this.x);
  }
 
  /**
   * @deprecated Use peek() instead.
   */
  public peak(): number {
    return this.peek();
  }
 
  public skip(length: number): void {
    this.x += length;
  }
 
  public buf(size: number = this.size()): Uint8Array {
    const x = this.x;
    const end = x + size;
    const bin = this.uint8.subarray(x, end);
    this.x = end;
    return bin;
  }
 
  public subarray(start: number = 0, end?: number): Uint8Array {
    const x = this.x;
    const actualStart = x + start;
    const actualEnd = typeof end === 'number' ? x + end : this.end;
    return this.uint8.subarray(actualStart, actualEnd);
  }
 
  /**
   * Creates a new {@link Reader} that references the same underlying memory
   * buffer. But with independent cursor and end.
   *
   * Preferred over {@link buf} since it also provides a DataView and is much
   * faster to allocate a new {@link Slice} than a new {@link Uint8Array}.
   *
   * @param start Start offset relative to the current cursor position.
   * @param end End offset relative to the current cursor position.
   * @returns A new {@link Reader} instance.
   */
  public slice(start: number = 0, end?: number): Reader {
    const x = this.x;
    const actualStart = x + start;
    const actualEnd = typeof end === 'number' ? x + end : this.end;
    return new Reader(this.uint8, this.view, actualStart, actualEnd);
  }
 
  /**
   * Similar to {@link slice} but also advances the cursor. Returns a new
   * {@link Reader} that references the same underlying memory buffer, starting
   * from the current cursor position.
   *
   * @param size Number of bytes to cut from the current position.
   * @returns A new {@link Reader} instance.
   */
  public cut(size: number = this.size()): Reader {
    const slice = this.slice(0, size);
    this.skip(size);
    return slice;
  }
 
  public u8(): number {
    return this.uint8[this.x++];
    // return this.view.getUint8(this.x++);
  }
 
  public i8(): number {
    return this.view.getInt8(this.x++);
  }
 
  public u16(): number {
    // const num = this.view.getUint16(this.x);
    // this.x += 2;
    // return num;
    let x = this.x;
    const num = (this.uint8[x++] << 8) + this.uint8[x++];
    this.x = x;
    return num;
  }
 
  public i16(): number {
    const num = this.view.getInt16(this.x);
    this.x += 2;
    return num;
  }
 
  public u32(): number {
    const num = this.view.getUint32(this.x);
    this.x += 4;
    return num;
  }
 
  public i32(): number {
    const num = this.view.getInt32(this.x);
    this.x += 4;
    return num;
  }
 
  public u64(): bigint {
    const num = this.view.getBigUint64(this.x);
    this.x += 8;
    return num;
  }
 
  public i64(): bigint {
    const num = this.view.getBigInt64(this.x);
    this.x += 8;
    return num;
  }
 
  public f32(): number {
    const pos = this.x;
    this.x += 4;
    return this.view.getFloat32(pos);
  }
 
  public f64(): number {
    const pos = this.x;
    this.x += 8;
    return this.view.getFloat64(pos);
  }
 
  public utf8(size: number): string {
    const start = this.x;
    this.x += size;
    return decodeUtf8(this.uint8, start, size);
  }
 
  public ascii(length: number): string {
    const uint8 = this.uint8;
    let str = '';
    const end = this.x + length;
    for (let i = this.x; i < end; i++) str += String.fromCharCode(uint8[i]);
    this.x = end;
    return str;
  }
}