array.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.ArrayCoder = exports.unpack = exports.pack = void 0;
  4. const index_js_1 = require("../../utils/index.js");
  5. const typed_js_1 = require("../typed.js");
  6. const abstract_coder_js_1 = require("./abstract-coder.js");
  7. const anonymous_js_1 = require("./anonymous.js");
  8. /**
  9. * @_ignore
  10. */
  11. function pack(writer, coders, values) {
  12. let arrayValues = [];
  13. if (Array.isArray(values)) {
  14. arrayValues = values;
  15. }
  16. else if (values && typeof (values) === "object") {
  17. let unique = {};
  18. arrayValues = coders.map((coder) => {
  19. const name = coder.localName;
  20. (0, index_js_1.assert)(name, "cannot encode object for signature with missing names", "INVALID_ARGUMENT", { argument: "values", info: { coder }, value: values });
  21. (0, index_js_1.assert)(!unique[name], "cannot encode object for signature with duplicate names", "INVALID_ARGUMENT", { argument: "values", info: { coder }, value: values });
  22. unique[name] = true;
  23. return values[name];
  24. });
  25. }
  26. else {
  27. (0, index_js_1.assertArgument)(false, "invalid tuple value", "tuple", values);
  28. }
  29. (0, index_js_1.assertArgument)(coders.length === arrayValues.length, "types/value length mismatch", "tuple", values);
  30. let staticWriter = new abstract_coder_js_1.Writer();
  31. let dynamicWriter = new abstract_coder_js_1.Writer();
  32. let updateFuncs = [];
  33. coders.forEach((coder, index) => {
  34. let value = arrayValues[index];
  35. if (coder.dynamic) {
  36. // Get current dynamic offset (for the future pointer)
  37. let dynamicOffset = dynamicWriter.length;
  38. // Encode the dynamic value into the dynamicWriter
  39. coder.encode(dynamicWriter, value);
  40. // Prepare to populate the correct offset once we are done
  41. let updateFunc = staticWriter.writeUpdatableValue();
  42. updateFuncs.push((baseOffset) => {
  43. updateFunc(baseOffset + dynamicOffset);
  44. });
  45. }
  46. else {
  47. coder.encode(staticWriter, value);
  48. }
  49. });
  50. // Backfill all the dynamic offsets, now that we know the static length
  51. updateFuncs.forEach((func) => { func(staticWriter.length); });
  52. let length = writer.appendWriter(staticWriter);
  53. length += writer.appendWriter(dynamicWriter);
  54. return length;
  55. }
  56. exports.pack = pack;
  57. /**
  58. * @_ignore
  59. */
  60. function unpack(reader, coders) {
  61. let values = [];
  62. let keys = [];
  63. // A reader anchored to this base
  64. let baseReader = reader.subReader(0);
  65. coders.forEach((coder) => {
  66. let value = null;
  67. if (coder.dynamic) {
  68. let offset = reader.readIndex();
  69. let offsetReader = baseReader.subReader(offset);
  70. try {
  71. value = coder.decode(offsetReader);
  72. }
  73. catch (error) {
  74. // Cannot recover from this
  75. if ((0, index_js_1.isError)(error, "BUFFER_OVERRUN")) {
  76. throw error;
  77. }
  78. value = error;
  79. value.baseType = coder.name;
  80. value.name = coder.localName;
  81. value.type = coder.type;
  82. }
  83. }
  84. else {
  85. try {
  86. value = coder.decode(reader);
  87. }
  88. catch (error) {
  89. // Cannot recover from this
  90. if ((0, index_js_1.isError)(error, "BUFFER_OVERRUN")) {
  91. throw error;
  92. }
  93. value = error;
  94. value.baseType = coder.name;
  95. value.name = coder.localName;
  96. value.type = coder.type;
  97. }
  98. }
  99. if (value == undefined) {
  100. throw new Error("investigate");
  101. }
  102. values.push(value);
  103. keys.push(coder.localName || null);
  104. });
  105. return abstract_coder_js_1.Result.fromItems(values, keys);
  106. }
  107. exports.unpack = unpack;
  108. /**
  109. * @_ignore
  110. */
  111. class ArrayCoder extends abstract_coder_js_1.Coder {
  112. coder;
  113. length;
  114. constructor(coder, length, localName) {
  115. const type = (coder.type + "[" + (length >= 0 ? length : "") + "]");
  116. const dynamic = (length === -1 || coder.dynamic);
  117. super("array", type, localName, dynamic);
  118. (0, index_js_1.defineProperties)(this, { coder, length });
  119. }
  120. defaultValue() {
  121. // Verifies the child coder is valid (even if the array is dynamic or 0-length)
  122. const defaultChild = this.coder.defaultValue();
  123. const result = [];
  124. for (let i = 0; i < this.length; i++) {
  125. result.push(defaultChild);
  126. }
  127. return result;
  128. }
  129. encode(writer, _value) {
  130. const value = typed_js_1.Typed.dereference(_value, "array");
  131. if (!Array.isArray(value)) {
  132. this._throwError("expected array value", value);
  133. }
  134. let count = this.length;
  135. if (count === -1) {
  136. count = value.length;
  137. writer.writeValue(value.length);
  138. }
  139. (0, index_js_1.assertArgumentCount)(value.length, count, "coder array" + (this.localName ? (" " + this.localName) : ""));
  140. let coders = [];
  141. for (let i = 0; i < value.length; i++) {
  142. coders.push(this.coder);
  143. }
  144. return pack(writer, coders, value);
  145. }
  146. decode(reader) {
  147. let count = this.length;
  148. if (count === -1) {
  149. count = reader.readIndex();
  150. // Check that there is *roughly* enough data to ensure
  151. // stray random data is not being read as a length. Each
  152. // slot requires at least 32 bytes for their value (or 32
  153. // bytes as a link to the data). This could use a much
  154. // tighter bound, but we are erroring on the side of safety.
  155. (0, index_js_1.assert)(count * abstract_coder_js_1.WordSize <= reader.dataLength, "insufficient data length", "BUFFER_OVERRUN", { buffer: reader.bytes, offset: count * abstract_coder_js_1.WordSize, length: reader.dataLength });
  156. }
  157. let coders = [];
  158. for (let i = 0; i < count; i++) {
  159. coders.push(new anonymous_js_1.AnonymousCoder(this.coder));
  160. }
  161. return unpack(reader, coders);
  162. }
  163. }
  164. exports.ArrayCoder = ArrayCoder;
  165. //# sourceMappingURL=array.js.map