@exornea/zeno-compiler 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/zeno-codegen.mjs +117 -0
- package/dist/analyzer.d.ts +13 -0
- package/dist/analyzer.d.ts.map +1 -0
- package/dist/analyzer.js +153 -0
- package/dist/analyzer.js.map +1 -0
- package/dist/diagnostics.d.ts +38 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +36 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/emitter-fixed-array.d.ts +11 -0
- package/dist/emitter-fixed-array.d.ts.map +1 -0
- package/dist/emitter-fixed-array.js +90 -0
- package/dist/emitter-fixed-array.js.map +1 -0
- package/dist/emitter-template.d.ts +5 -0
- package/dist/emitter-template.d.ts.map +1 -0
- package/dist/emitter-template.js +37 -0
- package/dist/emitter-template.js.map +1 -0
- package/dist/emitter.d.ts +7 -0
- package/dist/emitter.d.ts.map +1 -0
- package/dist/emitter.js +746 -0
- package/dist/emitter.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/lowering.d.ts +18 -0
- package/dist/lowering.d.ts.map +1 -0
- package/dist/lowering.js +631 -0
- package/dist/lowering.js.map +1 -0
- package/dist/measurement.d.ts +41 -0
- package/dist/measurement.d.ts.map +1 -0
- package/dist/measurement.js +58 -0
- package/dist/measurement.js.map +1 -0
- package/dist/result.d.ts +20 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +25 -0
- package/dist/result.js.map +1 -0
- package/dist/validator.d.ts +4 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +342 -0
- package/dist/validator.js.map +1 -0
- package/package.json +47 -0
package/dist/emitter.js
ADDED
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
import { scalarGetterMethod, scalarSetterMethod, scalarTsType, } from "@exornea/zeno-schema";
|
|
2
|
+
import { canWriteFixedArrayStructElement, collectFixedArrayRuntimeImports, emitFixedArrayFieldAccessor, emitFixedArrayObjectFieldWrite, fixedArrayInputElementType, } from "./emitter-fixed-array.js";
|
|
3
|
+
import { method } from "./emitter-template.js";
|
|
4
|
+
export function emitStructView(layout, options = {}) {
|
|
5
|
+
return emitProjectionFile([layout], options);
|
|
6
|
+
}
|
|
7
|
+
export function emitProjectionFile(layouts, options = {}) {
|
|
8
|
+
const lines = [];
|
|
9
|
+
const runtimeImports = collectRuntimeImports(layouts);
|
|
10
|
+
const layoutMap = new Map(layouts.map((layout) => [layout.name, layout]));
|
|
11
|
+
lines.push(`import { ${runtimeImports.join(", ")} } from "@exornea/zeno-runtime";`);
|
|
12
|
+
lines.push("");
|
|
13
|
+
for (const layout of layouts) {
|
|
14
|
+
lines.push(...emitInputInterface(layout));
|
|
15
|
+
lines.push("");
|
|
16
|
+
lines.push(...emitLayoutConstants(layout));
|
|
17
|
+
lines.push("");
|
|
18
|
+
lines.push(...emitStructClass(layout, options, layoutMap));
|
|
19
|
+
lines.push("");
|
|
20
|
+
}
|
|
21
|
+
return lines.join("\n");
|
|
22
|
+
}
|
|
23
|
+
function collectRuntimeImports(layouts) {
|
|
24
|
+
const imports = new Set(["ProjectionView"]);
|
|
25
|
+
const layoutMap = new Map(layouts.map((layout) => [layout.name, layout]));
|
|
26
|
+
for (const layout of layouts) {
|
|
27
|
+
if (hasTailWriterFields(layout, layoutMap)) {
|
|
28
|
+
imports.add("DynamicLayoutWriter");
|
|
29
|
+
}
|
|
30
|
+
for (const field of layout.fields) {
|
|
31
|
+
collectFieldRuntimeImports(field, imports);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return Array.from(imports).sort();
|
|
35
|
+
}
|
|
36
|
+
function collectFieldRuntimeImports(field, imports) {
|
|
37
|
+
switch (field.kind) {
|
|
38
|
+
case "fixed-bytes":
|
|
39
|
+
imports.add("fixedBytesView");
|
|
40
|
+
imports.add("writeFixedBytes");
|
|
41
|
+
return;
|
|
42
|
+
case "fixed-string":
|
|
43
|
+
imports.add("decodeFixedText");
|
|
44
|
+
imports.add("fixedBytesView");
|
|
45
|
+
imports.add("writeFixedText");
|
|
46
|
+
return;
|
|
47
|
+
case "dynamic-string":
|
|
48
|
+
imports.add("Utf8SpanView");
|
|
49
|
+
return;
|
|
50
|
+
case "dynamic-bytes":
|
|
51
|
+
imports.add("BytesSpanView");
|
|
52
|
+
return;
|
|
53
|
+
case "vector":
|
|
54
|
+
switch (field.element.kind) {
|
|
55
|
+
case "scalar":
|
|
56
|
+
imports.add("ScalarVectorView");
|
|
57
|
+
return;
|
|
58
|
+
case "dynamic-string":
|
|
59
|
+
imports.add("Utf8VectorView");
|
|
60
|
+
return;
|
|
61
|
+
case "dynamic-bytes":
|
|
62
|
+
imports.add("BytesVectorView");
|
|
63
|
+
return;
|
|
64
|
+
case "fixed-bytes":
|
|
65
|
+
imports.add("FixedBytesVectorView");
|
|
66
|
+
return;
|
|
67
|
+
case "fixed-string":
|
|
68
|
+
imports.add("FixedStringVectorView");
|
|
69
|
+
return;
|
|
70
|
+
case "struct":
|
|
71
|
+
imports.add("StructVectorView");
|
|
72
|
+
return;
|
|
73
|
+
case "pointer":
|
|
74
|
+
imports.add("PointerVectorView");
|
|
75
|
+
return;
|
|
76
|
+
default:
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
case "fixed-array":
|
|
80
|
+
collectFixedArrayRuntimeImports(field.element, imports);
|
|
81
|
+
return;
|
|
82
|
+
default:
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function emitInputInterface(layout) {
|
|
87
|
+
const lines = [`export interface ${layout.name}ViewInput {`];
|
|
88
|
+
for (const field of layout.fields) {
|
|
89
|
+
lines.push(` readonly ${field.name}: ${fieldInputType(field)};`);
|
|
90
|
+
}
|
|
91
|
+
lines.push("}");
|
|
92
|
+
return lines;
|
|
93
|
+
}
|
|
94
|
+
function fieldInputType(field) {
|
|
95
|
+
switch (field.kind) {
|
|
96
|
+
case "scalar":
|
|
97
|
+
return scalarTsType(field.scalar);
|
|
98
|
+
case "fixed-bytes":
|
|
99
|
+
case "dynamic-bytes":
|
|
100
|
+
return "ArrayLike<number> | Uint8Array";
|
|
101
|
+
case "fixed-string":
|
|
102
|
+
case "dynamic-string":
|
|
103
|
+
return "string";
|
|
104
|
+
case "struct":
|
|
105
|
+
return `${field.typeName}ViewInput`;
|
|
106
|
+
case "pointer":
|
|
107
|
+
return "number | null";
|
|
108
|
+
case "fixed-array":
|
|
109
|
+
return `readonly ${fixedArrayInputElementType(field.element)}[]`;
|
|
110
|
+
case "vector":
|
|
111
|
+
switch (field.element.kind) {
|
|
112
|
+
case "scalar":
|
|
113
|
+
return `readonly ${scalarTsType(field.element.scalar)}[]`;
|
|
114
|
+
case "fixed-bytes":
|
|
115
|
+
case "dynamic-bytes":
|
|
116
|
+
return "readonly (ArrayLike<number> | Uint8Array)[]";
|
|
117
|
+
case "fixed-string":
|
|
118
|
+
case "dynamic-string":
|
|
119
|
+
return "readonly string[]";
|
|
120
|
+
case "struct":
|
|
121
|
+
return `readonly ${field.element.typeName}ViewInput[]`;
|
|
122
|
+
case "pointer":
|
|
123
|
+
return "readonly (number | null)[]";
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function emitLayoutConstants(layout) {
|
|
128
|
+
const lines = [];
|
|
129
|
+
lines.push(`export const ${layout.name}ViewByteLength = ${layout.byteLength};`);
|
|
130
|
+
lines.push(`export const ${layout.name}ViewAlignment = ${layout.alignment};`);
|
|
131
|
+
for (const field of layout.fields) {
|
|
132
|
+
lines.push(`export const ${layout.name}View${toPascalCase(field.name)}Offset = ${field.offset};`);
|
|
133
|
+
}
|
|
134
|
+
return lines;
|
|
135
|
+
}
|
|
136
|
+
function emitStructClass(layout, options, layoutMap) {
|
|
137
|
+
const scalarFields = layout.fields.filter((field) => field.kind === "scalar");
|
|
138
|
+
const littleEndianDefault = toLittleEndianLiteral(layout);
|
|
139
|
+
const lines = [`export class ${layout.name}View extends ProjectionView {`];
|
|
140
|
+
lines.push(...method `
|
|
141
|
+
static readonly byteLength = ${layout.byteLength};
|
|
142
|
+
static readonly alignment = ${layout.alignment};
|
|
143
|
+
${layout.fields.map((field) => `static readonly ${field.name}Offset = ${field.offset};`)}`);
|
|
144
|
+
if (layout.fields.some((field) => field.kind === "pointer")) {
|
|
145
|
+
lines.push("");
|
|
146
|
+
lines.push(...method `
|
|
147
|
+
private static assertPointer32Payload(value: number): void {
|
|
148
|
+
if (!Number.isInteger(value) || value < -0x80000000 || value > 0x7fffffff || value === -1) {
|
|
149
|
+
throw new RangeError(\`pointer32 target offset must encode to signed i32 except -1: \${value}\`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private static assertPointerTargetRange(view: DataView, targetOffset: number, byteLength: number): void {
|
|
154
|
+
if (!Number.isSafeInteger(targetOffset) || targetOffset < 0) {
|
|
155
|
+
throw new RangeError(\`pointer32 target offset must be a non-negative safe integer: \${targetOffset}\`);
|
|
156
|
+
}
|
|
157
|
+
if (!Number.isSafeInteger(byteLength) || byteLength < 0) {
|
|
158
|
+
throw new RangeError(\`pointer32 target byteLength must be a non-negative safe integer: \${byteLength}\`);
|
|
159
|
+
}
|
|
160
|
+
if (byteLength > view.byteLength - targetOffset) {
|
|
161
|
+
throw new RangeError(\`pointer32 target \${targetOffset}..\${targetOffset + byteLength} exceeds DataView length \${view.byteLength}\`);
|
|
162
|
+
}
|
|
163
|
+
}`);
|
|
164
|
+
}
|
|
165
|
+
if (options.optimizeCursorOffsets && scalarFields.length > 0) {
|
|
166
|
+
lines.push("");
|
|
167
|
+
lines.push(...method `${scalarFields.map((field) => `private $${field.name}Offset = ${field.offset};`)}`);
|
|
168
|
+
}
|
|
169
|
+
lines.push("");
|
|
170
|
+
if (options.optimizeCursorOffsets && scalarFields.length > 0) {
|
|
171
|
+
lines.push(...method `
|
|
172
|
+
constructor(view: DataView, baseOffset = 0, littleEndian = ${littleEndianDefault}) {
|
|
173
|
+
super(view, baseOffset, littleEndian);
|
|
174
|
+
this.$refreshOffsets();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private $refreshOffsets(): void {
|
|
178
|
+
${scalarFields.map((field) => ` this.$${field.name}Offset = this.baseOffset + ${field.offset};`)}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
override rebase(baseOffset: number): this {
|
|
182
|
+
super.rebase(baseOffset);
|
|
183
|
+
this.$refreshOffsets();
|
|
184
|
+
return this;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
override rebaseUnchecked(baseOffset: number): this {
|
|
188
|
+
super.rebaseUnchecked(baseOffset);
|
|
189
|
+
this.$refreshOffsets();
|
|
190
|
+
return this;
|
|
191
|
+
}`);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
lines.push(...method `
|
|
195
|
+
constructor(view: DataView, baseOffset = 0, littleEndian = ${littleEndianDefault}) {
|
|
196
|
+
super(view, baseOffset, littleEndian);
|
|
197
|
+
}`);
|
|
198
|
+
}
|
|
199
|
+
lines.push("");
|
|
200
|
+
lines.push(...method `
|
|
201
|
+
static at(view: DataView, baseOffset = 0, littleEndian = ${littleEndianDefault}): ${layout.name}View {
|
|
202
|
+
return new ${layout.name}View(view, baseOffset, littleEndian);
|
|
203
|
+
}`);
|
|
204
|
+
lines.push("");
|
|
205
|
+
if (options.optimizeCursorOffsets && scalarFields.length > 0) {
|
|
206
|
+
lines.push(...method `
|
|
207
|
+
moveTo(index: number): this {
|
|
208
|
+
this.moveToIndex(index, ${layout.name}View.byteLength);
|
|
209
|
+
this.$refreshOffsets();
|
|
210
|
+
return this;
|
|
211
|
+
}`);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
lines.push(...method `
|
|
215
|
+
moveTo(index: number): this {
|
|
216
|
+
return this.moveToIndex(index, ${layout.name}View.byteLength);
|
|
217
|
+
}`);
|
|
218
|
+
}
|
|
219
|
+
lines.push("");
|
|
220
|
+
lines.push(...method `
|
|
221
|
+
moveToUnchecked(index: number): this {
|
|
222
|
+
return this.rebaseUnchecked(index * ${layout.byteLength});
|
|
223
|
+
}`);
|
|
224
|
+
lines.push("");
|
|
225
|
+
const writerLines = emitDynamicWriterMethods(layout, layoutMap);
|
|
226
|
+
for (const line of writerLines) {
|
|
227
|
+
lines.push(line);
|
|
228
|
+
}
|
|
229
|
+
if (writerLines.length > 0) {
|
|
230
|
+
lines.push("");
|
|
231
|
+
}
|
|
232
|
+
const objectWriterLines = emitObjectWriterMethod(layout, layoutMap);
|
|
233
|
+
for (const line of objectWriterLines) {
|
|
234
|
+
lines.push(line);
|
|
235
|
+
}
|
|
236
|
+
if (objectWriterLines.length > 0) {
|
|
237
|
+
lines.push("");
|
|
238
|
+
}
|
|
239
|
+
for (const field of layout.fields) {
|
|
240
|
+
const staticAccessorLines = emitStaticFieldAccessor(layout, field);
|
|
241
|
+
for (const line of staticAccessorLines) {
|
|
242
|
+
lines.push(line);
|
|
243
|
+
}
|
|
244
|
+
if (staticAccessorLines.length > 0) {
|
|
245
|
+
lines.push("");
|
|
246
|
+
}
|
|
247
|
+
for (const line of emitField(layout, field, options)) {
|
|
248
|
+
lines.push(line);
|
|
249
|
+
}
|
|
250
|
+
lines.push("");
|
|
251
|
+
}
|
|
252
|
+
lines.push("}");
|
|
253
|
+
return lines;
|
|
254
|
+
}
|
|
255
|
+
function emitDynamicWriterMethods(layout, layoutMap) {
|
|
256
|
+
const fields = layout.fields.filter((field) => isTailWriterField(field, layoutMap));
|
|
257
|
+
if (fields.length === 0) {
|
|
258
|
+
return [];
|
|
259
|
+
}
|
|
260
|
+
const lines = [
|
|
261
|
+
...method `
|
|
262
|
+
static createWriter(view: DataView, baseOffset = 0, tailOffset = ${layout.name}View.byteLength, littleEndian = ${toLittleEndianLiteral(layout)}): DynamicLayoutWriter {
|
|
263
|
+
return new DynamicLayoutWriter(view, tailOffset, baseOffset, littleEndian);
|
|
264
|
+
}`,
|
|
265
|
+
"",
|
|
266
|
+
];
|
|
267
|
+
for (const field of fields) {
|
|
268
|
+
const pascalName = toPascalCase(field.name);
|
|
269
|
+
switch (field.kind) {
|
|
270
|
+
case "dynamic-string":
|
|
271
|
+
lines.push(...method `
|
|
272
|
+
static write${pascalName}(writer: DynamicLayoutWriter, value: string) {
|
|
273
|
+
return writer.writeText(${layout.name}View.${field.name}Offset, value, ${encodingLiteral(field.encoding)});
|
|
274
|
+
}`);
|
|
275
|
+
break;
|
|
276
|
+
case "dynamic-bytes":
|
|
277
|
+
lines.push(...method `
|
|
278
|
+
static write${pascalName}(writer: DynamicLayoutWriter, value: ArrayLike<number> | Uint8Array) {
|
|
279
|
+
return writer.writeBytes(${layout.name}View.${field.name}Offset, value);
|
|
280
|
+
}`);
|
|
281
|
+
break;
|
|
282
|
+
case "vector":
|
|
283
|
+
lines.push(...emitVectorWriterMethod(layout, layoutMap, field, pascalName));
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
lines.push("");
|
|
287
|
+
}
|
|
288
|
+
lines.pop();
|
|
289
|
+
return lines;
|
|
290
|
+
}
|
|
291
|
+
const vectorWriterEmitters = {
|
|
292
|
+
"dynamic-string": ({ layout, field, pascalName }) => method `
|
|
293
|
+
static write${pascalName}(writer: DynamicLayoutWriter, values: readonly string[]) {
|
|
294
|
+
return writer.writeTextVector(${layout.name}View.${field.name}Offset, values, ${encodingLiteral(field.element.encoding)});
|
|
295
|
+
}`,
|
|
296
|
+
"dynamic-bytes": ({ layout, field, pascalName }) => method `
|
|
297
|
+
static write${pascalName}(writer: DynamicLayoutWriter, values: readonly (ArrayLike<number> | Uint8Array)[]) {
|
|
298
|
+
return writer.writeBytesVector(${layout.name}View.${field.name}Offset, values);
|
|
299
|
+
}`,
|
|
300
|
+
"fixed-bytes": ({ layout, field, pascalName }) => method `
|
|
301
|
+
static write${pascalName}(writer: DynamicLayoutWriter, values: readonly (ArrayLike<number> | Uint8Array)[]) {
|
|
302
|
+
return writer.writeFixedBytesVector(${layout.name}View.${field.name}Offset, values, ${field.element.byteLength});
|
|
303
|
+
}`,
|
|
304
|
+
"fixed-string": ({ layout, field, pascalName }) => method `
|
|
305
|
+
static write${pascalName}(writer: DynamicLayoutWriter, values: readonly string[]) {
|
|
306
|
+
return writer.writeFixedTextVector(${layout.name}View.${field.name}Offset, values, ${field.element.byteLength}, ${encodingLiteral(field.element.encoding)});
|
|
307
|
+
}`,
|
|
308
|
+
scalar: ({ layout, field, pascalName }) => method `
|
|
309
|
+
static write${pascalName}(writer: DynamicLayoutWriter, values: readonly ${scalarTsType(field.element.scalar)}[]) {
|
|
310
|
+
return writer.writeScalarVector(${layout.name}View.${field.name}Offset, "${field.element.scalar}", values);
|
|
311
|
+
}`,
|
|
312
|
+
struct: ({ layout, layoutMap, field, pascalName }) => {
|
|
313
|
+
const elementLayout = layoutMap.get(field.element.typeName);
|
|
314
|
+
const alignment = elementLayout?.alignment ?? 1;
|
|
315
|
+
return method `
|
|
316
|
+
static write${pascalName}(writer: DynamicLayoutWriter, values: readonly ${field.element.typeName}ViewInput[]) {
|
|
317
|
+
return writer.writeStructVector(${layout.name}View.${field.name}Offset, values, ${field.element.byteLength}, (view, value, baseOffset, littleEndian) => ${field.element.typeName}View.write(view, value, baseOffset, littleEndian), ${alignment});
|
|
318
|
+
}`;
|
|
319
|
+
},
|
|
320
|
+
pointer: ({ layout, field, pascalName }) => method `
|
|
321
|
+
static write${pascalName}(writer: DynamicLayoutWriter, values: readonly (number | null)[]) {
|
|
322
|
+
return writer.writePointerVector(${layout.name}View.${field.name}Offset, values, ${field.element.targetTypeName}View.byteLength);
|
|
323
|
+
}`,
|
|
324
|
+
};
|
|
325
|
+
function emitVectorWriterMethod(layout, layoutMap, field, pascalName) {
|
|
326
|
+
const emitWriter = vectorWriterEmitters[field.element.kind];
|
|
327
|
+
return emitWriter({ layout, layoutMap, field, pascalName });
|
|
328
|
+
}
|
|
329
|
+
function emitObjectWriterMethod(layout, layoutMap) {
|
|
330
|
+
if (!canEmitObjectWriter(layout, layoutMap)) {
|
|
331
|
+
return [];
|
|
332
|
+
}
|
|
333
|
+
const hasTailFields = hasTailWriterFields(layout, layoutMap);
|
|
334
|
+
const returnType = hasTailFields ? "DynamicLayoutWriter" : "void";
|
|
335
|
+
const bodyLines = [];
|
|
336
|
+
if (hasTailFields) {
|
|
337
|
+
bodyLines.push(` const writer = ${layout.name}View.createWriter(view, baseOffset, ${layout.name}View.byteLength, littleEndian);`);
|
|
338
|
+
}
|
|
339
|
+
for (const field of layout.fields) {
|
|
340
|
+
bodyLines.push(...emitObjectFieldWrite(layout, field));
|
|
341
|
+
}
|
|
342
|
+
if (hasTailFields) {
|
|
343
|
+
bodyLines.push(" return writer;");
|
|
344
|
+
}
|
|
345
|
+
return method `
|
|
346
|
+
static write(view: DataView, value: ${layout.name}ViewInput, baseOffset = 0, littleEndian = ${toLittleEndianLiteral(layout)}): ${returnType} {
|
|
347
|
+
${bodyLines}
|
|
348
|
+
}`;
|
|
349
|
+
}
|
|
350
|
+
function emitObjectFieldWrite(layout, field) {
|
|
351
|
+
const pascalName = toPascalCase(field.name);
|
|
352
|
+
switch (field.kind) {
|
|
353
|
+
case "scalar":
|
|
354
|
+
return [
|
|
355
|
+
` ${layout.name}View.set${pascalName}(view, value.${field.name}, baseOffset, littleEndian);`,
|
|
356
|
+
];
|
|
357
|
+
case "fixed-bytes":
|
|
358
|
+
return [
|
|
359
|
+
` writeFixedBytes(view.buffer, view.byteOffset + baseOffset + ${field.offset}, ${field.byteLength}, value.${field.name});`,
|
|
360
|
+
];
|
|
361
|
+
case "fixed-string":
|
|
362
|
+
return [
|
|
363
|
+
` writeFixedText(view.buffer, view.byteOffset + baseOffset + ${field.offset}, ${field.byteLength}, value.${field.name}, ${encodingLiteral(field.encoding)});`,
|
|
364
|
+
];
|
|
365
|
+
case "dynamic-string":
|
|
366
|
+
case "dynamic-bytes":
|
|
367
|
+
return [` ${layout.name}View.write${pascalName}(writer, value.${field.name});`];
|
|
368
|
+
case "struct":
|
|
369
|
+
return [
|
|
370
|
+
` ${field.typeName}View.write(view, value.${field.name}, baseOffset + ${field.offset}, littleEndian);`,
|
|
371
|
+
];
|
|
372
|
+
case "pointer":
|
|
373
|
+
return [
|
|
374
|
+
` ${layout.name}View.set${pascalName}TargetOffset(view, value.${field.name}, baseOffset, littleEndian);`,
|
|
375
|
+
];
|
|
376
|
+
case "fixed-array":
|
|
377
|
+
return emitFixedArrayObjectFieldWrite(field, encodingLiteral);
|
|
378
|
+
case "vector":
|
|
379
|
+
return [` ${layout.name}View.write${pascalName}(writer, value.${field.name});`];
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
function emitStaticFieldAccessor(layout, field) {
|
|
383
|
+
if (field.kind === "pointer") {
|
|
384
|
+
const pascalName = toPascalCase(field.name);
|
|
385
|
+
const littleEndianDefault = toLittleEndianLiteral(layout);
|
|
386
|
+
const indexOffset = `index * ${layout.byteLength} + ${field.offset}`;
|
|
387
|
+
const pointerPosition = `baseOffset + ${field.offset}`;
|
|
388
|
+
return method `
|
|
389
|
+
static getRaw${pascalName}RelativeOffset(view: DataView, baseOffset = 0, littleEndian = ${littleEndianDefault}): number {
|
|
390
|
+
return view.getUint32(baseOffset + ${field.offset}, littleEndian);
|
|
391
|
+
}
|
|
392
|
+
static get${pascalName}RelativeOffset(view: DataView, baseOffset = 0, littleEndian = ${littleEndianDefault}): number | null {
|
|
393
|
+
const rawValue = ${layout.name}View.getRaw${pascalName}RelativeOffset(view, baseOffset, littleEndian);
|
|
394
|
+
if (rawValue === 0xffffffff) {
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
return view.getInt32(baseOffset + ${field.offset}, littleEndian);
|
|
398
|
+
}
|
|
399
|
+
static set${pascalName}RelativeOffset(view: DataView, value: number | null, baseOffset = 0, littleEndian = ${littleEndianDefault}): void {
|
|
400
|
+
if (value === null) {
|
|
401
|
+
view.setUint32(baseOffset + ${field.offset}, 0xffffffff, littleEndian);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
${layout.name}View.assertPointer32Payload(value);
|
|
405
|
+
view.setInt32(baseOffset + ${field.offset}, value, littleEndian);
|
|
406
|
+
}
|
|
407
|
+
static getUnchecked${pascalName}TargetOffset(view: DataView, baseOffset = 0, littleEndian = ${littleEndianDefault}): number | null {
|
|
408
|
+
const relativeOffset = ${layout.name}View.get${pascalName}RelativeOffset(view, baseOffset, littleEndian);
|
|
409
|
+
if (relativeOffset === null) {
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
return ${pointerPosition} + relativeOffset;
|
|
413
|
+
}
|
|
414
|
+
static get${pascalName}TargetOffset(view: DataView, baseOffset = 0, littleEndian = ${littleEndianDefault}): number | null {
|
|
415
|
+
const targetOffset = ${layout.name}View.getUnchecked${pascalName}TargetOffset(view, baseOffset, littleEndian);
|
|
416
|
+
if (targetOffset === null) {
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
${layout.name}View.assertPointerTargetRange(view, targetOffset, ${field.targetTypeName}View.byteLength);
|
|
420
|
+
return targetOffset;
|
|
421
|
+
}
|
|
422
|
+
static setUnchecked${pascalName}TargetOffset(view: DataView, targetOffset: number | null, baseOffset = 0, littleEndian = ${littleEndianDefault}): void {
|
|
423
|
+
if (targetOffset === null) {
|
|
424
|
+
${layout.name}View.set${pascalName}RelativeOffset(view, null, baseOffset, littleEndian);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
const relativeOffset = targetOffset - (${pointerPosition});
|
|
428
|
+
${layout.name}View.set${pascalName}RelativeOffset(view, relativeOffset, baseOffset, littleEndian);
|
|
429
|
+
}
|
|
430
|
+
static set${pascalName}TargetOffset(view: DataView, targetOffset: number | null, baseOffset = 0, littleEndian = ${littleEndianDefault}): void {
|
|
431
|
+
if (targetOffset !== null) {
|
|
432
|
+
${layout.name}View.assertPointerTargetRange(view, targetOffset, ${field.targetTypeName}View.byteLength);
|
|
433
|
+
}
|
|
434
|
+
${layout.name}View.setUnchecked${pascalName}TargetOffset(view, targetOffset, baseOffset, littleEndian);
|
|
435
|
+
}
|
|
436
|
+
static get${pascalName}RelativeOffsetAt(view: DataView, index: number, littleEndian = ${littleEndianDefault}): number | null {
|
|
437
|
+
const rawValue = ${layout.name}View.getRaw${pascalName}RelativeOffset(view, index * ${layout.byteLength}, littleEndian);
|
|
438
|
+
if (rawValue === 0xffffffff) {
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
return view.getInt32(${indexOffset}, littleEndian);
|
|
442
|
+
}
|
|
443
|
+
static set${pascalName}RelativeOffsetAt(view: DataView, value: number | null, index: number, littleEndian = ${littleEndianDefault}): void {
|
|
444
|
+
if (value === null) {
|
|
445
|
+
view.setUint32(${indexOffset}, 0xffffffff, littleEndian);
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
${layout.name}View.assertPointer32Payload(value);
|
|
449
|
+
view.setInt32(${indexOffset}, value, littleEndian);
|
|
450
|
+
}`;
|
|
451
|
+
}
|
|
452
|
+
if (field.kind !== "scalar") {
|
|
453
|
+
return [];
|
|
454
|
+
}
|
|
455
|
+
const getterMethod = scalarGetterMethod(field.scalar);
|
|
456
|
+
const setterMethod = scalarSetterMethod(field.scalar);
|
|
457
|
+
const typeName = scalarTsType(field.scalar);
|
|
458
|
+
const littleEndianDefault = toLittleEndianLiteral(layout);
|
|
459
|
+
const endianArg = field.byteLength === 1 || field.scalar === "bool" ? "" : ", littleEndian";
|
|
460
|
+
const getterBody = field.scalar === "bool"
|
|
461
|
+
? ` return view.${getterMethod}(baseOffset + ${field.offset}) !== 0;`
|
|
462
|
+
: ` return view.${getterMethod}(baseOffset + ${field.offset}${endianArg});`;
|
|
463
|
+
const setterBody = field.scalar === "bool"
|
|
464
|
+
? ` view.${setterMethod}(baseOffset + ${field.offset}, value ? 1 : 0);`
|
|
465
|
+
: ` view.${setterMethod}(baseOffset + ${field.offset}, value${endianArg});`;
|
|
466
|
+
const indexOffset = `index * ${layout.byteLength} + ${field.offset}`;
|
|
467
|
+
const indexGetterBody = field.scalar === "bool"
|
|
468
|
+
? ` return view.${getterMethod}(${indexOffset}) !== 0;`
|
|
469
|
+
: ` return view.${getterMethod}(${indexOffset}${endianArg});`;
|
|
470
|
+
const indexSetterBody = field.scalar === "bool"
|
|
471
|
+
? ` view.${setterMethod}(${indexOffset}, value ? 1 : 0);`
|
|
472
|
+
: ` view.${setterMethod}(${indexOffset}, value${endianArg});`;
|
|
473
|
+
const pascalName = toPascalCase(field.name);
|
|
474
|
+
return [
|
|
475
|
+
` static get${pascalName}(view: DataView, baseOffset = 0, littleEndian = ${littleEndianDefault}): ${typeName} {`,
|
|
476
|
+
getterBody,
|
|
477
|
+
" }",
|
|
478
|
+
` static set${pascalName}(view: DataView, value: ${typeName}, baseOffset = 0, littleEndian = ${littleEndianDefault}): void {`,
|
|
479
|
+
setterBody,
|
|
480
|
+
" }",
|
|
481
|
+
` static get${pascalName}At(view: DataView, index: number, littleEndian = ${littleEndianDefault}): ${typeName} {`,
|
|
482
|
+
indexGetterBody,
|
|
483
|
+
" }",
|
|
484
|
+
` static set${pascalName}At(view: DataView, value: ${typeName}, index: number, littleEndian = ${littleEndianDefault}): void {`,
|
|
485
|
+
indexSetterBody,
|
|
486
|
+
" }",
|
|
487
|
+
...emitScalarSumKernel(layout, field, getterMethod, littleEndianDefault, pascalName),
|
|
488
|
+
];
|
|
489
|
+
}
|
|
490
|
+
function emitScalarSumKernel(layout, field, getterMethod, littleEndianDefault, pascalName) {
|
|
491
|
+
if (!isNumberSumScalar(field.scalar)) {
|
|
492
|
+
return [];
|
|
493
|
+
}
|
|
494
|
+
const endianArg = field.byteLength === 1 ? "" : ", littleEndian";
|
|
495
|
+
return method `
|
|
496
|
+
static sum${pascalName}(view: DataView, count: number, baseOffset = 0, littleEndian = ${littleEndianDefault}): number {
|
|
497
|
+
if (!Number.isInteger(count) || count < 0) {
|
|
498
|
+
throw new RangeError(\`Invalid record count: \${count}\`);
|
|
499
|
+
}
|
|
500
|
+
if (!Number.isFinite(baseOffset) || !Number.isInteger(baseOffset) || baseOffset < 0) {
|
|
501
|
+
throw new RangeError(\`Invalid base offset: \${baseOffset}\`);
|
|
502
|
+
}
|
|
503
|
+
if (count === 0) {
|
|
504
|
+
return 0;
|
|
505
|
+
}
|
|
506
|
+
const start = baseOffset + ${field.offset};
|
|
507
|
+
const limit = start + count * ${layout.byteLength};
|
|
508
|
+
const lastByte = start + (count - 1) * ${layout.byteLength} + ${field.byteLength};
|
|
509
|
+
if (lastByte > view.byteLength) {
|
|
510
|
+
throw new RangeError(\`scan range exceeds DataView length \${view.byteLength}\`);
|
|
511
|
+
}
|
|
512
|
+
let sum = 0;
|
|
513
|
+
for (let offset = start; offset < limit; offset += ${layout.byteLength}) {
|
|
514
|
+
sum += view.${getterMethod}(offset${endianArg});
|
|
515
|
+
}
|
|
516
|
+
return sum;
|
|
517
|
+
}`;
|
|
518
|
+
}
|
|
519
|
+
function isNumberSumScalar(kind) {
|
|
520
|
+
return kind !== "i64" && kind !== "u64" && kind !== "bool";
|
|
521
|
+
}
|
|
522
|
+
function emitField(layout, field, options) {
|
|
523
|
+
switch (field.kind) {
|
|
524
|
+
case "scalar": {
|
|
525
|
+
const getterMethod = scalarGetterMethod(field.scalar);
|
|
526
|
+
const setterMethod = scalarSetterMethod(field.scalar);
|
|
527
|
+
const typeName = scalarTsType(field.scalar);
|
|
528
|
+
const getterArgs = field.byteLength === 1 || field.scalar === "bool" ? "" : ", this.littleEndian";
|
|
529
|
+
const instanceOffset = options.optimizeCursorOffsets
|
|
530
|
+
? `this.$${field.name}Offset`
|
|
531
|
+
: `this.baseOffset + ${field.offset}`;
|
|
532
|
+
const getterBody = field.scalar === "bool"
|
|
533
|
+
? `return this.view.${getterMethod}(${instanceOffset}) !== 0;`
|
|
534
|
+
: `return this.view.${getterMethod}(${instanceOffset}${getterArgs});`;
|
|
535
|
+
const setterBody = field.scalar === "bool"
|
|
536
|
+
? `this.view.${setterMethod}(${instanceOffset}, value ? 1 : 0);`
|
|
537
|
+
: `this.view.${setterMethod}(${instanceOffset}, value${getterArgs});`;
|
|
538
|
+
return method `
|
|
539
|
+
get ${field.name}(): ${typeName} {
|
|
540
|
+
${getterBody}
|
|
541
|
+
}
|
|
542
|
+
set ${field.name}(value: ${typeName}) {
|
|
543
|
+
${setterBody}
|
|
544
|
+
}`;
|
|
545
|
+
}
|
|
546
|
+
case "fixed-bytes":
|
|
547
|
+
return method `
|
|
548
|
+
${field.name}Bytes(): Uint8Array {
|
|
549
|
+
return fixedBytesView(this.backingBuffer(), this.backingOffset(${field.offset}), ${field.byteLength});
|
|
550
|
+
}`;
|
|
551
|
+
case "fixed-string":
|
|
552
|
+
return method `
|
|
553
|
+
${field.name}Text(): string {
|
|
554
|
+
return decodeFixedText(this.backingBuffer(), this.backingOffset(${field.offset}), ${field.byteLength}, ${encodingLiteral(field.encoding)});
|
|
555
|
+
}
|
|
556
|
+
${field.name}Bytes(): Uint8Array {
|
|
557
|
+
return fixedBytesView(this.backingBuffer(), this.backingOffset(${field.offset}), ${field.byteLength});
|
|
558
|
+
}`;
|
|
559
|
+
case "dynamic-string":
|
|
560
|
+
return method `
|
|
561
|
+
${field.name}View(): Utf8SpanView {
|
|
562
|
+
return new Utf8SpanView(this.view, ${field.offset}, this.baseOffset, this.littleEndian, ${encodingLiteral(field.encoding)});
|
|
563
|
+
}`;
|
|
564
|
+
case "dynamic-bytes":
|
|
565
|
+
return method `
|
|
566
|
+
${field.name}View(): BytesSpanView {
|
|
567
|
+
return new BytesSpanView(this.view, ${field.offset}, this.baseOffset, this.littleEndian);
|
|
568
|
+
}
|
|
569
|
+
${field.name}Bytes(): Uint8Array {
|
|
570
|
+
return this.${field.name}View().bytes();
|
|
571
|
+
}`;
|
|
572
|
+
case "struct":
|
|
573
|
+
return method `
|
|
574
|
+
${field.name}View(): ${field.typeName}View {
|
|
575
|
+
return new ${field.typeName}View(this.view, this.absoluteOffset(${field.offset}), this.littleEndian);
|
|
576
|
+
}`;
|
|
577
|
+
case "pointer": {
|
|
578
|
+
const pascalName = toPascalCase(field.name);
|
|
579
|
+
return method `
|
|
580
|
+
get raw${pascalName}RelativeOffset(): number {
|
|
581
|
+
return this.view.getUint32(this.baseOffset + ${field.offset}, this.littleEndian);
|
|
582
|
+
}
|
|
583
|
+
get ${field.name}RelativeOffset(): number | null {
|
|
584
|
+
const rawValue = this.raw${pascalName}RelativeOffset;
|
|
585
|
+
if (rawValue === 0xffffffff) {
|
|
586
|
+
return null;
|
|
587
|
+
}
|
|
588
|
+
return this.view.getInt32(this.baseOffset + ${field.offset}, this.littleEndian);
|
|
589
|
+
}
|
|
590
|
+
set ${field.name}RelativeOffset(value: number | null) {
|
|
591
|
+
if (value === null) {
|
|
592
|
+
this.view.setUint32(this.baseOffset + ${field.offset}, 0xffffffff, this.littleEndian);
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
if (!Number.isInteger(value) || value < -0x80000000 || value > 0x7fffffff || value === -1) {
|
|
596
|
+
throw new RangeError(\`pointer32 target offset must encode to signed i32 except -1: \${value}\`);
|
|
597
|
+
}
|
|
598
|
+
this.view.setInt32(this.baseOffset + ${field.offset}, value, this.littleEndian);
|
|
599
|
+
}
|
|
600
|
+
get unchecked${pascalName}TargetOffset(): number | null {
|
|
601
|
+
const relativeOffset = this.${field.name}RelativeOffset;
|
|
602
|
+
if (relativeOffset === null) {
|
|
603
|
+
return null;
|
|
604
|
+
}
|
|
605
|
+
return this.baseOffset + ${field.offset} + relativeOffset;
|
|
606
|
+
}
|
|
607
|
+
get ${field.name}TargetOffset(): number | null {
|
|
608
|
+
const targetOffset = this.unchecked${pascalName}TargetOffset;
|
|
609
|
+
if (targetOffset === null) {
|
|
610
|
+
return null;
|
|
611
|
+
}
|
|
612
|
+
${layout.name}View.assertPointerTargetRange(this.view, targetOffset, ${field.targetTypeName}View.byteLength);
|
|
613
|
+
return targetOffset;
|
|
614
|
+
}
|
|
615
|
+
set unchecked${pascalName}TargetOffset(targetOffset: number | null) {
|
|
616
|
+
if (targetOffset === null) {
|
|
617
|
+
this.${field.name}RelativeOffset = null;
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
const relativeOffset = targetOffset - (this.baseOffset + ${field.offset});
|
|
621
|
+
this.${field.name}RelativeOffset = relativeOffset;
|
|
622
|
+
}
|
|
623
|
+
set ${field.name}TargetOffset(targetOffset: number | null) {
|
|
624
|
+
if (targetOffset !== null) {
|
|
625
|
+
${layout.name}View.assertPointerTargetRange(this.view, targetOffset, ${field.targetTypeName}View.byteLength);
|
|
626
|
+
}
|
|
627
|
+
this.unchecked${pascalName}TargetOffset = targetOffset;
|
|
628
|
+
}
|
|
629
|
+
${field.name}View(): ${field.targetTypeName}View | null {
|
|
630
|
+
const targetOffset = this.${field.name}TargetOffset;
|
|
631
|
+
if (targetOffset === null) {
|
|
632
|
+
return null;
|
|
633
|
+
}
|
|
634
|
+
const target = new ${field.targetTypeName}View(this.view, 0, this.littleEndian);
|
|
635
|
+
target.moveToOffset(targetOffset, ${field.targetTypeName}View.byteLength);
|
|
636
|
+
return target;
|
|
637
|
+
}
|
|
638
|
+
${field.name}Into(out: ${field.targetTypeName}View): boolean {
|
|
639
|
+
const targetOffset = this.${field.name}TargetOffset;
|
|
640
|
+
if (targetOffset === null) {
|
|
641
|
+
return false;
|
|
642
|
+
}
|
|
643
|
+
out.moveToOffset(targetOffset, ${field.targetTypeName}View.byteLength);
|
|
644
|
+
return true;
|
|
645
|
+
}`;
|
|
646
|
+
}
|
|
647
|
+
case "fixed-array":
|
|
648
|
+
return emitFixedArrayFieldAccessor(field, encodingLiteral);
|
|
649
|
+
case "vector":
|
|
650
|
+
switch (field.element.kind) {
|
|
651
|
+
case "scalar":
|
|
652
|
+
return method `
|
|
653
|
+
${field.name}View(): ScalarVectorView<${scalarTsType(field.element.scalar)}> {
|
|
654
|
+
return new ScalarVectorView(this.view, ${field.offset}, "${field.element.scalar}", this.baseOffset, this.littleEndian);
|
|
655
|
+
}`;
|
|
656
|
+
case "dynamic-string":
|
|
657
|
+
return method `
|
|
658
|
+
${field.name}View(): Utf8VectorView {
|
|
659
|
+
return new Utf8VectorView(this.view, ${field.offset}, this.baseOffset, this.littleEndian, ${encodingLiteral(field.element.encoding)});
|
|
660
|
+
}`;
|
|
661
|
+
case "dynamic-bytes":
|
|
662
|
+
return method `
|
|
663
|
+
${field.name}View(): BytesVectorView {
|
|
664
|
+
return new BytesVectorView(this.view, ${field.offset}, this.baseOffset, this.littleEndian);
|
|
665
|
+
}`;
|
|
666
|
+
case "fixed-bytes":
|
|
667
|
+
return method `
|
|
668
|
+
${field.name}View(): FixedBytesVectorView {
|
|
669
|
+
return new FixedBytesVectorView(this.view, ${field.offset}, ${field.element.byteLength}, this.baseOffset, this.littleEndian);
|
|
670
|
+
}`;
|
|
671
|
+
case "fixed-string":
|
|
672
|
+
return method `
|
|
673
|
+
${field.name}View(): FixedStringVectorView {
|
|
674
|
+
return new FixedStringVectorView(this.view, ${field.offset}, ${field.element.byteLength}, this.baseOffset, this.littleEndian, ${encodingLiteral(field.element.encoding)});
|
|
675
|
+
}`;
|
|
676
|
+
case "struct":
|
|
677
|
+
return method `
|
|
678
|
+
${field.name}View(): StructVectorView<${field.element.typeName}View> {
|
|
679
|
+
return new StructVectorView(this.view, ${field.offset}, ${field.element.byteLength}, (view, baseOffset, littleEndian) => new ${field.element.typeName}View(view, baseOffset, littleEndian), this.baseOffset, this.littleEndian);
|
|
680
|
+
}`;
|
|
681
|
+
case "pointer":
|
|
682
|
+
return method `
|
|
683
|
+
${field.name}View(): PointerVectorView<${field.element.targetTypeName}View> {
|
|
684
|
+
return new PointerVectorView(this.view, ${field.offset}, ${field.element.targetTypeName}View.byteLength, (view, baseOffset, littleEndian) => new ${field.element.targetTypeName}View(view, baseOffset, littleEndian), this.baseOffset, this.littleEndian);
|
|
685
|
+
}`;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
function toPascalCase(name) {
|
|
690
|
+
return name.slice(0, 1).toUpperCase() + name.slice(1);
|
|
691
|
+
}
|
|
692
|
+
function toLittleEndianLiteral(layout) {
|
|
693
|
+
return layout.endianness === "little" ? "true" : "false";
|
|
694
|
+
}
|
|
695
|
+
function encodingLiteral(encoding) {
|
|
696
|
+
return encoding === "ascii" ? "\"ascii\"" : "\"utf8\"";
|
|
697
|
+
}
|
|
698
|
+
function hasTailWriterFields(layout, layoutMap) {
|
|
699
|
+
return layout.fields.some((field) => isTailWriterField(field, layoutMap));
|
|
700
|
+
}
|
|
701
|
+
function isTailWriterField(field, layoutMap) {
|
|
702
|
+
switch (field.kind) {
|
|
703
|
+
case "dynamic-string":
|
|
704
|
+
case "dynamic-bytes":
|
|
705
|
+
return true;
|
|
706
|
+
case "vector":
|
|
707
|
+
return (field.element.kind === "scalar" ||
|
|
708
|
+
field.element.kind === "fixed-bytes" ||
|
|
709
|
+
field.element.kind === "fixed-string" ||
|
|
710
|
+
field.element.kind === "dynamic-string" ||
|
|
711
|
+
field.element.kind === "dynamic-bytes" ||
|
|
712
|
+
field.element.kind === "pointer" ||
|
|
713
|
+
canWriteStructVectorElement(field.element, layoutMap));
|
|
714
|
+
default:
|
|
715
|
+
return false;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
function canEmitObjectWriter(layout, layoutMap) {
|
|
719
|
+
return layout.fields.every((field) => canWriteObjectField(field, layoutMap));
|
|
720
|
+
}
|
|
721
|
+
function canWriteObjectField(field, layoutMap) {
|
|
722
|
+
switch (field.kind) {
|
|
723
|
+
case "scalar":
|
|
724
|
+
case "fixed-bytes":
|
|
725
|
+
case "fixed-string":
|
|
726
|
+
case "dynamic-string":
|
|
727
|
+
case "dynamic-bytes":
|
|
728
|
+
case "struct":
|
|
729
|
+
case "pointer":
|
|
730
|
+
return true;
|
|
731
|
+
case "fixed-array":
|
|
732
|
+
return (field.element.kind !== "struct" ||
|
|
733
|
+
canWriteFixedArrayStructElement(field.element, layoutMap, hasTailWriterFields));
|
|
734
|
+
case "vector":
|
|
735
|
+
return (field.element.kind !== "struct" ||
|
|
736
|
+
canWriteStructVectorElement(field.element, layoutMap));
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
function canWriteStructVectorElement(element, layoutMap) {
|
|
740
|
+
if (element.kind !== "struct") {
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
743
|
+
const elementLayout = layoutMap.get(element.typeName);
|
|
744
|
+
return elementLayout !== undefined && !hasTailWriterFields(elementLayout, layoutMap);
|
|
745
|
+
}
|
|
746
|
+
//# sourceMappingURL=emitter.js.map
|