text: "use strict";
  import { arrayify, concat, hexConcat, hexlify } from "@420integrated/bytes";
  import { BigNumber } from "@420integrated/bignumber";
  import { defineReadOnly } from "@420integrated/properties";
  import { Logger } from "@420integrated/logger";
  import { version } from "../_version";
  const logger = new Logger(version);
  export function checkResultErrors(result) {
      // Find the first error (if any)
      const errors = [];
      const checkErrors = function (path, object) {
          if (!Array.isArray(object)) {
              return;
          }
          for (let key in object) {
              const childPath = path.slice();
              childPath.push(key);
              try {
                  checkErrors(childPath, object[key]);
              }
              catch (error) {
                  errors.push({ path: childPath, error: error });
              }
          }
      };
      checkErrors([], result);
      return errors;
  }
  export class Coder {
      constructor(name, type, localName, dynamic) {
          // @TODO: defineReadOnly these
          this.name = name;
          this.type = type;
          this.localName = localName;
          this.dynamic = dynamic;
      }
      _throwError(message, value) {
          logger.throwArgumentError(message, this.localName, value);
      }
  }
  export class Writer {
      constructor(wordSize) {
          defineReadOnly(this, "wordSize", wordSize || 32);
          this._data = [];
          this._dataLength = 0;
          this._padding = new Uint8Array(wordSize);
      }
      get data() {
          return hexConcat(this._data);
      }
      get length() { return this._dataLength; }
      _writeData(data) {
          this._data.push(data);
          this._dataLength += data.length;
          return data.length;
      }
      appendWriter(writer) {
          return this._writeData(concat(writer._data));
      }
      // Arrayish items; padded on the right to wordSize
      writeBytes(value) {
          let bytes = arrayify(value);
          const paddingOffset = bytes.length % this.wordSize;
          if (paddingOffset) {
              bytes = concat([bytes, this._padding.slice(paddingOffset)]);
          }
          return this._writeData(bytes);
      }
      _getValue(value) {
          let bytes = arrayify(BigNumber.from(value));
          if (bytes.length > this.wordSize) {
              logger.throwError("value out-of-bounds", Logger.errors.BUFFER_OVERRUN, {
                  length: this.wordSize,
                  offset: bytes.length
              });
          }
          if (bytes.length % this.wordSize) {
              bytes = concat([this._padding.slice(bytes.length % this.wordSize), bytes]);
          }
          return bytes;
      }
      // BigNumberish items; padded on the left to wordSize
      writeValue(value) {
          return this._writeData(this._getValue(value));
      }
      writeUpdatableValue() {
          const offset = this._data.length;
          this._data.push(this._padding);
          this._dataLength += this.wordSize;
          return (value) => {
              this._data[offset] = this._getValue(value);
          };
      }
  }
  export class Reader {
      constructor(data, wordSize, coerceFunc, allowLoose) {
          defineReadOnly(this, "_data", arrayify(data));
          defineReadOnly(this, "wordSize", wordSize || 32);
          defineReadOnly(this, "_coerceFunc", coerceFunc);
          defineReadOnly(this, "allowLoose", allowLoose);
          this._offset = 0;
      }
      get data() { return hexlify(this._data); }
      get consumed() { return this._offset; }
      // The default Coerce function
      static coerce(name, value) {
          let match = name.match("^u?int([0-9]+)$");
          if (match && parseInt(match[1]) <= 48) {
              value = value.toNumber();
          }
          return value;
      }
      coerce(name, value) {
          if (this._coerceFunc) {
              return this._coerceFunc(name, value);
          }
          return Reader.coerce(name, value);
      }
      _peekBytes(offset, length, loose) {
          let alignedLength = Math.ceil(length / this.wordSize) * this.wordSize;
          if (this._offset + alignedLength > this._data.length) {
              if (this.allowLoose && loose && this._offset + length <= this._data.length) {
                  alignedLength = length;
              }
              else {
                  logger.throwError("data out-of-bounds", Logger.errors.BUFFER_OVERRUN, {
                      length: this._data.length,
                      offset: this._offset + alignedLength
                  });
              }
          }
          return this._data.slice(this._offset, this._offset + alignedLength);
      }
      subReader(offset) {
          return new Reader(this._data.slice(this._offset + offset), this.wordSize, this._coerceFunc, this.allowLoose);
      }
      readBytes(length, loose) {
          let bytes = this._peekBytes(0, length, !!loose);
          this._offset += bytes.length;
          // @TODO: Make sure the length..end bytes are all 0?
          return bytes.slice(0, length);
      }
      readValue() {
          return BigNumber.from(this.readBytes(this.wordSize));
      }
  }
  //# sourceMappingURL=abstract-coder.js.map