@naeemo/capnp 0.1.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/LICENSE +21 -0
- package/README.md +103 -0
- package/README.zh.md +83 -0
- package/dist/cli.js +394 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +765 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +747 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,765 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
//#region src/core/pointer.ts
|
|
4
|
+
/**
|
|
5
|
+
* Cap'n Proto 指针编解码
|
|
6
|
+
* 纯 TypeScript 实现
|
|
7
|
+
*/
|
|
8
|
+
let PointerTag = /* @__PURE__ */ function(PointerTag) {
|
|
9
|
+
PointerTag[PointerTag["STRUCT"] = 0] = "STRUCT";
|
|
10
|
+
PointerTag[PointerTag["LIST"] = 1] = "LIST";
|
|
11
|
+
PointerTag[PointerTag["FAR"] = 2] = "FAR";
|
|
12
|
+
PointerTag[PointerTag["OTHER"] = 3] = "OTHER";
|
|
13
|
+
return PointerTag;
|
|
14
|
+
}({});
|
|
15
|
+
let ElementSize = /* @__PURE__ */ function(ElementSize) {
|
|
16
|
+
ElementSize[ElementSize["VOID"] = 0] = "VOID";
|
|
17
|
+
ElementSize[ElementSize["BIT"] = 1] = "BIT";
|
|
18
|
+
ElementSize[ElementSize["BYTE"] = 2] = "BYTE";
|
|
19
|
+
ElementSize[ElementSize["TWO_BYTES"] = 3] = "TWO_BYTES";
|
|
20
|
+
ElementSize[ElementSize["FOUR_BYTES"] = 4] = "FOUR_BYTES";
|
|
21
|
+
ElementSize[ElementSize["EIGHT_BYTES"] = 5] = "EIGHT_BYTES";
|
|
22
|
+
ElementSize[ElementSize["POINTER"] = 6] = "POINTER";
|
|
23
|
+
ElementSize[ElementSize["COMPOSITE"] = 7] = "COMPOSITE";
|
|
24
|
+
return ElementSize;
|
|
25
|
+
}({});
|
|
26
|
+
/**
|
|
27
|
+
* 解码指针(64位)
|
|
28
|
+
*/
|
|
29
|
+
function decodePointer(ptr) {
|
|
30
|
+
const tag = Number(ptr & BigInt(3));
|
|
31
|
+
switch (tag) {
|
|
32
|
+
case PointerTag.STRUCT: {
|
|
33
|
+
const offset = Number(ptr >> BigInt(2)) & 1073741823;
|
|
34
|
+
return {
|
|
35
|
+
tag,
|
|
36
|
+
offset: offset >= 536870912 ? offset - 1073741824 : offset,
|
|
37
|
+
dataWords: Number(ptr >> BigInt(32) & BigInt(65535)),
|
|
38
|
+
pointerCount: Number(ptr >> BigInt(48) & BigInt(65535))
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
case PointerTag.LIST: {
|
|
42
|
+
const offset = Number(ptr >> BigInt(2)) & 1073741823;
|
|
43
|
+
return {
|
|
44
|
+
tag,
|
|
45
|
+
offset: offset >= 536870912 ? offset - 1073741824 : offset,
|
|
46
|
+
elementSize: Number(ptr >> BigInt(32) & BigInt(7)),
|
|
47
|
+
elementCount: Number(ptr >> BigInt(35) & BigInt(536870911))
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
case PointerTag.FAR: {
|
|
51
|
+
const doubleFar = Boolean(ptr >> BigInt(2) & BigInt(1));
|
|
52
|
+
const targetOffset = Number(ptr >> BigInt(3) & BigInt(536870911));
|
|
53
|
+
return {
|
|
54
|
+
tag,
|
|
55
|
+
doubleFar,
|
|
56
|
+
targetSegment: Number(ptr >> BigInt(32) & BigInt(4294967295)),
|
|
57
|
+
targetOffset
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
default: return { tag: PointerTag.OTHER };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 编码 Struct 指针
|
|
65
|
+
*/
|
|
66
|
+
function encodeStructPointer(offset, dataWords, pointerCount) {
|
|
67
|
+
return (BigInt(offset < 0 ? offset + 1073741824 : offset) & BigInt(1073741823)) << BigInt(2) | BigInt(dataWords) << BigInt(32) | BigInt(pointerCount) << BigInt(48);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 编码 List 指针
|
|
71
|
+
*/
|
|
72
|
+
function encodeListPointer(offset, elementSize, elementCount) {
|
|
73
|
+
return (BigInt(offset < 0 ? offset + 1073741824 : offset) & BigInt(1073741823)) << BigInt(2) | BigInt(1) | BigInt(elementSize) << BigInt(32) | BigInt(elementCount) << BigInt(35);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/core/segment.ts
|
|
78
|
+
/**
|
|
79
|
+
* Cap'n Proto Segment 管理
|
|
80
|
+
* 纯 TypeScript 实现
|
|
81
|
+
*/
|
|
82
|
+
const WORD_SIZE = 8;
|
|
83
|
+
var Segment = class Segment {
|
|
84
|
+
buffer;
|
|
85
|
+
view;
|
|
86
|
+
_size;
|
|
87
|
+
constructor(initialCapacity = 1024) {
|
|
88
|
+
this.buffer = new ArrayBuffer(initialCapacity);
|
|
89
|
+
this.view = new DataView(this.buffer);
|
|
90
|
+
this._size = 0;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 从现有 buffer 创建(用于读取)
|
|
94
|
+
*/
|
|
95
|
+
static fromBuffer(buffer) {
|
|
96
|
+
const seg = new Segment(0);
|
|
97
|
+
seg.buffer = buffer;
|
|
98
|
+
seg.view = new DataView(buffer);
|
|
99
|
+
seg._size = buffer.byteLength;
|
|
100
|
+
return seg;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 确保容量足够
|
|
104
|
+
*/
|
|
105
|
+
ensureCapacity(minBytes) {
|
|
106
|
+
if (this.buffer.byteLength >= minBytes) return;
|
|
107
|
+
let newCapacity = this.buffer.byteLength * 2;
|
|
108
|
+
while (newCapacity < minBytes) newCapacity *= 2;
|
|
109
|
+
const newBuffer = new ArrayBuffer(newCapacity);
|
|
110
|
+
new Uint8Array(newBuffer).set(new Uint8Array(this.buffer, 0, this._size));
|
|
111
|
+
this.buffer = newBuffer;
|
|
112
|
+
this.view = new DataView(newBuffer);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 分配空间,返回字偏移
|
|
116
|
+
*/
|
|
117
|
+
allocate(words) {
|
|
118
|
+
const bytes = words * WORD_SIZE;
|
|
119
|
+
const offset = this._size;
|
|
120
|
+
this.ensureCapacity(offset + bytes);
|
|
121
|
+
this._size = offset + bytes;
|
|
122
|
+
return offset / WORD_SIZE;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 获取字(64位)
|
|
126
|
+
*/
|
|
127
|
+
getWord(wordOffset) {
|
|
128
|
+
const byteOffset = wordOffset * WORD_SIZE;
|
|
129
|
+
const low = BigInt(this.view.getUint32(byteOffset, true));
|
|
130
|
+
return BigInt(this.view.getUint32(byteOffset + 4, true)) << BigInt(32) | low;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 设置字(64位)
|
|
134
|
+
*/
|
|
135
|
+
setWord(wordOffset, value) {
|
|
136
|
+
const byteOffset = wordOffset * WORD_SIZE;
|
|
137
|
+
this.view.setUint32(byteOffset, Number(value & BigInt(4294967295)), true);
|
|
138
|
+
this.view.setUint32(byteOffset + 4, Number(value >> BigInt(32)), true);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 获取原始 buffer(只读到 _size)
|
|
142
|
+
*/
|
|
143
|
+
asUint8Array() {
|
|
144
|
+
return new Uint8Array(this.buffer, 0, this._size);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* 获取字数量
|
|
148
|
+
*/
|
|
149
|
+
get wordCount() {
|
|
150
|
+
return this._size / WORD_SIZE;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* 获取字节数量
|
|
154
|
+
*/
|
|
155
|
+
get byteLength() {
|
|
156
|
+
return this._size;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* 获取 DataView
|
|
160
|
+
*/
|
|
161
|
+
get dataView() {
|
|
162
|
+
return this.view;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region src/core/message-builder.ts
|
|
168
|
+
/**
|
|
169
|
+
* Cap'n Proto MessageBuilder
|
|
170
|
+
* 纯 TypeScript 实现
|
|
171
|
+
*/
|
|
172
|
+
var MessageBuilder = class {
|
|
173
|
+
segment;
|
|
174
|
+
rootSet = false;
|
|
175
|
+
constructor() {
|
|
176
|
+
this.segment = new Segment(1024);
|
|
177
|
+
this.segment.allocate(1);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* 初始化根结构
|
|
181
|
+
*/
|
|
182
|
+
initRoot(dataWords, pointerCount) {
|
|
183
|
+
if (this.rootSet) throw new Error("Root already initialized");
|
|
184
|
+
const size = dataWords + pointerCount;
|
|
185
|
+
const structOffset = this.segment.allocate(size);
|
|
186
|
+
const rootPtr = encodeStructPointer(structOffset - 1, dataWords, pointerCount);
|
|
187
|
+
this.segment.setWord(0, rootPtr);
|
|
188
|
+
this.rootSet = true;
|
|
189
|
+
return new StructBuilder(this, 0, structOffset, dataWords, pointerCount);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* 序列化为 ArrayBuffer
|
|
193
|
+
*/
|
|
194
|
+
toArrayBuffer() {
|
|
195
|
+
const segmentData = this.segment.asUint8Array();
|
|
196
|
+
const wordCount = this.segment.wordCount;
|
|
197
|
+
const header = /* @__PURE__ */ new ArrayBuffer(8);
|
|
198
|
+
const headerView = new DataView(header);
|
|
199
|
+
headerView.setUint32(0, 0, true);
|
|
200
|
+
headerView.setUint32(4, wordCount, true);
|
|
201
|
+
const result = new Uint8Array(8 + segmentData.byteLength);
|
|
202
|
+
result.set(new Uint8Array(header), 0);
|
|
203
|
+
result.set(segmentData, 8);
|
|
204
|
+
return result.buffer;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* 获取段(内部使用)
|
|
208
|
+
*/
|
|
209
|
+
getSegment() {
|
|
210
|
+
return this.segment;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
/**
|
|
214
|
+
* 结构构建器
|
|
215
|
+
*/
|
|
216
|
+
var StructBuilder = class StructBuilder {
|
|
217
|
+
constructor(message, segmentIndex, wordOffset, dataWords, pointerCount) {
|
|
218
|
+
this.message = message;
|
|
219
|
+
this.segmentIndex = segmentIndex;
|
|
220
|
+
this.wordOffset = wordOffset;
|
|
221
|
+
this.dataWords = dataWords;
|
|
222
|
+
this.pointerCount = pointerCount;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* 设置 bool 字段
|
|
226
|
+
*/
|
|
227
|
+
setBool(bitOffset, value) {
|
|
228
|
+
const byteOffset = Math.floor(bitOffset / 8);
|
|
229
|
+
const bitInByte = bitOffset % 8;
|
|
230
|
+
const view = this.message.getSegment().dataView;
|
|
231
|
+
const offset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
232
|
+
const current = view.getUint8(offset);
|
|
233
|
+
const newValue = value ? current | 1 << bitInByte : current & ~(1 << bitInByte);
|
|
234
|
+
view.setUint8(offset, newValue);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* 设置 int8 字段
|
|
238
|
+
*/
|
|
239
|
+
setInt8(byteOffset, value) {
|
|
240
|
+
this.message.getSegment().dataView.setInt8(this.wordOffset * WORD_SIZE + byteOffset, value);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* 设置 int16 字段
|
|
244
|
+
*/
|
|
245
|
+
setInt16(byteOffset, value) {
|
|
246
|
+
this.message.getSegment().dataView.setInt16(this.wordOffset * WORD_SIZE + byteOffset, value, true);
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* 设置 int32 字段
|
|
250
|
+
*/
|
|
251
|
+
setInt32(byteOffset, value) {
|
|
252
|
+
this.message.getSegment().dataView.setInt32(this.wordOffset * WORD_SIZE + byteOffset, value, true);
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* 设置 int64 字段
|
|
256
|
+
*/
|
|
257
|
+
setInt64(byteOffset, value) {
|
|
258
|
+
const segment = this.message.getSegment();
|
|
259
|
+
const offset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
260
|
+
segment.dataView.setUint32(offset, Number(value & BigInt(4294967295)), true);
|
|
261
|
+
segment.dataView.setInt32(offset + 4, Number(value >> BigInt(32)), true);
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* 设置 uint8 字段
|
|
265
|
+
*/
|
|
266
|
+
setUint8(byteOffset, value) {
|
|
267
|
+
this.message.getSegment().dataView.setUint8(this.wordOffset * WORD_SIZE + byteOffset, value);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* 设置 uint16 字段
|
|
271
|
+
*/
|
|
272
|
+
setUint16(byteOffset, value) {
|
|
273
|
+
this.message.getSegment().dataView.setUint16(this.wordOffset * WORD_SIZE + byteOffset, value, true);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* 设置 uint32 字段
|
|
277
|
+
*/
|
|
278
|
+
setUint32(byteOffset, value) {
|
|
279
|
+
this.message.getSegment().dataView.setUint32(this.wordOffset * WORD_SIZE + byteOffset, value, true);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* 设置 uint64 字段
|
|
283
|
+
*/
|
|
284
|
+
setUint64(byteOffset, value) {
|
|
285
|
+
const segment = this.message.getSegment();
|
|
286
|
+
const offset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
287
|
+
segment.dataView.setUint32(offset, Number(value & BigInt(4294967295)), true);
|
|
288
|
+
segment.dataView.setUint32(offset + 4, Number(value >> BigInt(32)), true);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* 设置 float32 字段
|
|
292
|
+
*/
|
|
293
|
+
setFloat32(byteOffset, value) {
|
|
294
|
+
this.message.getSegment().dataView.setFloat32(this.wordOffset * WORD_SIZE + byteOffset, value, true);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* 设置 float64 字段
|
|
298
|
+
*/
|
|
299
|
+
setFloat64(byteOffset, value) {
|
|
300
|
+
this.message.getSegment().dataView.setFloat64(this.wordOffset * WORD_SIZE + byteOffset, value, true);
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* 获取 uint16 字段(用于 UnionBuilder 读取 tag)
|
|
304
|
+
*/
|
|
305
|
+
getUint16(byteOffset) {
|
|
306
|
+
return this.message.getSegment().dataView.getUint16(this.wordOffset * WORD_SIZE + byteOffset, true);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* 设置文本字段
|
|
310
|
+
*/
|
|
311
|
+
setText(pointerIndex, value) {
|
|
312
|
+
const ptrOffset = this.wordOffset + this.dataWords + pointerIndex;
|
|
313
|
+
const segment = this.message.getSegment();
|
|
314
|
+
const bytes = new TextEncoder().encode(`${value}\0`);
|
|
315
|
+
const wordCount = Math.ceil(bytes.length / WORD_SIZE);
|
|
316
|
+
const listOffset = segment.allocate(wordCount);
|
|
317
|
+
new Uint8Array(segment.dataView.buffer, listOffset * WORD_SIZE, bytes.length).set(bytes);
|
|
318
|
+
const ptr = encodeListPointer(listOffset - ptrOffset - 1, ElementSize.BYTE, bytes.length);
|
|
319
|
+
segment.setWord(ptrOffset, ptr);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* 初始化嵌套结构
|
|
323
|
+
*/
|
|
324
|
+
initStruct(pointerIndex, dataWords, pointerCount) {
|
|
325
|
+
const ptrOffset = this.wordOffset + this.dataWords + pointerIndex;
|
|
326
|
+
const segment = this.message.getSegment();
|
|
327
|
+
const size = dataWords + pointerCount;
|
|
328
|
+
const structOffset = segment.allocate(size);
|
|
329
|
+
const ptr = encodeStructPointer(structOffset - ptrOffset - 1, dataWords, pointerCount);
|
|
330
|
+
segment.setWord(ptrOffset, ptr);
|
|
331
|
+
return new StructBuilder(this.message, 0, structOffset, dataWords, pointerCount);
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* 初始化列表
|
|
335
|
+
*/
|
|
336
|
+
initList(pointerIndex, elementSize, elementCount, structSize) {
|
|
337
|
+
const ptrOffset = this.wordOffset + this.dataWords + pointerIndex;
|
|
338
|
+
const segment = this.message.getSegment();
|
|
339
|
+
let elementWords = 1;
|
|
340
|
+
if (elementSize === ElementSize.BYTE) elementWords = 1;
|
|
341
|
+
else if (elementSize === ElementSize.TWO_BYTES) elementWords = 1;
|
|
342
|
+
else if (elementSize === ElementSize.FOUR_BYTES) elementWords = 1;
|
|
343
|
+
else if (elementSize === ElementSize.EIGHT_BYTES) elementWords = 1;
|
|
344
|
+
else if (elementSize === ElementSize.COMPOSITE && structSize) elementWords = structSize.dataWords + structSize.pointerCount;
|
|
345
|
+
const totalWords = elementWords * elementCount;
|
|
346
|
+
const listOffset = segment.allocate(totalWords);
|
|
347
|
+
const ptr = encodeListPointer(listOffset - ptrOffset - 1, elementSize, elementCount);
|
|
348
|
+
segment.setWord(ptrOffset, ptr);
|
|
349
|
+
return new ListBuilder(this.message, elementSize, elementCount, structSize, listOffset);
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
//#endregion
|
|
354
|
+
//#region src/core/list.ts
|
|
355
|
+
/**
|
|
356
|
+
* Cap'n Proto List 实现
|
|
357
|
+
* 纯 TypeScript
|
|
358
|
+
*/
|
|
359
|
+
/**
|
|
360
|
+
* ListReader - 读取列表
|
|
361
|
+
*/
|
|
362
|
+
var ListReader = class {
|
|
363
|
+
segment;
|
|
364
|
+
startOffset;
|
|
365
|
+
constructor(message, segmentIndex, elementSize, elementCount, structSize, wordOffset) {
|
|
366
|
+
this.message = message;
|
|
367
|
+
this.elementSize = elementSize;
|
|
368
|
+
this.elementCount = elementCount;
|
|
369
|
+
this.structSize = structSize;
|
|
370
|
+
this.segment = message.getSegment(segmentIndex);
|
|
371
|
+
this.startOffset = wordOffset;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* 列表长度
|
|
375
|
+
*/
|
|
376
|
+
get length() {
|
|
377
|
+
return this.elementCount;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* 获取元素(基础类型)
|
|
381
|
+
*/
|
|
382
|
+
getPrimitive(index) {
|
|
383
|
+
if (index < 0 || index >= this.elementCount) throw new RangeError("Index out of bounds");
|
|
384
|
+
switch (this.elementSize) {
|
|
385
|
+
case ElementSize.BIT: {
|
|
386
|
+
const byteOffset = Math.floor(index / 8);
|
|
387
|
+
const bitInByte = index % 8;
|
|
388
|
+
return (this.segment.dataView.getUint8(this.startOffset * WORD_SIZE + byteOffset) & 1 << bitInByte) !== 0 ? 1 : 0;
|
|
389
|
+
}
|
|
390
|
+
case ElementSize.BYTE: return this.segment.dataView.getUint8(this.startOffset * WORD_SIZE + index);
|
|
391
|
+
case ElementSize.TWO_BYTES: return this.segment.dataView.getUint16(this.startOffset * WORD_SIZE + index * 2, true);
|
|
392
|
+
case ElementSize.FOUR_BYTES: return this.segment.dataView.getUint32(this.startOffset * WORD_SIZE + index * 4, true);
|
|
393
|
+
case ElementSize.EIGHT_BYTES: {
|
|
394
|
+
const offset = this.startOffset * WORD_SIZE + index * 8;
|
|
395
|
+
const low = BigInt(this.segment.dataView.getUint32(offset, true));
|
|
396
|
+
return BigInt(this.segment.dataView.getUint32(offset + 4, true)) << BigInt(32) | low;
|
|
397
|
+
}
|
|
398
|
+
default: throw new Error(`Unsupported element size: ${this.elementSize}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* 获取结构元素
|
|
403
|
+
*/
|
|
404
|
+
getStruct(index) {
|
|
405
|
+
if (!this.structSize) throw new Error("Not a struct list");
|
|
406
|
+
const { dataWords, pointerCount } = this.structSize;
|
|
407
|
+
const size = dataWords + pointerCount;
|
|
408
|
+
const offset = this.startOffset + index * size;
|
|
409
|
+
return new StructReader(this.message, 0, offset, dataWords, pointerCount);
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* 迭代器
|
|
413
|
+
*/
|
|
414
|
+
*[Symbol.iterator]() {
|
|
415
|
+
for (let i = 0; i < this.elementCount; i++) yield this.getPrimitive(i);
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
/**
|
|
419
|
+
* ListBuilder - 构建列表
|
|
420
|
+
*/
|
|
421
|
+
var ListBuilder = class {
|
|
422
|
+
segment;
|
|
423
|
+
startOffset;
|
|
424
|
+
constructor(message, elementSize, elementCount, structSize, wordOffset) {
|
|
425
|
+
this.message = message;
|
|
426
|
+
this.elementSize = elementSize;
|
|
427
|
+
this.elementCount = elementCount;
|
|
428
|
+
this.structSize = structSize;
|
|
429
|
+
this.segment = message.getSegment();
|
|
430
|
+
this.startOffset = wordOffset;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* 列表长度
|
|
434
|
+
*/
|
|
435
|
+
get length() {
|
|
436
|
+
return this.elementCount;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* 设置基础类型元素
|
|
440
|
+
*/
|
|
441
|
+
setPrimitive(index, value) {
|
|
442
|
+
if (index < 0 || index >= this.elementCount) throw new RangeError("Index out of bounds");
|
|
443
|
+
switch (this.elementSize) {
|
|
444
|
+
case ElementSize.BIT: {
|
|
445
|
+
const byteOffset = Math.floor(index / 8);
|
|
446
|
+
const bitInByte = index % 8;
|
|
447
|
+
const offset = this.startOffset * WORD_SIZE + byteOffset;
|
|
448
|
+
const current = this.segment.dataView.getUint8(offset);
|
|
449
|
+
const newValue = value ? current | 1 << bitInByte : current & ~(1 << bitInByte);
|
|
450
|
+
this.segment.dataView.setUint8(offset, newValue);
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
case ElementSize.BYTE:
|
|
454
|
+
this.segment.dataView.setUint8(this.startOffset * WORD_SIZE + index, Number(value));
|
|
455
|
+
break;
|
|
456
|
+
case ElementSize.TWO_BYTES:
|
|
457
|
+
this.segment.dataView.setUint16(this.startOffset * WORD_SIZE + index * 2, Number(value), true);
|
|
458
|
+
break;
|
|
459
|
+
case ElementSize.FOUR_BYTES:
|
|
460
|
+
this.segment.dataView.setUint32(this.startOffset * WORD_SIZE + index * 4, Number(value), true);
|
|
461
|
+
break;
|
|
462
|
+
case ElementSize.EIGHT_BYTES: {
|
|
463
|
+
const offset = this.startOffset * WORD_SIZE + index * 8;
|
|
464
|
+
const bigValue = value;
|
|
465
|
+
this.segment.dataView.setUint32(offset, Number(bigValue & BigInt(4294967295)), true);
|
|
466
|
+
this.segment.dataView.setUint32(offset + 4, Number(bigValue >> BigInt(32)), true);
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
default: throw new Error(`Unsupported element size: ${this.elementSize}`);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* 获取结构元素(用于修改)
|
|
474
|
+
*/
|
|
475
|
+
getStruct(index) {
|
|
476
|
+
if (!this.structSize) throw new Error("Not a struct list");
|
|
477
|
+
const { dataWords, pointerCount } = this.structSize;
|
|
478
|
+
const size = dataWords + pointerCount;
|
|
479
|
+
const offset = this.startOffset + index * size;
|
|
480
|
+
return new StructBuilder(this.message, 0, offset, dataWords, pointerCount);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
//#endregion
|
|
485
|
+
//#region src/core/message-reader.ts
|
|
486
|
+
/**
|
|
487
|
+
* Cap'n Proto MessageReader
|
|
488
|
+
* 纯 TypeScript 实现
|
|
489
|
+
*/
|
|
490
|
+
var MessageReader = class {
|
|
491
|
+
segments;
|
|
492
|
+
constructor(buffer) {
|
|
493
|
+
const uint8Array = buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : buffer;
|
|
494
|
+
this.segments = [];
|
|
495
|
+
if (uint8Array.byteLength < 8) return;
|
|
496
|
+
const view = new DataView(uint8Array.buffer, uint8Array.byteOffset, uint8Array.byteLength);
|
|
497
|
+
const firstWordLow = view.getUint32(0, true);
|
|
498
|
+
const firstWordHigh = view.getUint32(4, true);
|
|
499
|
+
const segmentCount = (firstWordLow & 4294967295) + 1;
|
|
500
|
+
const firstSegmentSize = firstWordHigh;
|
|
501
|
+
let offset = 8;
|
|
502
|
+
const segmentSizes = [firstSegmentSize];
|
|
503
|
+
for (let i = 1; i < segmentCount; i++) {
|
|
504
|
+
if (offset + 4 > uint8Array.byteLength) {
|
|
505
|
+
this.segments = [];
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
segmentSizes.push(view.getUint32(offset, true));
|
|
509
|
+
offset += 4;
|
|
510
|
+
}
|
|
511
|
+
offset = offset + 7 & -8;
|
|
512
|
+
if (offset > uint8Array.byteLength) {
|
|
513
|
+
this.segments = [];
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
this.segments = [];
|
|
517
|
+
for (const size of segmentSizes) {
|
|
518
|
+
if (offset + size * WORD_SIZE > uint8Array.byteLength) break;
|
|
519
|
+
const segmentBuffer = uint8Array.slice(offset, offset + size * WORD_SIZE);
|
|
520
|
+
this.segments.push(Segment.fromBuffer(segmentBuffer.buffer));
|
|
521
|
+
offset += size * WORD_SIZE;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* 获取根结构
|
|
526
|
+
*/
|
|
527
|
+
getRoot(_dataWords, _pointerCount) {
|
|
528
|
+
const segment = this.segments[0];
|
|
529
|
+
const ptr = decodePointer(segment.getWord(0));
|
|
530
|
+
if (ptr.tag !== PointerTag.STRUCT) throw new Error("Root pointer is not a struct");
|
|
531
|
+
const structPtr = ptr;
|
|
532
|
+
const dataOffset = 1 + structPtr.offset;
|
|
533
|
+
return new StructReader(this, 0, dataOffset, structPtr.dataWords, structPtr.pointerCount);
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* 获取段
|
|
537
|
+
*/
|
|
538
|
+
getSegment(index) {
|
|
539
|
+
return this.segments[index];
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* 段数量
|
|
543
|
+
*/
|
|
544
|
+
get segmentCount() {
|
|
545
|
+
return this.segments.length;
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
/**
|
|
549
|
+
* 结构读取器
|
|
550
|
+
*/
|
|
551
|
+
var StructReader = class StructReader {
|
|
552
|
+
constructor(message, segmentIndex, wordOffset, dataWords, pointerCount) {
|
|
553
|
+
this.message = message;
|
|
554
|
+
this.segmentIndex = segmentIndex;
|
|
555
|
+
this.wordOffset = wordOffset;
|
|
556
|
+
this.dataWords = dataWords;
|
|
557
|
+
this.pointerCount = pointerCount;
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* 获取 bool 字段
|
|
561
|
+
*/
|
|
562
|
+
getBool(bitOffset) {
|
|
563
|
+
const byteOffset = Math.floor(bitOffset / 8);
|
|
564
|
+
const bitInByte = bitOffset % 8;
|
|
565
|
+
return (this.message.getSegment(this.segmentIndex).dataView.getUint8(this.wordOffset * WORD_SIZE + byteOffset) & 1 << bitInByte) !== 0;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* 获取 int8 字段
|
|
569
|
+
*/
|
|
570
|
+
getInt8(byteOffset) {
|
|
571
|
+
return this.message.getSegment(this.segmentIndex).dataView.getInt8(this.wordOffset * WORD_SIZE + byteOffset);
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* 获取 int16 字段
|
|
575
|
+
*/
|
|
576
|
+
getInt16(byteOffset) {
|
|
577
|
+
return this.message.getSegment(this.segmentIndex).dataView.getInt16(this.wordOffset * WORD_SIZE + byteOffset, true);
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* 获取 int32 字段
|
|
581
|
+
*/
|
|
582
|
+
getInt32(byteOffset) {
|
|
583
|
+
return this.message.getSegment(this.segmentIndex).dataView.getInt32(this.wordOffset * WORD_SIZE + byteOffset, true);
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* 获取 int64 字段
|
|
587
|
+
*/
|
|
588
|
+
getInt64(byteOffset) {
|
|
589
|
+
const segment = this.message.getSegment(this.segmentIndex);
|
|
590
|
+
const offset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
591
|
+
const low = BigInt(segment.dataView.getUint32(offset, true));
|
|
592
|
+
return BigInt(segment.dataView.getInt32(offset + 4, true)) << BigInt(32) | low;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* 获取 uint8 字段
|
|
596
|
+
*/
|
|
597
|
+
getUint8(byteOffset) {
|
|
598
|
+
return this.message.getSegment(this.segmentIndex).dataView.getUint8(this.wordOffset * WORD_SIZE + byteOffset);
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* 获取 uint16 字段
|
|
602
|
+
*/
|
|
603
|
+
getUint16(byteOffset) {
|
|
604
|
+
return this.message.getSegment(this.segmentIndex).dataView.getUint16(this.wordOffset * WORD_SIZE + byteOffset, true);
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* 获取 uint32 字段
|
|
608
|
+
*/
|
|
609
|
+
getUint32(byteOffset) {
|
|
610
|
+
return this.message.getSegment(this.segmentIndex).dataView.getUint32(this.wordOffset * WORD_SIZE + byteOffset, true);
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* 获取 uint64 字段
|
|
614
|
+
*/
|
|
615
|
+
getUint64(byteOffset) {
|
|
616
|
+
const segment = this.message.getSegment(this.segmentIndex);
|
|
617
|
+
const offset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
618
|
+
const low = BigInt(segment.dataView.getUint32(offset, true));
|
|
619
|
+
return BigInt(segment.dataView.getUint32(offset + 4, true)) << BigInt(32) | low;
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* 获取 float32 字段
|
|
623
|
+
*/
|
|
624
|
+
getFloat32(byteOffset) {
|
|
625
|
+
return this.message.getSegment(this.segmentIndex).dataView.getFloat32(this.wordOffset * WORD_SIZE + byteOffset, true);
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* 获取 float64 字段
|
|
629
|
+
*/
|
|
630
|
+
getFloat64(byteOffset) {
|
|
631
|
+
return this.message.getSegment(this.segmentIndex).dataView.getFloat64(this.wordOffset * WORD_SIZE + byteOffset, true);
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* 获取文本字段
|
|
635
|
+
*/
|
|
636
|
+
getText(pointerIndex) {
|
|
637
|
+
const ptrOffset = this.wordOffset + this.dataWords + pointerIndex;
|
|
638
|
+
const segment = this.message.getSegment(this.segmentIndex);
|
|
639
|
+
const ptrValue = segment.getWord(ptrOffset);
|
|
640
|
+
if (ptrValue === 0n) return "";
|
|
641
|
+
const ptr = decodePointer(ptrValue);
|
|
642
|
+
if (ptr.tag !== PointerTag.LIST) return "";
|
|
643
|
+
const listPtr = ptr;
|
|
644
|
+
const targetOffset = ptrOffset + 1 + listPtr.offset;
|
|
645
|
+
const bytes = new Uint8Array(segment.dataView.buffer, targetOffset * WORD_SIZE, listPtr.elementCount - 1);
|
|
646
|
+
return new TextDecoder().decode(bytes);
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* 获取嵌套结构
|
|
650
|
+
*/
|
|
651
|
+
getStruct(pointerIndex, _dataWords, _pointerCount) {
|
|
652
|
+
const ptrOffset = this.wordOffset + this.dataWords + pointerIndex;
|
|
653
|
+
const ptrValue = this.message.getSegment(this.segmentIndex).getWord(ptrOffset);
|
|
654
|
+
if (ptrValue === 0n) return void 0;
|
|
655
|
+
const ptr = decodePointer(ptrValue);
|
|
656
|
+
if (ptr.tag !== PointerTag.STRUCT) return void 0;
|
|
657
|
+
const structPtr = ptr;
|
|
658
|
+
const targetOffset = ptrOffset + 1 + structPtr.offset;
|
|
659
|
+
return new StructReader(this.message, this.segmentIndex, targetOffset, structPtr.dataWords, structPtr.pointerCount);
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* 获取列表
|
|
663
|
+
*/
|
|
664
|
+
getList(pointerIndex, _elementSize, structSize) {
|
|
665
|
+
const ptrOffset = this.wordOffset + this.dataWords + pointerIndex;
|
|
666
|
+
const ptrValue = this.message.getSegment(this.segmentIndex).getWord(ptrOffset);
|
|
667
|
+
if (ptrValue === 0n) return void 0;
|
|
668
|
+
const ptr = decodePointer(ptrValue);
|
|
669
|
+
if (ptr.tag !== PointerTag.LIST) return void 0;
|
|
670
|
+
const listPtr = ptr;
|
|
671
|
+
const targetOffset = ptrOffset + 1 + listPtr.offset;
|
|
672
|
+
return new ListReader(this.message, this.segmentIndex, listPtr.elementSize, listPtr.elementCount, structSize, targetOffset);
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
//#endregion
|
|
677
|
+
//#region src/core/union.ts
|
|
678
|
+
/**
|
|
679
|
+
* UnionReader - 读取 Union 的 tag 和 variant
|
|
680
|
+
*/
|
|
681
|
+
var UnionReader = class {
|
|
682
|
+
constructor(struct, tagOffset, variants) {
|
|
683
|
+
this.struct = struct;
|
|
684
|
+
this.tagOffset = tagOffset;
|
|
685
|
+
this.variants = variants;
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* 获取当前激活的 variant tag
|
|
689
|
+
*/
|
|
690
|
+
getTag() {
|
|
691
|
+
return this.struct.getUint16(this.tagOffset);
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* 获取当前激活的 variant 名称
|
|
695
|
+
*/
|
|
696
|
+
getVariantName() {
|
|
697
|
+
return this.variants.get(this.getTag());
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* 检查是否是某个 variant
|
|
701
|
+
*/
|
|
702
|
+
is(variantTag) {
|
|
703
|
+
return this.getTag() === variantTag;
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
/**
|
|
707
|
+
* UnionBuilder - 设置 Union 的 tag 和 variant
|
|
708
|
+
*/
|
|
709
|
+
var UnionBuilder = class {
|
|
710
|
+
constructor(struct, tagOffset) {
|
|
711
|
+
this.struct = struct;
|
|
712
|
+
this.tagOffset = tagOffset;
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* 获取当前 tag
|
|
716
|
+
*/
|
|
717
|
+
getTag() {
|
|
718
|
+
return this.struct.getUint16(this.tagOffset);
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* 设置 tag
|
|
722
|
+
*/
|
|
723
|
+
setTag(tag) {
|
|
724
|
+
this.struct.setUint16(this.tagOffset, tag);
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* 初始化某个 variant(自动设置 tag)
|
|
728
|
+
*/
|
|
729
|
+
initVariant(tag, initFn) {
|
|
730
|
+
this.setTag(tag);
|
|
731
|
+
initFn();
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
/**
|
|
735
|
+
* 创建 UnionReader 的工厂函数
|
|
736
|
+
*/
|
|
737
|
+
function createUnionReader(struct, tagOffset, variants) {
|
|
738
|
+
return new UnionReader(struct, tagOffset, new Map(Object.entries(variants).map(([k, v]) => [Number(k), v])));
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* 创建 UnionBuilder 的工厂函数
|
|
742
|
+
*/
|
|
743
|
+
function createUnionBuilder(struct, tagOffset) {
|
|
744
|
+
return new UnionBuilder(struct, tagOffset);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
//#endregion
|
|
748
|
+
exports.ElementSize = ElementSize;
|
|
749
|
+
exports.ListBuilder = ListBuilder;
|
|
750
|
+
exports.ListReader = ListReader;
|
|
751
|
+
exports.MessageBuilder = MessageBuilder;
|
|
752
|
+
exports.MessageReader = MessageReader;
|
|
753
|
+
exports.PointerTag = PointerTag;
|
|
754
|
+
exports.Segment = Segment;
|
|
755
|
+
exports.StructBuilder = StructBuilder;
|
|
756
|
+
exports.StructReader = StructReader;
|
|
757
|
+
exports.UnionBuilder = UnionBuilder;
|
|
758
|
+
exports.UnionReader = UnionReader;
|
|
759
|
+
exports.WORD_SIZE = WORD_SIZE;
|
|
760
|
+
exports.createUnionBuilder = createUnionBuilder;
|
|
761
|
+
exports.createUnionReader = createUnionReader;
|
|
762
|
+
exports.decodePointer = decodePointer;
|
|
763
|
+
exports.encodeListPointer = encodeListPointer;
|
|
764
|
+
exports.encodeStructPointer = encodeStructPointer;
|
|
765
|
+
//# sourceMappingURL=index.cjs.map
|