You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
6.2 KiB
165 lines
6.2 KiB
"use strict"; |
|
Object.defineProperty(exports, "__esModule", { value: true }); |
|
exports.ArrayCoder = exports.unpack = exports.pack = void 0; |
|
const index_js_1 = require("../../utils/index.js"); |
|
const typed_js_1 = require("../typed.js"); |
|
const abstract_coder_js_1 = require("./abstract-coder.js"); |
|
const anonymous_js_1 = require("./anonymous.js"); |
|
/** |
|
* @_ignore |
|
*/ |
|
function pack(writer, coders, values) { |
|
let arrayValues = []; |
|
if (Array.isArray(values)) { |
|
arrayValues = values; |
|
} |
|
else if (values && typeof (values) === "object") { |
|
let unique = {}; |
|
arrayValues = coders.map((coder) => { |
|
const name = coder.localName; |
|
(0, index_js_1.assert)(name, "cannot encode object for signature with missing names", "INVALID_ARGUMENT", { argument: "values", info: { coder }, value: values }); |
|
(0, index_js_1.assert)(!unique[name], "cannot encode object for signature with duplicate names", "INVALID_ARGUMENT", { argument: "values", info: { coder }, value: values }); |
|
unique[name] = true; |
|
return values[name]; |
|
}); |
|
} |
|
else { |
|
(0, index_js_1.assertArgument)(false, "invalid tuple value", "tuple", values); |
|
} |
|
(0, index_js_1.assertArgument)(coders.length === arrayValues.length, "types/value length mismatch", "tuple", values); |
|
let staticWriter = new abstract_coder_js_1.Writer(); |
|
let dynamicWriter = new abstract_coder_js_1.Writer(); |
|
let updateFuncs = []; |
|
coders.forEach((coder, index) => { |
|
let value = arrayValues[index]; |
|
if (coder.dynamic) { |
|
// Get current dynamic offset (for the future pointer) |
|
let dynamicOffset = dynamicWriter.length; |
|
// Encode the dynamic value into the dynamicWriter |
|
coder.encode(dynamicWriter, value); |
|
// Prepare to populate the correct offset once we are done |
|
let updateFunc = staticWriter.writeUpdatableValue(); |
|
updateFuncs.push((baseOffset) => { |
|
updateFunc(baseOffset + dynamicOffset); |
|
}); |
|
} |
|
else { |
|
coder.encode(staticWriter, value); |
|
} |
|
}); |
|
// Backfill all the dynamic offsets, now that we know the static length |
|
updateFuncs.forEach((func) => { func(staticWriter.length); }); |
|
let length = writer.appendWriter(staticWriter); |
|
length += writer.appendWriter(dynamicWriter); |
|
return length; |
|
} |
|
exports.pack = pack; |
|
/** |
|
* @_ignore |
|
*/ |
|
function unpack(reader, coders) { |
|
let values = []; |
|
let keys = []; |
|
// A reader anchored to this base |
|
let baseReader = reader.subReader(0); |
|
coders.forEach((coder) => { |
|
let value = null; |
|
if (coder.dynamic) { |
|
let offset = reader.readIndex(); |
|
let offsetReader = baseReader.subReader(offset); |
|
try { |
|
value = coder.decode(offsetReader); |
|
} |
|
catch (error) { |
|
// Cannot recover from this |
|
if ((0, index_js_1.isError)(error, "BUFFER_OVERRUN")) { |
|
throw error; |
|
} |
|
value = error; |
|
value.baseType = coder.name; |
|
value.name = coder.localName; |
|
value.type = coder.type; |
|
} |
|
} |
|
else { |
|
try { |
|
value = coder.decode(reader); |
|
} |
|
catch (error) { |
|
// Cannot recover from this |
|
if ((0, index_js_1.isError)(error, "BUFFER_OVERRUN")) { |
|
throw error; |
|
} |
|
value = error; |
|
value.baseType = coder.name; |
|
value.name = coder.localName; |
|
value.type = coder.type; |
|
} |
|
} |
|
if (value == undefined) { |
|
throw new Error("investigate"); |
|
} |
|
values.push(value); |
|
keys.push(coder.localName || null); |
|
}); |
|
return abstract_coder_js_1.Result.fromItems(values, keys); |
|
} |
|
exports.unpack = unpack; |
|
/** |
|
* @_ignore |
|
*/ |
|
class ArrayCoder extends abstract_coder_js_1.Coder { |
|
coder; |
|
length; |
|
constructor(coder, length, localName) { |
|
const type = (coder.type + "[" + (length >= 0 ? length : "") + "]"); |
|
const dynamic = (length === -1 || coder.dynamic); |
|
super("array", type, localName, dynamic); |
|
(0, index_js_1.defineProperties)(this, { coder, length }); |
|
} |
|
defaultValue() { |
|
// Verifies the child coder is valid (even if the array is dynamic or 0-length) |
|
const defaultChild = this.coder.defaultValue(); |
|
const result = []; |
|
for (let i = 0; i < this.length; i++) { |
|
result.push(defaultChild); |
|
} |
|
return result; |
|
} |
|
encode(writer, _value) { |
|
const value = typed_js_1.Typed.dereference(_value, "array"); |
|
if (!Array.isArray(value)) { |
|
this._throwError("expected array value", value); |
|
} |
|
let count = this.length; |
|
if (count === -1) { |
|
count = value.length; |
|
writer.writeValue(value.length); |
|
} |
|
(0, index_js_1.assertArgumentCount)(value.length, count, "coder array" + (this.localName ? (" " + this.localName) : "")); |
|
let coders = []; |
|
for (let i = 0; i < value.length; i++) { |
|
coders.push(this.coder); |
|
} |
|
return pack(writer, coders, value); |
|
} |
|
decode(reader) { |
|
let count = this.length; |
|
if (count === -1) { |
|
count = reader.readIndex(); |
|
// Check that there is *roughly* enough data to ensure |
|
// stray random data is not being read as a length. Each |
|
// slot requires at least 32 bytes for their value (or 32 |
|
// bytes as a link to the data). This could use a much |
|
// tighter bound, but we are erroring on the side of safety. |
|
(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 }); |
|
} |
|
let coders = []; |
|
for (let i = 0; i < count; i++) { |
|
coders.push(new anonymous_js_1.AnonymousCoder(this.coder)); |
|
} |
|
return unpack(reader, coders); |
|
} |
|
} |
|
exports.ArrayCoder = ArrayCoder; |
|
//# sourceMappingURL=array.js.map
|