...

Text file src/github.com/google/flatbuffers/ts/flexbuffers/reference.ts

Documentation: github.com/google/flatbuffers/ts/flexbuffers

     1import { fromByteWidth } from './bit-width-util.js'
     2import { ValueType } from './value-type.js'
     3import { isNumber, isIndirectNumber, isAVector, fixedTypedVectorElementSize, isFixedTypedVector, isTypedVector, typedVectorElementType, packedType, fixedTypedVectorElementType } from './value-type-util.js'
     4import { indirect, keyForIndex, keyIndex, readFloat, readInt, readUInt } from './reference-util.js'
     5import { fromUTF8Array } from './flexbuffers-util.js';
     6import { BitWidth } from './bit-width.js';
     7
     8export function toReference(buffer: ArrayBuffer): Reference {
     9  const len = buffer.byteLength;
    10
    11  if (len < 3) {
    12    throw "Buffer needs to be bigger than 3";
    13  }
    14
    15  const dataView = new DataView(buffer);
    16  const byteWidth = dataView.getUint8(len - 1);
    17  const packedType = dataView.getUint8(len - 2);
    18  const parentWidth = fromByteWidth(byteWidth);
    19  const offset = len - byteWidth - 2;
    20
    21  return new Reference(dataView, offset, parentWidth, packedType, "/")
    22}
    23
    24function valueForIndexWithKey(index: number, key: string, dataView: DataView, offset: number, parentWidth: number, byteWidth: number, length: number, path: string): Reference {
    25  const _indirect = indirect(dataView, offset, parentWidth);
    26  const elementOffset = _indirect + index * byteWidth;
    27  const packedType = dataView.getUint8(_indirect + length * byteWidth + index);
    28  return new Reference(dataView, elementOffset, fromByteWidth(byteWidth), packedType, `${path}/${key}`)
    29}
    30
    31export class Reference {
    32  private readonly byteWidth: number
    33  private readonly valueType: ValueType
    34  private _length = -1
    35  constructor(private dataView: DataView, private offset: number, private parentWidth: number, private packedType: ValueType, private path: string) {
    36    this.byteWidth = 1 << (packedType & 3)
    37    this.valueType = packedType >> 2
    38  }
    39
    40  isNull(): boolean { return this.valueType === ValueType.NULL; }
    41  isNumber(): boolean { return isNumber(this.valueType) || isIndirectNumber(this.valueType); }
    42  isFloat(): boolean { return ValueType.FLOAT === this.valueType || ValueType.INDIRECT_FLOAT === this.valueType; }
    43  isInt(): boolean { return this.isNumber() && !this.isFloat(); }
    44  isString(): boolean { return ValueType.STRING === this.valueType || ValueType.KEY === this.valueType; }
    45  isBool(): boolean { return ValueType.BOOL === this.valueType; }
    46  isBlob(): boolean { return ValueType.BLOB === this.valueType; }
    47  isVector(): boolean { return isAVector(this.valueType); }
    48  isMap(): boolean { return ValueType.MAP === this.valueType; }
    49
    50  boolValue(): boolean | null {
    51    if (this.isBool()) {
    52      return readInt(this.dataView, this.offset, this.parentWidth) > 0;
    53    }
    54    return null;
    55  }
    56
    57  intValue(): number | bigint | null {
    58    if (this.valueType === ValueType.INT) {
    59      return readInt(this.dataView, this.offset, this.parentWidth);
    60    }
    61    if (this.valueType === ValueType.UINT) {
    62      return readUInt(this.dataView, this.offset, this.parentWidth);
    63    }
    64    if (this.valueType === ValueType.INDIRECT_INT) {
    65      return readInt(this.dataView, indirect(this.dataView, this.offset, this.parentWidth), fromByteWidth(this.byteWidth));
    66    }
    67    if (this.valueType === ValueType.INDIRECT_UINT) {
    68      return readUInt(this.dataView, indirect(this.dataView, this.offset, this.parentWidth), fromByteWidth(this.byteWidth));
    69    }
    70    return null;
    71  }
    72
    73  floatValue(): number | null {
    74    if (this.valueType === ValueType.FLOAT) {
    75      return readFloat(this.dataView, this.offset, this.parentWidth);
    76    }
    77    if (this.valueType === ValueType.INDIRECT_FLOAT) {
    78      return readFloat(this.dataView, indirect(this.dataView, this.offset, this.parentWidth), fromByteWidth(this.byteWidth));
    79    }
    80    return null;
    81  }
    82
    83  numericValue(): number | bigint | null { return this.floatValue() || this.intValue()}
    84
    85  stringValue(): string | null {
    86    if (this.valueType === ValueType.STRING || this.valueType === ValueType.KEY) {
    87      const begin = indirect(this.dataView, this.offset, this.parentWidth);
    88      return fromUTF8Array(new Uint8Array(this.dataView.buffer, begin, this.length()));
    89    }
    90    return null;
    91  }
    92
    93  blobValue(): Uint8Array | null {
    94    if (this.isBlob()) {
    95      const begin = indirect(this.dataView, this.offset, this.parentWidth);
    96      return new Uint8Array(this.dataView.buffer, begin, this.length());
    97    }
    98    return null;
    99  }
   100
   101  get(key: number): Reference {
   102    const length = this.length();
   103    if (Number.isInteger(key) && isAVector(this.valueType)) {
   104      if (key >= length || key < 0) {
   105        throw `Key: [${key}] is not applicable on ${this.path} of ${this.valueType} length: ${length}`;
   106      }
   107      const _indirect = indirect(this.dataView, this.offset, this.parentWidth);
   108      const elementOffset = _indirect + key * this.byteWidth;
   109      let _packedType = this.dataView.getUint8(_indirect + length * this.byteWidth + key);
   110      if (isTypedVector(this.valueType)) {
   111        const _valueType = typedVectorElementType(this.valueType);
   112        _packedType = packedType(_valueType, BitWidth.WIDTH8);
   113      } else if (isFixedTypedVector(this.valueType)) {
   114        const _valueType = fixedTypedVectorElementType(this.valueType);
   115        _packedType = packedType(_valueType, BitWidth.WIDTH8);
   116      }
   117      return new Reference(this.dataView, elementOffset, fromByteWidth(this.byteWidth), _packedType, `${this.path}[${key}]`);
   118    }
   119    if (typeof key === 'string') {
   120      const index = keyIndex(key, this.dataView, this.offset, this.parentWidth, this.byteWidth, length);
   121      if (index !== null) {
   122        return valueForIndexWithKey(index, key, this.dataView, this.offset, this.parentWidth, this.byteWidth, length, this.path)
   123      }
   124    }
   125    throw `Key [${key}] is not applicable on ${this.path} of ${this.valueType}`;
   126  }
   127
   128  length(): number {
   129    let size;
   130    if (this._length > -1) {
   131      return this._length;
   132    }
   133    if (isFixedTypedVector(this.valueType)) {
   134      this._length = fixedTypedVectorElementSize(this.valueType);
   135    } else if (this.valueType === ValueType.BLOB
   136      || this.valueType === ValueType.MAP
   137      || isAVector(this.valueType)) {
   138      this._length = readUInt(this.dataView, indirect(this.dataView, this.offset, this.parentWidth) - this.byteWidth, fromByteWidth(this.byteWidth)) as number
   139    } else if (this.valueType === ValueType.NULL) {
   140      this._length = 0;
   141    } else if (this.valueType === ValueType.STRING) {
   142      const _indirect = indirect(this.dataView, this.offset, this.parentWidth);
   143      let sizeByteWidth = this.byteWidth;
   144      size = readUInt(this.dataView, _indirect - sizeByteWidth, fromByteWidth(this.byteWidth));
   145      while (this.dataView.getInt8(_indirect + (size as number)) !== 0) {
   146        sizeByteWidth <<= 1;
   147        size = readUInt(this.dataView, _indirect - sizeByteWidth, fromByteWidth(this.byteWidth));
   148      }
   149      this._length = size as number;
   150    } else if (this.valueType === ValueType.KEY) {
   151      const _indirect = indirect(this.dataView, this.offset, this.parentWidth);
   152      size = 1;
   153      while (this.dataView.getInt8(_indirect + size) !== 0) {
   154        size++;
   155      }
   156      this._length = size;
   157    } else {
   158      this._length = 1;
   159    }
   160    return Number(this._length);
   161  }
   162
   163  toObject(): unknown {
   164    const length = this.length();
   165    if (this.isVector()) {
   166      const result = [];
   167      for (let i = 0; i < length; i++) {
   168        result.push(this.get(i).toObject());
   169      }
   170      return result;
   171    }
   172    if (this.isMap()) {
   173      const result: Record<string, unknown> = {};
   174      for (let i = 0; i < length; i++) {
   175        const key = keyForIndex(i, this.dataView, this.offset, this.parentWidth, this.byteWidth);
   176        result[key] = valueForIndexWithKey(i, key, this.dataView, this.offset, this.parentWidth, this.byteWidth, length, this.path).toObject();
   177      }
   178      return result;
   179    }
   180    if (this.isNull()) {
   181      return null;
   182    }
   183    if (this.isBool()) {
   184      return this.boolValue();
   185    }
   186    if (this.isNumber()) {
   187      return this.numericValue();
   188    }
   189    return this.blobValue() || this.stringValue();
   190  }
   191}

View as plain text