Press n or j to go to the next uncovered block, b, p or k for the previous block.
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 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 6296x 6296x 6296x 6296x 6296x 6296x 6296x 6296x 6296x 6296x 6296x 6296x 6296x 6296x 15070x 15070x 15070x 4544x 4544x 4544x 4544x 4544x 4544x 4544x 4544x 4544x 4544x 4544x 4544x 15070x 10526x 10526x 6296x 6296x 6296x 6296x 6296x 6296x 6296x 6296x 6296x 1x 1x 1x 1x 1x 6427x 6427x 6427x 6427x 6427x 6427x 6427x 15163x 15163x 15163x 4754x 4754x 4754x 4754x 4754x 4754x 15163x 10409x 10409x 10409x 10409x 15163x 15163x 15163x 15163x 15163x 6427x 6427x 6427x 6427x 1x 1x 1x 1x 1x 2404x 2404x 2404x 2404x 2404x 2404x 2404x 2404x 2404x 2404x 2404x 2404x 2404x 2243x 2243x 2243x 2243x 2243x 2243x 2243x 481x 481x 481x 2243x 2243x 2243x 2243x 2243x 2243x 2243x 2243x 2404x 2404x 2243x 2243x 481x 481x 481x 481x 481x 481x 481x 481x 481x 481x 2243x 2243x 2243x 2243x 2243x 2404x | import { defineProperties, isError, assert, assertArgument, assertArgumentCount } from "../../utils/index.js"; import { Typed } from "../typed.js"; import { Coder, Result, WordSize, Writer } from "./abstract-coder.js"; import { AnonymousCoder } from "./anonymous.js"; import type { Reader } from "./abstract-coder.js"; /** * @_ignore */ export function pack(writer: Writer, coders: ReadonlyArray<Coder>, values: Array<any> | { [ name: string ]: any }): number { let arrayValues: Array<any> = [ ]; if (Array.isArray(values)) { arrayValues = values; } else if (values && typeof(values) === "object") { let unique: { [ name: string ]: boolean } = { }; arrayValues = coders.map((coder) => { const name = coder.localName; assert(name, "cannot encode object for signature with missing names", "INVALID_ARGUMENT", { argument: "values", info: { coder }, value: values }); 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 { assertArgument(false, "invalid tuple value", "tuple", values); } assertArgument(coders.length === arrayValues.length, "types/value length mismatch", "tuple", values); let staticWriter = new Writer(); let dynamicWriter = new Writer(); let updateFuncs: Array<(baseOffset: number) => void> = []; 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: number) => { 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; } /** * @_ignore */ export function unpack(reader: Reader, coders: ReadonlyArray<Coder>): Result { let values: Array<any> = []; let keys: Array<null | string> = [ ]; // A reader anchored to this base let baseReader = reader.subReader(0); coders.forEach((coder) => { let value: any = null; if (coder.dynamic) { let offset = reader.readIndex(); let offsetReader = baseReader.subReader(offset); try { value = coder.decode(offsetReader); } catch (error: any) { // Cannot recover from this if (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: any) { // Cannot recover from this if (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 Result.fromItems(values, keys); } /** * @_ignore */ export class ArrayCoder extends Coder { readonly coder!: Coder; readonly length!: number; constructor(coder: Coder, length: number, localName: string) { const type = (coder.type + "[" + (length >= 0 ? length: "") + "]"); const dynamic = (length === -1 || coder.dynamic); super("array", type, localName, dynamic); defineProperties<ArrayCoder>(this, { coder, length }); } defaultValue(): Array<any> { // Verifies the child coder is valid (even if the array is dynamic or 0-length) const defaultChild = this.coder.defaultValue(); const result: Array<any> = []; for (let i = 0; i < this.length; i++) { result.push(defaultChild); } return result; } encode(writer: Writer, _value: Array<any> | Typed): number { const value = 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); } assertArgumentCount(value.length, count, "coder array" + (this.localName? (" "+ this.localName): "")); let coders: Array<Coder> = [ ]; for (let i = 0; i < value.length; i++) { coders.push(this.coder); } return pack(writer, coders, value); } decode(reader: Reader): any { 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. assert(count * WordSize <= reader.dataLength, "insufficient data length", "BUFFER_OVERRUN", { buffer: reader.bytes, offset: count * WordSize, length: reader.dataLength }); } let coders: Array<Coder> = []; for (let i = 0; i < count; i++) { coders.push(new AnonymousCoder(this.coder)); } return unpack(reader, coders); } } |