# All files / src/utils output-stream.js

98.28% Statements 57/58
86.96% Branches 20/23
100% Functions 8/8
98.25% Lines 56/57

    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
    21x
    21x

    969x

    969x

    7442x
    7442x

    2737x
    2737x
    2737x
    2737x

    440x
    440x
    440x
    440x

    9x
    9x
    9x
    9x

    4256x
    4256x

    7442x
    7442x

    7442x

    2737x
    2737x
    2756x
    2756x
    2756x
    2737x
    2737x

    19x

    2737x

    449x
    449x
    451x
    451x
    451x
    451x

    451x
    449x
    449x

    2x

    449x

    63x
    63x
    63x
    63x
    6961x
    3029x

    3951x
    3951x

    63x

    1217x
    903x
    903x

    1217x

     // @flow
    import invariant from "invariant";
    import { sizeof, set, u8 } from "wasm-types";

    // Used to output raw binary, holds values and types in a large array 'stream'
    export default class OutputStream {
      data: Array<any>;
      size: number;

      constructor() {
        // Our data, expand it
        this.data = [];

        // start at the beginning
        this.size = 0;
      }

      push(type: string, value: any, debug: string = "") {
        let size = 0;
        switch (type) {
          case "varuint7":
          case "varuint32":
          case "varint7":
          case "varint1": {
            // Encode all of the LEB128 aka 'var*' types
            value = this.encode(value);
            size = value.length;
            invariant(size, `Cannot write a value of size ${size}`);
            break;
          }
          case "varint32": {
            value = this.encodeSigned(value);
            size = value.length;
            invariant(size, `Cannot write a value of size ${size}`);
            break;
          }
          case "varint64": {
            value = this.encodeSigned(value, 64);
            size = value.length;
            invariant(size, `Cannot write a value of size ${size}`);
            break;
          }
          default: {
            size = sizeof[type];
            invariant(size, `Cannot write a value of size ${size}, type ${type}`);
          }
        }

        this.data.push({ type, value, debug });
        this.size += size;

        return this;
      }

      encode(value: number) {
        const encoding = [];
        while (true) {
          const i = value & 127;
          value = value >>> 7;
          if (value === 0) {
            encoding.push(i);
            break;
          }

          encoding.push(i | 0x80);
        }

        return encoding;
      }

      encodeSigned(value: number, size: number = 32) {
        const encoding = [];
        while (true) {
          const byte = value & 127;
          value = value >>> 7;
          const signbit = byte & 0x40;
          Iif (value < 0) {
            value = value | (~0 << (size - 7));
          }

          if ((value === 0 && !signbit) || (value === -1 && signbit)) {
            encoding.push(byte);
            break;
          } else {
            encoding.push(byte | 0x80);
          }
        }
        return encoding;
      }

      // Get the BUFFER, not data array. **Always creates new buffer**
      buffer() {
        const buffer = new ArrayBuffer(this.size);
        const view = new DataView(buffer);
        let pc = 0;
        this.data.forEach(({ type, value }) => {
          if (Array.isArray(value)) {
            value.forEach(v => set(u8, pc++, view, v));
          } else {
            set(type, pc, view, value);
            pc += sizeof[type];
          }
        });
        return buffer;
      }

      // Writes source OutputStream into the current buffer
      write(source: ?OutputStream) {
        if (source) {
          this.data = this.data.concat(source.data);
          this.size += source.size;
        }

        return this;
      }
    }