diff --git a/.gitignore b/.gitignore index b711316..2ab2c9e 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ build/Release # Dependency directories node_modules jspm_packages +package-lock.json # Optional npm cache directory .npm diff --git a/.vscode/launch.json b/.vscode/launch.json index e368464..e3b2785 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,18 +11,38 @@ "type": "node" }, { - "cwd": "${workspaceRoot}", + "env": { + "NODE_ENV": "development", + "TAP_TIMEOUT": "0" + }, + "name": "Debug all", + "type": "node", + "request": "launch", + "cwd": "${workspaceFolder}", + "runtimeExecutable": "npm", + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "runtimeArgs": ["run", "test:watch"], + "outFiles": ["${workspaceFolder}/**/*.js", "!**/node_modules/**"], + "skipFiles": ["/**", "**/node_modules/**"] + }, + { "env": { "DEBUG": "capnp:*", - "NODE_ENV": "development" + "NODE_ENV": "development", + "TAP_TIMEOUT": "0" }, - "name": "Debug (Test)", - "preLaunchTask": "build", - "program": "${file}", + "name": "Debug current test", + "type": "node", "request": "launch", - "sourceMaps": true, - "stopOnEntry": false, - "type": "node" + // "preLaunchTask": "build", + "cwd": "${workspaceFolder}", + "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/tap", + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "runtimeArgs": ["--no-coverage", "--ts", "-c", "-Rspec", "${file}"], + "outFiles": ["${workspaceFolder}/**/*.js", "!**/node_modules/**"], + "skipFiles": ["/**", "**/node_modules/**"] } ] } diff --git a/Makefile b/Makefile index 2005b3f..aa368b6 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ SHELL := bash # environment variables CAPNP_BIN := capnp -TAP_FLAGS ?= -j8 --no-coverage --ts -Rterse -c +TAP_FLAGS ?= --no-coverage --ts -c TAP_TS := 1 TSC_FLAGS ?= STANDARD_FLAGS ?= --dry-run diff --git a/package-lock.json b/package-lock.json index be0d0a8..c6252dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "@types/benchmark": "^2.1.0", "@types/debug": "^4.1.5", "@types/mkdirp": "^1.0.1", - "@types/node": "^15.3.1", + "@types/node": "^17.0.8", "@types/tap": "^15.0.1", "@typescript-eslint/eslint-plugin": "^4.24.0", "@typescript-eslint/eslint-plugin-tslint": "^4.24.0", @@ -775,9 +775,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "15.14.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.14.8.tgz", - "integrity": "sha512-+ZjmmoGV7WBwhzNh/GkwehB7uyXn9HFwzQUfj9pbyR8eFAq20Qguoh93sPbWzzhsbhTme6YE92/iJ54Z0WRH7A==", + "version": "17.0.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.8.tgz", + "integrity": "sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg==", "dev": true }, "node_modules/@types/normalize-package-data": { @@ -10784,9 +10784,9 @@ "dev": true }, "@types/node": { - "version": "15.14.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.14.8.tgz", - "integrity": "sha512-+ZjmmoGV7WBwhzNh/GkwehB7uyXn9HFwzQUfj9pbyR8eFAq20Qguoh93sPbWzzhsbhTme6YE92/iJ54Z0WRH7A==", + "version": "17.0.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.8.tgz", + "integrity": "sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg==", "dev": true }, "@types/normalize-package-data": { diff --git a/package.json b/package.json index 165cc98..b688f97 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "@types/benchmark": "^2.1.0", "@types/debug": "^4.1.5", "@types/mkdirp": "^1.0.1", - "@types/node": "^15.3.1", + "@types/node": "^17.0.8", "@types/tap": "^15.0.1", "@typescript-eslint/eslint-plugin": "^4.24.0", "@typescript-eslint/eslint-plugin-tslint": "^4.24.0", @@ -69,6 +69,7 @@ "coverage": "make coverage", "coverage:watch": "npm run nodemon make coverage", "lint": "make lint", + "lint:watch": "npm run nodemon make lint", "nodemon": "nodemon -w ./packages/capnp-ts/src -w ./packages/capnpc-ts/src -w ./packages/capnp-ts/test -w ./packages/capnpc-ts/test -w ./packages/capnp-ts-test/test -w ./**/tsconfig.json -i './packages/capnp-ts/src/std' -i './packages/**/*.d.ts' -i './packages/**/*.capnp.ts' -e .ts -x ", "prepare": "husky install", "prepublishOnly": "make build", diff --git a/packages/capnp-ts-test/test/integration/hash-factory.capnp b/packages/capnp-ts-test/test/integration/hash-factory.capnp new file mode 100644 index 0000000..8582b44 --- /dev/null +++ b/packages/capnp-ts-test/test/integration/hash-factory.capnp @@ -0,0 +1,10 @@ +@0xbba26a2caa3411e8; + +interface HashFactory { + newSha1 @0 () -> (hash :Hash); +} + +interface Hash { + write @0 (data :Data) -> (); + sum @1 () -> (hash :Data); +} diff --git a/packages/capnp-ts-test/test/integration/hash-factory.spec.ts b/packages/capnp-ts-test/test/integration/hash-factory.spec.ts new file mode 100644 index 0000000..af91b1a --- /dev/null +++ b/packages/capnp-ts-test/test/integration/hash-factory.spec.ts @@ -0,0 +1,52 @@ +import { Hash, HashFactory } from "./hash-factory.capnp.js"; +import { createHash } from "crypto"; +import tap from "tap"; +import { TestNetwork } from "capnp-ts/src/rpc/transport"; +import { bufferToHex, encodeUtf8 } from "../../../capnp-ts/src/util.js"; + +void tap.test("HashFactory demo", async (t) => { + t.plan(1); + t.setTimeout(1000); + t.teardown(() => TestNetwork.shutdown()); + TestNetwork.onError = (e) => t.error(e); + + const server = async () => { + const s = await TestNetwork.accept(); + s.initMain(HashFactory, { + newSha1: (_, r) => { + const hash = createHash("sha1"); + const hs = new Hash.Server({ + async sum(_, r) { + const digest = hash.digest(); + return Promise.resolve(r.initHash(digest.length).copyBuffer(digest)); + }, + + write: (p) => + new Promise((resolve, reject) => + hash.write(p.getData().toUint8Array(), undefined, (err) => (err ? reject(err) : resolve())) + ), + }); + return Promise.resolve(r.setHash(hs.client())); + }, + }); + return s; + }; + + const client = async () => { + const hash = TestNetwork.connect().bootstrap(HashFactory).newSha1().getHash(); + hash.write((p) => { + const buf = encodeUtf8("hello "); + p.initData(buf.byteLength).copyBuffer(buf); + }); + hash.write((p) => { + const buf = encodeUtf8("world"); + p.initData(buf.byteLength).copyBuffer(buf); + }); + const sum = await hash.sum().promise(); + return sum.getHash().toUint8Array(); + }; + + const [, result] = await Promise.all([server(), client()]); + t.equal(bufferToHex(result), "[2a ae 6c 35 c9 4f cf b4 15 db e9 5f 40 8b 9c e9 1e e8 46 ed]"); + t.end(); +}); diff --git a/packages/capnp-ts-test/test/integration/simple-interface.capnp b/packages/capnp-ts-test/test/integration/simple-interface.capnp new file mode 100644 index 0000000..4d6216e --- /dev/null +++ b/packages/capnp-ts-test/test/integration/simple-interface.capnp @@ -0,0 +1,5 @@ +@0xaa89f7261e168017; + +interface SimpleInterface { + subtract @0 (a :Int32, b :Int32) -> (result :Int32); +} diff --git a/packages/capnp-ts-test/test/integration/simple-interface.spec.ts b/packages/capnp-ts-test/test/integration/simple-interface.spec.ts new file mode 100644 index 0000000..19ec894 --- /dev/null +++ b/packages/capnp-ts-test/test/integration/simple-interface.spec.ts @@ -0,0 +1,38 @@ +import tap from "tap"; +import { SimpleInterface } from "./simple-interface.capnp.js"; +import { TestNetwork } from "../../../capnp-ts/src/rpc/transport/test-network.js"; + +void tap.test("simple interface demo", async (t) => { + t.plan(1); + t.setTimeout(1000); + t.teardown(() => TestNetwork.shutdown()); + TestNetwork.onError = t.error.bind(t); + + const server = async () => { + const s = await TestNetwork.accept(); + s.initMain(SimpleInterface, { + subtract: (p, r) => Promise.resolve(r.setResult(p.getA() - p.getB())), + }); + return s; + }; + + const client = async () => { + const res = await TestNetwork.connect() + .bootstrap(SimpleInterface) + .subtract((p) => { + p.setA(9); + p.setB(-1); + }) + .promise(); + return res.getResult(); + }; + + try { + const [, result] = await Promise.all([server(), client()]); + t.equal(result, 10); + } catch (err) { + t.error(err); + } finally { + t.end(); + } +}); diff --git a/packages/capnp-ts-test/test/unit/rpc/queue.spec.ts b/packages/capnp-ts-test/test/unit/rpc/queue.spec.ts new file mode 100644 index 0000000..a723cda --- /dev/null +++ b/packages/capnp-ts-test/test/unit/rpc/queue.spec.ts @@ -0,0 +1,124 @@ +import { Queue } from "capnp-ts/src/rpc/queue"; +import tap from "tap"; + +class Ints { + data: number[]; + constructor(len: number) { + this.data = new Array(len).fill(0); + } + + len(): number { + return this.data.length; + } + + clear(i: number) { + this.data[i] = 0; + } +} + +void tap.test("Queue new", (t) => { + const qi = new Ints(5); + const q = new Queue(qi, 0); + + t.equal(q.len(), 0); + t.end(); +}); + +void tap.test("Queue prepush", (t) => { + const qi = new Ints(5); + qi.data[0] = 42; + + const q = new Queue(qi, 1); + t.equal(q.len(), 1); + t.equal(q.front(), 0); + t.end(); +}); + +void tap.test("Queue push", (t) => { + const qi = new Ints(5); + const q = new Queue(qi, 0); + + const i = q.push(); + t.not(i, -1); + qi.data[i] = 42; + + t.equal(q.len(), 1); + t.equal(q.front(), i); + t.end(); +}); + +void tap.test("Queue push full", (t) => { + const qi = new Ints(5); + const q = new Queue(qi, 0); + const ok: boolean[] = new Array(6).fill(false); + + const push = (n: number, val: number) => { + const i = q.push(); + if (i === -1) { + return; + } + ok[n] = true; + qi.data[i] = val; + }; + push(0, 10); + push(1, 11); + push(2, 12); + push(3, 13); + push(4, 14); + push(5, 15); + + for (let i = 0; i < 5; i++) { + t.ok(ok[i]); + } + t.notOk(ok[5]); + t.equal(q.len(), 5); + t.end(); +}); + +void tap.test("Queue pop", (t) => { + const qi = new Ints(5); + const q = new Queue(qi, 0); + qi.data[q.push()] = 1; + qi.data[q.push()] = 2; + qi.data[q.push()] = 3; + + const outs: number[] = new Array(3).fill(0); + for (let n = 0; n < outs.length; n++) { + const i = q.front(); + t.not(i, -1); + outs[n] = qi.data[i]; + t.ok(q.pop()); + } + + t.equal(q.len(), 0); + t.equal(outs[0], 1); + t.equal(outs[1], 2); + t.equal(outs[2], 3); + for (let i = 0; i < qi.len(); i++) { + t.equal(qi.data[i], 0); + } + + t.end(); +}); + +void tap.test("Queue wrap", (t) => { + const qi = new Ints(5); + const q = new Queue(qi, 0); + + qi.data[q.push()] = 10; + qi.data[q.push()] = 11; + qi.data[q.push()] = 12; + q.pop(); + q.pop(); + qi.data[q.push()] = 13; + qi.data[q.push()] = 14; + qi.data[q.push()] = 15; + qi.data[q.push()] = 16; + + t.equal(q.len(), 5); + for (let i = 12; q.len() > 0; i++) { + t.equal(qi.data[q.front()], i); + t.ok(q.pop()); + } + t.end(); +}); diff --git a/packages/capnp-ts-test/test/unit/serialization/message.spec.ts b/packages/capnp-ts-test/test/unit/serialization/message.spec.ts index 9b6c4ca..e474549 100644 --- a/packages/capnp-ts-test/test/unit/serialization/message.spec.ts +++ b/packages/capnp-ts-test/test/unit/serialization/message.spec.ts @@ -141,7 +141,7 @@ void tap.test("Message.allocateSegment()", (t) => { }); void tap.test("Message.dump()", (t) => { - const m1 = new Message(new MultiSegmentArena()); + const m1 = new Message(new MultiSegmentArena([])); t.equal( m1.dump(), @@ -172,15 +172,18 @@ Segment #0 }); void tap.test("Message.getSegment()", (t) => { - const s = new Message(new MultiSegmentArena()).getSegment(0); + const s = new Message(new MultiSegmentArena([])).getSegment(0); t.equal(s.byteLength, 8, "should preallocate segment 0"); t.throws(() => new Message().getSegment(1), undefined, "should throw when getting out of range segments"); - const m = new Message(new MultiSegmentArena([new ArrayBuffer(2)])); // this is too small to hold the root pointer - - t.throws(() => m.getSegment(0), undefined, "should throw when segment 0 is too small"); + // this is too small to hold the root pointer + t.throws( + () => new MultiSegmentArena([new ArrayBuffer(2)]), + "CAPNP-TS037", + "should throw when segment 0 is too small" + ); t.end(); }); @@ -219,12 +222,12 @@ void tap.test("Message.toPackedArrayBuffer()", (t) => { void tap.test("preallocateSegments()", (t) => { t.throws( () => { - const message = new Message(new MultiSegmentArena()); + const message = new Message(new MultiSegmentArena([new ArrayBuffer(8), new ArrayBuffer(7)])); preallocateSegments(message); }, - undefined, - "should throw when preallocating an empty arena" + "CAPNP-TS005", + "should throw when preallocating with invalid buffers" ); t.end(); diff --git a/packages/capnp-ts/src/errors.ts b/packages/capnp-ts/src/errors.ts index 3fce404..461939f 100644 --- a/packages/capnp-ts/src/errors.ts +++ b/packages/capnp-ts/src/errors.ts @@ -4,13 +4,8 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { MAX_SEGMENT_LENGTH } from "./constants"; -const trace = initTrace("capnp:errors"); -trace("load"); - // Invariant violations (sometimes known as "precondition failed"). // // All right, hold up the brakes. This is a serious 1 === 0 WHAT THE FAILURE moment here. Tell the SO's you won't be @@ -113,3 +108,28 @@ export const TYPE_SET_GENERIC_LIST = "CAPNP-TS042 Attempted to call set() on a g export const PTR_WRITE_CONST_LIST = "CAPNP-TS043 Attempted to write to a const list."; export const PTR_WRITE_CONST_STRUCT = "CAPNP-TS044 Attempted to write to a const struct."; + +// RPC errors +// +// RPC is hard too. + +export const RPC_NULL_CLIENT = "CAPNP-TS100 Call on null client."; +export const RPC_CALL_QUEUE_FULL = "CAPNP-TS101 Promised answer call queue full."; +export const RPC_QUEUE_CALL_CANCEL = "CAPNP-TS102 Queue call canceled."; +export const RPC_CLOSED_CLIENT = "CAPNP-TS104 Close() called on closed client."; +export const RPC_ZERO_REF = "CAPNP-TS105 Ref() called on zeroed refcount."; +export const RPC_IMPORT_CLOSED = "CAPNP-TS106 Call on closed import."; +export const RPC_METHOD_NOT_IMPLEMENTED = "CAPNP-TS107 Method not implemented."; +export const RPC_UNIMPLEMENTED = "CAPNP-TS108 Remote used unimplemented feature."; +export const RPC_BAD_TARGET = "CAPNP-TS109 Target not found."; +export const RPC_ONERROR_CALLBACK_MISSING = "CAPNP-TS110 Connection error callback unavailable; original error: %s"; +export const RPC_RETURN_FOR_UNKNOWN_QUESTION = "CAPNP-TS111 Received return for unknown question (id=%s)."; +export const RPC_QUESTION_ID_REUSED = "CAPNP-TS112 Attempted to re-use question id (%s)."; +export const RPC_UNKNOWN_EXPORT_ID = "CAPNP-TS113 Capability table references unknown export ID (%s)."; +export const RPC_UNKNOWN_ANSWER_ID = "CAPNP-TS114 Capability table references unknown answer ID (%s)."; +export const RPC_UNKNOWN_CAP_DESCRIPTOR = "CAPNP-TS115 Unknown cap descriptor type (which: %s)."; +export const RPC_METHOD_ERROR = "CAPNP-TS116 RPC method failed at %s.%s(): %s"; +export const RPC_ERROR = "CAPNP-TS117 RPC call failed, reason: %s"; +export const RPC_NO_MAIN_INTERFACE = "CAPNP-TS118 Received bootstrap message without main interface set."; +export const RPC_FINISH_UNKNOWN_ANSWER = "CAPNP-TS119 Received finish message for unknown answer ID (%s)."; +export const RPC_FULFILL_ALREADY_CALLED = "CAPNP-TS120 Fulfill called more than once for question (%s)."; diff --git a/packages/capnp-ts/src/index.ts b/packages/capnp-ts/src/index.ts index d21a7fc..523956c 100644 --- a/packages/capnp-ts/src/index.ts +++ b/packages/capnp-ts/src/index.ts @@ -48,3 +48,5 @@ export { getUint64Mask, getUint8Mask, } from "./serialization"; + +export { Deferred, Transport, Conn, Call, Client, Pipeline, RPCMessage, Method, Server, Registry } from "./rpc"; diff --git a/packages/capnp-ts/src/rpc/answer.ts b/packages/capnp-ts/src/rpc/answer.ts new file mode 100644 index 0000000..2b738ff --- /dev/null +++ b/packages/capnp-ts/src/rpc/answer.ts @@ -0,0 +1,249 @@ +import { Struct } from "../serialization/pointers/struct"; +import { PipelineOp } from "./pipeline-op"; +import { Call, copyCall } from "./call"; +import { Conn } from "./conn"; +import { Deferred } from "./deferred"; +import { MessageTarget } from "../std/rpc.capnp"; +import { Fulfiller } from "./fulfiller/fulfiller"; +import { newReturnMessage, setReturnException } from "./capability"; +import { Pointer } from "../serialization/pointers/pointer"; +import { transformPtr } from "./transform-ptr"; +import { Interface } from "../serialization/pointers/interface"; +import { INVARIANT_UNREACHABLE_CODE, RPC_CALL_QUEUE_FULL, RPC_NULL_CLIENT } from "../errors"; +import { QueueClient, callQueueSize } from "./queue-client"; + +// An Answer is the deferred result of a client call, which is usually wrapped +// by a Pipeline. +export interface Answer { + // struct waits until the call is finished and returns the result. + struct(): Promise; + + // The following methods are the same as in Client except with an added + // transform parameter -- a path to the interface to use. + pipelineCall( + transform: PipelineOp[], + call: Call + ): Answer; + pipelineClose(transform: PipelineOp[]): void; +} + +export class AnswerEntry { + id: number; + conn: Conn; + resultCaps: number[] = []; + + done = false; + obj?: R; + err?: Error; + deferred = new Deferred(); + queue: AnswerPCall[] = []; + + constructor(conn: Conn, id: number) { + this.conn = conn; + this.id = id; + } + + // fulfill is called to resolve an answer successfully. + fulfill(obj: R): void { + if (this.done) { + throw new Error(`answer.fulfill called more than once`); + } + + this.done = true; + this.obj = obj; + + const retmsg = newReturnMessage(this.id); + const ret = retmsg.getReturn(); + const payload = ret.initResults(); + payload.setContent(obj); + + let firstErr: Error | undefined; + try { + this.conn.makeCapTable(ret.segment, (len) => payload.initCapTable(len)); + this.deferred.resolve(obj); + this.conn.sendMessage(retmsg); + } catch (err) { + if (!firstErr) { + firstErr = err as Error; + } + } + + const [queues, queuesErr] = this.emptyQueue(obj); + if (queuesErr && !firstErr) { + firstErr = queuesErr; + } + + const objcap = obj.segment.message._capnp; + if (!objcap.capTable) { + objcap.capTable = []; + } + for (const capIdxStr of Object.keys(queues)) { + const capIdx = Number(capIdxStr); + const q = queues[capIdx]; + if (objcap.capTable === null) throw new Error(INVARIANT_UNREACHABLE_CODE); + objcap.capTable[capIdx] = new QueueClient( + this.conn, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + objcap.capTable[capIdx]!, + q + ); + } + + if (firstErr) { + throw firstErr; + } + } + + // reject is called to resolve an answer with failure. + reject(err: Error): void { + if (!err) { + throw new Error(`answer.reject called with nil`); + } + if (this.done) { + throw new Error(`answer.reject claled more than once`); + } + + const m = newReturnMessage(this.id); + const mret = m.getReturn(); + setReturnException(mret, err); + + this.err = err; + this.done = true; + this.deferred.reject(err); + + let firstErr: Error | undefined; + try { + this.conn.sendMessage(m); + } catch (e) { + firstErr = e as Error; + } + + for (let i = 0; i < this.queue.length; i++) { + const qa = this.queue[i]; + try { + if (qa.qcall && isRemoteCall(qa.qcall)) { + qa.qcall.a.reject(err); + } + } catch (e) { + if (!firstErr) { + firstErr = e as Error; + } + } + } + this.queue = []; + + if (firstErr) { + throw firstErr; + } + } + + // emptyQueue splits the queue by which capability it targets + // and drops any invalid calls. Once this function returns, + // this.queue will be empty. + emptyQueue(obj: R): [{ [key: number]: AnswerQCall[] }, Error | undefined] { + let firstErr: Error | undefined; + const qs: { [key: number]: AnswerQCall[] } = {}; + + for (let i = 0; i < this.queue.length; i++) { + const pc = this.queue[i]; + if (!isRemoteCall(pc.qcall)) { + continue; + } + + if (!pc.qcall.a) { + continue; + } + + let c: Pointer; + try { + c = transformPtr(obj, pc.transform); + } catch (err) { + try { + pc.qcall.a.reject(err as Error); + } catch (err) { + if (!firstErr) { + firstErr = err as Error; + } + } + continue; + } + + const ci = Interface.fromPointer(c); + if (!ci) { + try { + pc.qcall.a.reject(new Error(RPC_NULL_CLIENT)); + } catch (err) { + if (!firstErr) { + firstErr = err as Error; + } + } + continue; + } + + const cn = ci.getCapId(); + if (!qs[cn]) { + qs[cn] = []; + } + qs[cn].push(pc.qcall); + } + + this.queue = []; + return [qs, firstErr]; + } + + queueCall

(call: Call, transform: PipelineOp[], a: AnswerEntry): void { + if (this.queue.length >= callQueueSize) { + throw new Error(RPC_CALL_QUEUE_FULL); + } + + const qcall: QCallRemoteCall = { + a, + call: copyCall(call), + }; + const pcall: AnswerPCall = { + qcall, + transform, + }; + this.queue.push(pcall); + } +} + +export type AnswerQCall = QCallRemoteCall | QCallLocalCall | QCallDisembargo; + +export interface QCallRemoteCall { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + call: Call; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + a: AnswerEntry; // defined if remote call +} + +export interface QCallLocalCall { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + call: Call; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + f: Fulfiller; // defined if local call +} + +export interface QCallDisembargo { + embargoID: number; + embargoTarget: MessageTarget; +} + +export function isRemoteCall(a: AnswerQCall): a is QCallRemoteCall { + return !!(a as QCallRemoteCall).a; +} + +export function isLocalCall(a: AnswerQCall): a is QCallLocalCall { + return !!(a as QCallLocalCall).f; +} + +export function isDisembargo(a: AnswerQCall): a is QCallDisembargo { + return !!(a as QCallDisembargo).embargoTarget; +} + +export interface AnswerPCall { + qcall: AnswerQCall; + transform: PipelineOp[]; +} diff --git a/packages/capnp-ts/src/rpc/call.ts b/packages/capnp-ts/src/rpc/call.ts new file mode 100644 index 0000000..d36a471 --- /dev/null +++ b/packages/capnp-ts/src/rpc/call.ts @@ -0,0 +1,75 @@ +import { Struct } from "../serialization/pointers/struct"; +import { Pointer } from "../serialization/pointers/pointer"; +import { Message } from "../serialization/message"; +import { Method } from "./method"; + +// The Call type holds the record for an outgoing interface call. +export type Call

= FuncCall | DataCall; + +export interface BaseCall

{ + // Method is the interface ID and method ID, along with the optional name, of + // the method to call. + method: Method; +} + +export type FuncCall

= BaseCall & { + // ParamsFunc is a function that populates an allocated struct with + // the parameters for the call. ParamsSize determines the size of the + // struct to allocate. This is used when application code is using a + // client. These settings should be set together; they are mutually + // exclusive with Params. + paramsFunc?(params: P): void; +}; + +export type DataCall

= BaseCall & { + // Params is a struct containing parameters for the call. + // This should be set when the RPC system receives a call for an + // exported interface. It is mutually exclusive with ParamsFunc + // and ParamsSize. + params: P; +}; + +export function isFuncCall

(call: Call): call is FuncCall { + return !isDataCall(call); +} + +export function isDataCall

(call: Call): call is DataCall { + return !!(call as DataCall).params; +} + +// Copy clones a call, ensuring that its params are placed. +// If Call.ParamsFunc is nil, then the same Call will be returned. +export function copyCall

(call: Call): DataCall { + if (isDataCall(call)) { + return call; + } + + // FIXME: it's not clear to me why the Go implementation needed + // copyCall in the first place - and why it needed params to be + // placed. + return { + method: call.method, + params: placeParams(call, undefined), + }; +} + +export function placeParams

(call: Call, contentPtr: Pointer | undefined): P { + if (isDataCall(call)) { + return call.params; + } + + // TODO: this needs to be reviewed, I'm pretty sure it's the wrong + // way to do it. + let p: P; + if (contentPtr) { + p = new call.method.ParamsClass(contentPtr.segment, contentPtr.byteOffset, contentPtr._capnp.depthLimit); + } else { + const msg = new Message(); + p = new call.method.ParamsClass(msg.getSegment(0), 0); + } + Struct.initStruct(call.method.ParamsClass._capnp.size, p); + if (call.paramsFunc) { + call.paramsFunc(p); + } + return p; +} diff --git a/packages/capnp-ts/src/rpc/capability.ts b/packages/capnp-ts/src/rpc/capability.ts new file mode 100644 index 0000000..fc55dbc --- /dev/null +++ b/packages/capnp-ts/src/rpc/capability.ts @@ -0,0 +1,58 @@ +import { RPCMessage } from "./rpc-message"; +import { Message } from "../serialization/message"; +import { Return, Exception, Disembargo_Context_Which } from "../std/rpc.capnp"; +import { toException } from "./rpc-error"; +import { INVARIANT_UNREACHABLE_CODE } from "../errors"; + +// A CapabilityID is an index into a message's capability table. +export type CapabilityID = number; + +export function newMessage(): RPCMessage { + return new Message().initRoot(RPCMessage); +} + +export function newFinishMessage(questionID: number, release: boolean): RPCMessage { + const m = newMessage(); + const f = m.initFinish(); + f.setQuestionId(questionID); + f.setReleaseResultCaps(release); + return m; +} + +export function newUnimplementedMessage(m: RPCMessage): RPCMessage { + const n = newMessage(); + n.setUnimplemented(m); + return n; +} + +export function newReturnMessage(id: number): RPCMessage { + const m = newMessage(); + const ret = m.initReturn(); + ret.setAnswerId(id); + return m; +} + +export function setReturnException(ret: Return, err: Error): Exception { + const exc = ret.initException(); + toException(exc, err); + return exc; +} + +export function newDisembargoMessage(which: Disembargo_Context_Which, id: number): RPCMessage { + const m = newMessage(); + const dis = m.initDisembargo(); + const ctx = dis.initContext(); + switch (which) { + case Disembargo_Context_Which.SENDER_LOOPBACK: { + ctx.setSenderLoopback(id); + break; + } + case Disembargo_Context_Which.RECEIVER_LOOPBACK: { + ctx.setReceiverLoopback(id); + break; + } + default: + throw new Error(INVARIANT_UNREACHABLE_CODE); + } + return m; +} diff --git a/packages/capnp-ts/src/rpc/client.ts b/packages/capnp-ts/src/rpc/client.ts new file mode 100644 index 0000000..bceaf43 --- /dev/null +++ b/packages/capnp-ts/src/rpc/client.ts @@ -0,0 +1,51 @@ +import { Struct, getInterfaceClientOrNull } from "../serialization/pointers/struct"; +import { Call } from "./call"; +import { Answer } from "./answer"; +import { PipelineOp } from "./pipeline-op"; +import { ErrorClient } from "./error-client"; +import { transformPtr } from "./transform-ptr"; + +// A Client represents an Cap'n Proto interface type. +export interface Client { + // call starts executing a method and returns an answer that will hold + // the resulting struct. The call's parameters must be placed before + // call() returns. + // + // Calls are delivered to the capability in the order they are made. + // This guarantee is based on the concept of a capability + // acknowledging delivery of a call: this is specific to an + // implementation of Client. A type that implements Client must + // guarantee that if foo() then bar() is called on a client, that + // acknowledging foo() happens before acknowledging bar(). + call

(call: Call): Answer; + + // close releases any resources associated with this client. + // No further calls to the client should be made after calling Close. + close(): void; +} + +export function isSameClient(c: Client, d: Client): boolean { + const norm = (c: Client): Client => { + // TODO: normalize, see https://sourcegraph.com/github.com/capnproto/go-capnproto2@e1ae1f982d9908a41db464f02861a850a0880a5a/-/blob/rpc/introspect.go#L209 + return c; + }; + return norm(c) === norm(d); +} + +/* + * clientFromResolution retrieves a client from a resolved question or answer + * by applying a transform. + */ +export function clientFromResolution(transform: PipelineOp[], obj?: Struct, err?: Error): Client { + if (err) { + return new ErrorClient(err); + } + + if (!obj) { + return new ErrorClient(new Error(`null obj!`)); + } + + const out = transformPtr(obj, transform); + return getInterfaceClientOrNull(out); + // return clientOrNull(Interface.fromPointer(out)!.getClient()); +} diff --git a/packages/capnp-ts/src/rpc/conn.ts b/packages/capnp-ts/src/rpc/conn.ts new file mode 100644 index 0000000..a1e49a3 --- /dev/null +++ b/packages/capnp-ts/src/rpc/conn.ts @@ -0,0 +1,649 @@ +import { IDGen } from "./idgen"; +import { RefCount } from "./refcount"; +import { Client, isSameClient, clientFromResolution } from "./client"; +import { Transport } from "./transport"; +import { Question, QuestionState } from "./question"; +import { + Message_Which, + Return, + Return_Which, + Payload, + CapDescriptor, + MessageTarget, + MessageTarget_Which, +} from "../std/rpc.capnp"; +import { RPCError } from "./rpc-error"; +import { AnswerEntry, Answer } from "./answer"; +import { + newMessage, + newFinishMessage, + newUnimplementedMessage, + newReturnMessage, + setReturnException, +} from "./capability"; +import { Pipeline } from "./pipeline"; +import { Struct } from "../serialization/pointers/struct"; +import { promisedAnswerOpsToTransform, transformToPromisedAnswer } from "./promised-answer"; +import { Method } from "./method"; +import { PipelineOp } from "./pipeline-op"; +import { ImportClient } from "./import-client"; +import { Call, placeParams } from "./call"; +import { Segment } from "../serialization/segment"; +import { List } from "../serialization/pointers/list"; +import { Ref } from "./ref"; +import { PipelineClient } from "./pipeline-client"; +import { FixedAnswer } from "./fixed-answer"; +import { LocalAnswerClient } from "./local-answer-client"; +import initTrace from "debug"; +import { Finalize } from "./finalize"; +import { RPCMessage } from "./rpc-message"; +import { MethodError } from "./method-error"; +import { Registry } from "./registry"; +import { joinAnswer } from "./join"; +import { + INVARIANT_UNREACHABLE_CODE, + RPC_BAD_TARGET, + RPC_FINISH_UNKNOWN_ANSWER, + RPC_NO_MAIN_INTERFACE, + RPC_ONERROR_CALLBACK_MISSING, + RPC_QUESTION_ID_REUSED, + RPC_RETURN_FOR_UNKNOWN_QUESTION, + RPC_UNKNOWN_ANSWER_ID, + RPC_UNKNOWN_CAP_DESCRIPTOR, + RPC_UNKNOWN_EXPORT_ID, +} from "../errors"; +import { format } from "../util"; +import { Interface, Message } from "../serialization"; +import { AnyStruct } from "../serialization/pointers/any-struct"; +import { InterfaceCtor, ServerTarget } from "../serialization/pointers/interface"; +import { Server } from "./server"; + +const trace = initTrace("capnp:rpc:conn"); + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type QuestionSlot = Question | null; + +export class Conn { + static weakRefRegistry = new FinalizationRegistry<() => void>((cb) => cb()); + static defaultFinalize: Finalize = (obj, finalizer): void => { + // eslint-disable-next-line @typescript-eslint/ban-types + Conn.weakRefRegistry.register(obj as object, finalizer); + }; + transport: Transport; + finalize: Finalize; + + questionID = new IDGen(); + questions = [] as QuestionSlot[]; + + exportID = new IDGen(); + exports = [] as Array; + + imports = {} as { [key: number]: ImportEntry }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + answers = {} as { [key: number]: AnswerEntry }; + + onError?: (err?: Error) => void; + main?: Client; + working = false; + + /** + * Create a new connection + * @param {Transport} transport The transport used to receive/send messages. + * @param {Finalize} finalize Weak reference implementation. Compatible with + * the 'weak' module on node.js (just add weak as a dependency and pass + * require("weak")), but alternative implementations can be provided for + * other platforms like Electron. Defaults to using FinalizationRegistry if + * available. + * @returns {Conn} A new connection. + */ + constructor(transport: Transport, finalize = Conn.defaultFinalize) { + this.transport = transport; + this.finalize = finalize; + this.questionID = new IDGen(); + this.questions = []; + this.startWork(); + } + + bootstrap(InterfaceClass: InterfaceCtor): C { + const q = this.newQuestion(); + const msg = newMessage(); + const boot = msg.initBootstrap(); + boot.setQuestionId(q.id); + + this.sendMessage(msg); + return new InterfaceClass.Client(new Pipeline(AnyStruct, q).client()); + } + + initMain>(InterfaceClass: S, target: ServerTarget): void { + this.main = new InterfaceClass.Server(target); + this.addExport(this.main); + } + + startWork(): void { + this.work().catch((e) => { + if (this.onError) { + this.onError(e); + } else if (e !== undefined) { + trace(format(RPC_ONERROR_CALLBACK_MISSING, e)); + throw e; + } + }); + } + + sendReturnException(id: number, err: Error): void { + const m = newReturnMessage(id); + setReturnException(m.getReturn(), err); + this.sendMessage(m); + } + + handleBootstrapMessage(m: RPCMessage): void { + trace("BOOTSTRAP received; main: %s", this.main); + const boot = m.getBootstrap(); + const id = boot.getQuestionId(); + const ret = newReturnMessage(id); + ret.getReturn().setReleaseParamCaps(false); + const a = this.insertAnswer(id); + if (a === null) return this.sendReturnException(id, new Error(RPC_QUESTION_ID_REUSED)); + if (this.main === undefined) return a.reject(new Error(RPC_NO_MAIN_INTERFACE)); + + const msg = new Message(); + msg.addCap(this.main); + a.fulfill(new Interface(msg.getSegment(0), 0)); + } + + handleFinishMessage(m: RPCMessage): void { + const finish = m.getFinish(); + const id = finish.getQuestionId(); + const a = this.popAnswer(id); + trace("FINISH received; id: %s", id); + if (a === null) { + throw new Error(format(RPC_FINISH_UNKNOWN_ANSWER, id)); + } + if (finish.getReleaseResultCaps()) { + const caps = a.resultCaps; + let i = caps.length; + while (--i >= 0) { + this.releaseExport(i, 1); + } + } + } + + handleMessage(m: RPCMessage): void { + switch (m.which()) { + case RPCMessage.UNIMPLEMENTED: { + // no-op for now to avoid feedback loop + break; + } + case RPCMessage.BOOTSTRAP: { + this.handleBootstrapMessage(m); + break; + } + case RPCMessage.ABORT: { + this.shutdown(new RPCError(m.getAbort())); + break; + } + case RPCMessage.FINISH: + this.handleFinishMessage(m); + break; + case RPCMessage.RETURN: { + // Make a copy to allow `m` to fall out of scope for GC and finalization + // this.handleReturnMessage(m.segment.message.copy().initRoot(RPCMessage)); + this.handleReturnMessage(m); + break; + } + case RPCMessage.CALL: { + // Make a copy to allow `m` to fall out of scope for GC and finalization + // this.handleCallMessage(m.segment.message.copy().initRoot(RPCMessage)); + this.handleCallMessage(m); + break; + } + default: { + trace(`Ignoring message ${Message_Which[m.which()]}`); + } + } + } + + handleReturnMessage(m: RPCMessage): void { + const ret = m.getReturn(); + const id = ret.getAnswerId(); + const q = this.popQuestion(id); + trace("RETURN received; id: %s, question: %s, release params: %s", id, q, ret.getReleaseParamCaps()); + if (!q) { + throw new Error(format(RPC_RETURN_FOR_UNKNOWN_QUESTION, id)); + } + + if (ret.getReleaseParamCaps()) { + for (let i = 0; i < q.paramCaps.length; i++) { + this.releaseExport(id, 1); + } + } + + let releaseResultCaps = true; + switch (ret.which()) { + case Return.RESULTS: { + releaseResultCaps = false; + const results = ret.getResults(); + // TODO: reply with unimplemented if we have a problem here + this.populateMessageCapTable(results); + + const content = results.getContent(); + q.fulfill(content); + break; + } + case Return.EXCEPTION: { + const exc = ret.getException(); + let err: Error; + if (q.method) { + err = new MethodError(q.method, exc.getReason()); + } else { + err = new RPCError(exc); + } + q.reject(err); + break; + } + default: { + trace(`Unhandled return which: ${Return_Which[ret.which()]}`); + } + } + + const fin = newFinishMessage(id, releaseResultCaps); + this.sendMessage(fin); + } + + handleCallMessage(m: RPCMessage): void { + const mcall = m.getCall(); + const mt = mcall.getTarget(); + trace("CALL received; target: ", MessageTarget_Which[mt.which()]); + if (mt.which() !== MessageTarget.IMPORTED_CAP && mt.which() !== MessageTarget.PROMISED_ANSWER) { + const um = newUnimplementedMessage(m); + this.sendMessage(um); + return; + } + + const mparams = mcall.getParams(); + try { + this.populateMessageCapTable(mparams); + } catch (e) { + const um = newUnimplementedMessage(m); + this.sendMessage(um); + return; + } + + const id = mcall.getQuestionId(); + const a = this.insertAnswer(id); + if (!a) { + // TODO: this should abort the whole conn + throw new Error(format(RPC_QUESTION_ID_REUSED, id)); + } + + const interfaceDef = Registry.lookup(mcall.getInterfaceId()); + if (!interfaceDef) { + trace(`handleCallMessage: Unknown interface: ${mcall.getInterfaceId().toString(16)}`); + const um = newUnimplementedMessage(m); + this.sendMessage(um); + return; + } + + const method = interfaceDef.methods[mcall.getMethodId()]; + if (!method) { + trace( + `handleCallMessage: Unknown method ${mcall.getMethodId()} on interface ${mcall.getInterfaceId().toString(16)}` + ); + const um = newUnimplementedMessage(m); + this.sendMessage(um); + return; + } + + const paramContent = mparams.getContent(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const call: Call = { + method, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + params: Struct.getAs(method.ParamsClass, paramContent), + }; + try { + this.routeCallMessage(a, mt, call); + } catch (e) { + a.reject(e as Error); + } + } + + routeCallMessage

( + result: AnswerEntry, + mt: MessageTarget, + cl: Call + ): void { + switch (mt.which()) { + case MessageTarget.IMPORTED_CAP: { + const id = mt.getImportedCap(); + const e = this.findExport(id); + if (!e) { + throw new Error(RPC_BAD_TARGET); + } + const answer = this.call(e.client, cl); + joinAnswer(result, answer); + break; + } + case MessageTarget.PROMISED_ANSWER: { + const mpromise = mt.getPromisedAnswer(); + const id = mpromise.getQuestionId(); + if (id === result.id) { + // Grandfather paradox + throw new Error(RPC_BAD_TARGET); + } + const pa = this.answers[id] as AnswerEntry; + if (!pa) { + throw new Error(RPC_BAD_TARGET); + } + const mtrans = mpromise.getTransform(); + const transform = promisedAnswerOpsToTransform(mtrans); + if (pa.done) { + const { obj, err } = pa; + const client = clientFromResolution(transform, obj, err); + const answer = this.call(client, cl); + joinAnswer(result, answer); + } else { + pa.queueCall(cl, transform, result); + } + + break; + } + default: { + throw new Error(INVARIANT_UNREACHABLE_CODE); + } + } + } + + populateMessageCapTable(payload: Payload): void { + const msg = payload.segment.message; + const ctab = payload.getCapTable(); + ctab.forEach((desc) => { + switch (desc.which()) { + case CapDescriptor.NONE: { + msg.addCap(null); + break; + } + case CapDescriptor.SENDER_HOSTED: { + const id = desc.getSenderHosted(); + const client = this.addImport(id); + msg.addCap(client); + break; + } + case CapDescriptor.SENDER_PROMISE: { + // Apparently, this is a hack, see https://sourcegraph.com/github.com/capnproto/go-capnproto2@e1ae1f982d9908a41db464f02861a850a0880a5a/-/blob/rpc/rpc.go#L549 + const id = desc.getSenderPromise(); + const client = this.addImport(id); + msg.addCap(client); + break; + } + case CapDescriptor.RECEIVER_HOSTED: { + const id = desc.getReceiverHosted(); + const e = this.findExport(id); + if (!e) { + throw new Error(format(RPC_UNKNOWN_EXPORT_ID, id)); + } + msg.addCap(e.rc.ref()); + break; + } + case CapDescriptor.RECEIVER_ANSWER: { + const recvAns = desc.getReceiverAnswer(); + const id = recvAns.getQuestionId(); + const a = this.answers[id]; + if (!a) { + throw new Error(format(RPC_UNKNOWN_ANSWER_ID, id)); + } + const recvTransform = recvAns.getTransform(); + const transform = promisedAnswerOpsToTransform(recvTransform); + msg.addCap(answerPipelineClient(a, transform)); + break; + } + default: + throw new Error(format(RPC_UNKNOWN_CAP_DESCRIPTOR, desc.which())); + } + }); + } + + addImport(id: number): Client { + const importEntry = this.imports[id]; + if (importEntry) { + importEntry.refs++; + return importEntry.rc.ref(); + } + const client = new ImportClient(this, id); + const [rc, ref] = RefCount.new(client, this.finalize); + this.imports[id] = { + rc, + refs: 1, + }; + return ref; + } + + findExport(id: number): Export | null { + if (id > this.exports.length) { + return null; + } + return this.exports[id]; + } + + addExport(client: Client): number { + for (let i = 0; i < this.exports.length; i++) { + const e = this.exports[i]; + if (e && isSameClient(e.rc._client, client)) { + e.wireRefs++; + return i; + } + } + + const id = this.exportID.next(); + const [rc, ref] = RefCount.new(client, this.finalize); + const _export: Export = { + client: ref, + id, + rc, + wireRefs: 1, + }; + if (id === this.exports.length) { + this.exports.push(_export); + } else { + this.exports[id] = _export; + } + return id; + } + + releaseExport(id: number, refs: number): void { + const e = this.findExport(id); + if (!e) { + return; + } + e.wireRefs -= refs; + if (e.wireRefs > 0) { + return; + } + if (e.wireRefs < 0) { + this.error(`warning: export ${id} has negative refcount (${e.wireRefs})`); + } + e.client.close(); + this.exports[id] = null; + this.exportID.remove(id); + } + + error(s: string): void { + console.error(s); + } + + newQuestion( + method?: Method + ): Question { + const id = this.questionID.next(); + const q = new Question(this, id, method); + if (id === this.questions.length) { + this.questions.push(q); + } else { + this.questions[id] = q; + } + return q; + } + + findQuestion

(id: number): Question | null { + if (id > this.questions.length) { + return null; + } + return this.questions[id]; + } + + popQuestion

(id: number): Question | null { + const q = this.findQuestion(id); + if (!q) { + return q; + } + this.questions[id] = null; + this.questionID.remove(id); + return q; + } + + // TODO: cancel context? + // eslint-disable-next-line @typescript-eslint/no-explicit-any + insertAnswer(id: number): AnswerEntry | null { + if (this.answers[id]) { + return null; + } + const a = new AnswerEntry(this, id); + this.answers[id] = a; + return a; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + popAnswer(id: number): AnswerEntry | null { + const a = this.answers[id]; + delete this.answers[id]; + return a; + } + + shutdown(err?: Error): void { + // FIXME: unstub + trace("shutdown (stub): %s", err?.stack); + this.transport.close(); + } + + call

(client: Client, call: Call): Answer { + // TODO: this has a lot of complicated logic in the Go implementation + // (lockedCall). + // Some of it has to do with locking, which we don't need + return client.call(call); + } + + fillParams

(payload: Payload, cl: Call): void { + const params = placeParams(cl, payload.getContent()); + payload.setContent(params); + this.makeCapTable(payload.segment, (length) => payload.initCapTable(length)); + } + + makeCapTable(s: Segment, init: (length: number) => List): void { + const msgtab = s.message._capnp.capTable; + if (!msgtab) { + return; + } + const t = init(msgtab.length); + for (let i = 0; i < msgtab.length; i++) { + const client = msgtab[i]; + const desc = t.get(i); + if (!client) { + desc.setNone(); + continue; + } + this.descriptorForClient(desc, client); + } + } + + // descriptorForClient fills desc for client, adding it to the export + // table if necessary. The caller must be holding onto c.mu. + descriptorForClient(desc: CapDescriptor, _client: Client): void { + { + dig: for (let client = _client; ; ) { + // cf. https://sourcegraph.com/github.com/capnproto/go-capnproto2@e1ae1f982d9908a41db464f02861a850a0880a5a/-/blob/rpc/introspect.go#L113 + // TODO: fulfiller.EmbargoClient + // TODO: embargoClient + // TODO: queueClient + // TODO: localAnswerClient + if (client instanceof ImportClient) { + if (client.conn !== this) { + break dig; + } + desc.setReceiverHosted(client.id); + return; + } else if (client instanceof Ref) { + client = client.client(); + } else if (client instanceof PipelineClient) { + const p = client.pipeline; + const ans = p.answer; + const transform = p.transform(); + // TODO: fulfiller + if (ans instanceof FixedAnswer) { + let s: Struct | undefined; + let err: Error | undefined; + try { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + s = ans.structSync(); + } catch (e) { + err = e as Error; + } + client = clientFromResolution(transform, s, err); + } else if (ans instanceof Question) { + if (ans.state !== QuestionState.IN_PROGRESS) { + client = clientFromResolution(transform, ans.obj, ans.err); + continue; + } + if (ans.conn !== this) { + break dig; + } + const a = desc.initReceiverAnswer(); + a.setQuestionId(ans.id); + transformToPromisedAnswer(a, p.transform()); + return; + } else { + break dig; + } + } else { + break dig; + } + } + } + + const id = this.addExport(_client); + desc.setSenderHosted(id); + } + + sendMessage(msg: RPCMessage): void { + this.transport.sendMessage(msg); + } + + private async work() { + this.working = true; + while (this.working) { + try { + const m = await this.transport.recvMessage(); + this.handleMessage(m); + } catch (err) { + if (err !== undefined) throw err; + this.working = false; + trace("aborting work loop: connection closed"); + } + } + } +} + +interface Export { + id: number; + rc: RefCount; + client: Client; + wireRefs: number; +} + +export interface ImportEntry { + rc: RefCount; + refs: number; +} + +export function answerPipelineClient(a: AnswerEntry, transform: PipelineOp[]): Client { + return new LocalAnswerClient(a, transform); +} diff --git a/packages/capnp-ts/src/rpc/deferred.ts b/packages/capnp-ts/src/rpc/deferred.ts new file mode 100644 index 0000000..820b9ad --- /dev/null +++ b/packages/capnp-ts/src/rpc/deferred.ts @@ -0,0 +1,35 @@ +// export class Deferred { +// promise: Promise; +// resolve!: (t: T) => void; +// reject!: (err: Error) => void; + +import initTrace from "debug"; + +const trace = initTrace("capnp:rpc:deferred"); + +// constructor() { +// this.promise = new Promise((resolve, reject) => { +// this.resolve = resolve; +// this.reject = reject; +// }); +// } +// } + +export class Deferred { + static fromPromise(p: Promise): Deferred { + const d = new Deferred(); + p.then(d.resolve, d.reject); + return d; + } + + promise: Promise; + reject!: (reason?: unknown) => void; + resolve!: (value: T | PromiseLike) => void; + + constructor() { + this.promise = new Promise((a, b) => { + this.resolve = a; + this.reject = b; + }); + } +} diff --git a/packages/capnp-ts/src/rpc/error-answer.ts b/packages/capnp-ts/src/rpc/error-answer.ts new file mode 100644 index 0000000..577897d --- /dev/null +++ b/packages/capnp-ts/src/rpc/error-answer.ts @@ -0,0 +1,34 @@ +import { FixedAnswer } from "./fixed-answer"; +import { Struct } from "../serialization/pointers/struct"; +import { PipelineOp } from "./pipeline-op"; +import { Call } from "./call"; +import { Answer } from "./answer"; + +export class ErrorAnswer extends FixedAnswer { + err: Error; + + constructor(err: Error) { + super(); + this.err = err; + } + + structSync(): T { + throw this.err; + } + + pipelineCall( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _transform: PipelineOp[], + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _call: Call + ): Answer { + // doesn't matter, it's still going to err + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any + return this as any; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + pipelineClose(_transform: PipelineOp[]): void { + throw this.err; + } +} diff --git a/packages/capnp-ts/src/rpc/error-client.ts b/packages/capnp-ts/src/rpc/error-client.ts new file mode 100644 index 0000000..83be13a --- /dev/null +++ b/packages/capnp-ts/src/rpc/error-client.ts @@ -0,0 +1,27 @@ +import { Client } from "./client"; +import { RPC_NULL_CLIENT } from "../errors"; +import { Answer } from "./answer"; +import { Struct } from "../serialization/pointers/struct"; +import { Call } from "./call"; +import { ErrorAnswer } from "./error-answer"; + +export class ErrorClient implements Client { + err: Error; + + constructor(err: Error) { + this.err = err; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + call

(_call: Call): Answer { + return new ErrorAnswer(this.err); + } + + close(): void { + throw this.err; + } +} + +export function clientOrNull(client: Client | null): Client { + return client ? client : new ErrorClient(new Error(RPC_NULL_CLIENT)); +} diff --git a/packages/capnp-ts/src/rpc/finalize.ts b/packages/capnp-ts/src/rpc/finalize.ts new file mode 100644 index 0000000..b2e2451 --- /dev/null +++ b/packages/capnp-ts/src/rpc/finalize.ts @@ -0,0 +1,2 @@ +export type Finalize = (obj: unknown, finalizer: Finalizer) => void; +export type Finalizer = () => void; diff --git a/packages/capnp-ts/src/rpc/fixed-answer.ts b/packages/capnp-ts/src/rpc/fixed-answer.ts new file mode 100644 index 0000000..3068624 --- /dev/null +++ b/packages/capnp-ts/src/rpc/fixed-answer.ts @@ -0,0 +1,18 @@ +import { Struct } from "../serialization/pointers/struct"; +import { Answer } from "./answer"; +import { PipelineOp } from "./pipeline-op"; +import { Call } from "./call"; + +export abstract class FixedAnswer implements Answer { + abstract structSync(): R; + + struct(): Promise { + return Promise.resolve(this.structSync()); + } + + abstract pipelineCall( + transform: PipelineOp[], + call: Call + ): Answer; + abstract pipelineClose(transform: PipelineOp[]): void; +} diff --git a/packages/capnp-ts/src/rpc/fulfiller/ecalls.ts b/packages/capnp-ts/src/rpc/fulfiller/ecalls.ts new file mode 100644 index 0000000..4fd9825 --- /dev/null +++ b/packages/capnp-ts/src/rpc/fulfiller/ecalls.ts @@ -0,0 +1,42 @@ +import { PipelineOp } from "../pipeline-op"; +import { Fulfiller } from "./fulfiller"; +import { Call } from "../call"; + +// ecall is a queued embargoed call +export interface ecall { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + call: Call; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + f: Fulfiller; +} + +// pcall is a queued pipeline call +export interface pcall extends ecall { + transform: PipelineOp[]; +} + +export type ecallSlot = ecall | null; + +export class Ecalls { + data: ecallSlot[]; + + constructor(data: ecallSlot[]) { + this.data = data; + } + + static copyOf(data: ecallSlot[]): Ecalls { + return new Ecalls([...data]); + } + + len(): number { + return this.data.length; + } + + clear(i: number): void { + this.data[i] = null; + } + + copy(): Ecalls { + return Ecalls.copyOf(this.data); + } +} diff --git a/packages/capnp-ts/src/rpc/fulfiller/embargo-client.ts b/packages/capnp-ts/src/rpc/fulfiller/embargo-client.ts new file mode 100644 index 0000000..c1d9010 --- /dev/null +++ b/packages/capnp-ts/src/rpc/fulfiller/embargo-client.ts @@ -0,0 +1,102 @@ +import { Client } from "../client"; +import { Queue } from "../queue"; +import { Ecalls, ecallSlot } from "./ecalls"; +import { Struct } from "../../serialization/pointers/struct"; +import { Fulfiller } from "./fulfiller"; +import { Answer } from "../answer"; +import { Call, copyCall } from "../call"; +import { RPC_CALL_QUEUE_FULL, RPC_QUEUE_CALL_CANCEL, INVARIANT_UNREACHABLE_CODE } from "../../errors"; +import { ErrorAnswer } from "../error-answer"; + +export class EmbargoClient implements Client { + _client: Client; + + q: Queue; + calls: Ecalls; + + constructor(client: Client, queue: Ecalls) { + this._client = client; + this.calls = queue.copy(); + this.q = new Queue(this.calls, this.calls.len()); + this.flushQueue(); + } + + flushQueue(): void { + let c: ecallSlot = null; + { + const i = this.q.front(); + if (i !== -1) { + c = this.calls.data[i]; + } + } + + while (c && c.call) { + const ans = this._client.call(c.call); + void (async (f: Fulfiller, ans: Answer) => { + try { + f.fulfill(await ans.struct()); + } catch (e) { + f.reject(e as Error); + } + })(c.f, ans); + this.q.pop(); + { + const i = this.q.front(); + if (i !== -1) { + c = this.calls.data[i]; + } else { + c = null; + } + } + } + } + + // client returns the underlying client if the embargo has + // been lifted and null otherwise + client(): Client | null { + return this.isPassthrough() ? this._client : null; + } + + isPassthrough(): boolean { + return this.q.len() === 0; + } + + // call either queues a call to the underlying client or starts a + // call if the embargo has been lifted + call

(call: Call): Answer { + // Fast path: queue is flushed + if (this.isPassthrough()) { + return this._client.call(call); + } + + // Add to queue + return this.push(call); + } + + push

(_call: Call): Answer { + const f = new Fulfiller(); + const call = copyCall(_call); + const i = this.q.push(); + if (i === -1) { + return new ErrorAnswer(new Error(RPC_CALL_QUEUE_FULL)); + } + this.calls.data[i] = { + call, + f, + }; + return f; + } + + close(): void { + // reject all queued calls + while (this.q.len() > 0) { + const first = this.calls.data[this.q.front()]; + if (!first) { + throw new Error(INVARIANT_UNREACHABLE_CODE); + } + first.f.reject(new Error(RPC_QUEUE_CALL_CANCEL)); + this.q.pop(); + } + this._client.close(); + } +} diff --git a/packages/capnp-ts/src/rpc/fulfiller/fulfiller.ts b/packages/capnp-ts/src/rpc/fulfiller/fulfiller.ts new file mode 100644 index 0000000..4f2f0de --- /dev/null +++ b/packages/capnp-ts/src/rpc/fulfiller/fulfiller.ts @@ -0,0 +1,128 @@ +import { Struct } from "../../serialization/pointers/struct"; +import { Answer } from "../../rpc/answer"; +import { Deferred } from "../deferred"; +import { ImmediateAnswer } from "../immediate-answer"; +import { EmbargoClient } from "./embargo-client"; +import { Ecalls, pcall } from "./ecalls"; +import { Call, copyCall } from "../call"; +import { PipelineOp } from "../pipeline-op"; +import { RPC_CALL_QUEUE_FULL, RPC_NULL_CLIENT, INVARIANT_UNREACHABLE_CODE } from "../../errors"; +import { Pointer } from "../../serialization/pointers/pointer"; +import { transformPtr } from "../transform-ptr"; +import { ErrorAnswer } from "../error-answer"; +import { Interface } from "../../serialization/pointers/interface"; + +const callQueueSize = 64; + +// Fulfiller is a promise for a Struct. It starts out +// as an unresolved answer. A Fulfiller is considered to be resolved +// once fulfill or reject is called. Calls to the fulfiller will queue +// up until it is resolved. +export class Fulfiller implements Answer { + resolved = false; + answer?: Answer; + queue: pcall[] = []; + queueCap = callQueueSize; + deferred = new Deferred(); + + fulfill(s: R): void { + this.answer = new ImmediateAnswer(s); + const queues = this.emptyQueue(s); + const msgcap = s.segment.message._capnp; + if (!msgcap.capTable) { + msgcap.capTable = []; + } + const ctab = msgcap.capTable; + + for (const _capIdx of Object.keys(queues)) { + const capIdx = +_capIdx; + const q = queues[capIdx]; + const client = ctab[capIdx]; + if (!client) { + throw new Error(INVARIANT_UNREACHABLE_CODE); + } + ctab[capIdx] = new EmbargoClient(client, q); + } + this.deferred.resolve(s); + } + + reject(err: Error): void { + this.deferred.reject(err); + } + + peek(): Answer | undefined { + return this.answer; + } + + async struct(): Promise { + return await this.deferred.promise; + } + + // pipelineCall calls pipelineCall on the fulfilled answer or + // queues the call if f has not been fulfilled + pipelineCall( + transform: PipelineOp[], + call: Call + ): Answer { + // Fast path: pass-through after fulfilled + { + const a = this.peek(); + if (a) { + return a.pipelineCall(transform, call); + } + } + + if (this.queue.length === this.queueCap) { + return new ErrorAnswer(new Error(RPC_CALL_QUEUE_FULL)); + } + const cc = copyCall(call); + const g = new Fulfiller(); + this.queue.push({ + call: cc, + f: g, + transform, + }); + return g; + } + + // pipelineClose waits until f is resolved and then calls + // pipelineClose on the fulfilled answer + // FIXME: should this be async? + pipelineClose(transform: PipelineOp[]): void { + const onFinally = () => { + if (this.answer) { + this.answer.pipelineClose(transform); + } + }; + this.deferred.promise.then(onFinally, onFinally); + } + + // emptyQueue splits the queue by which capability it targets and + // drops any invalid calls. Once this function returns, f.queue will + // be nil. + emptyQueue(s: Struct): Record { + const qs: { [key: number]: Ecalls } = {}; + for (let i = 0; i < this.queue.length; i++) { + const pc = this.queue[i]; + let c: Pointer; + try { + c = transformPtr(s, pc.transform); + } catch (e) { + pc.f.reject(e as Error); + continue; + } + const iface = Interface.fromPointer(c); + if (!iface) { + pc.f.reject(new Error(RPC_NULL_CLIENT)); + continue; + } + const cn = iface.getCapId(); + if (!qs[cn]) { + qs[cn] = new Ecalls([]); + } + qs[cn].data.push(pc); + } + this.queue = []; + return qs; + } +} diff --git a/packages/capnp-ts/src/rpc/idgen.ts b/packages/capnp-ts/src/rpc/idgen.ts new file mode 100644 index 0000000..8530bab --- /dev/null +++ b/packages/capnp-ts/src/rpc/idgen.ts @@ -0,0 +1,14 @@ +// IDGen returns a sequence of monotonically increasing IDs +// with support for replacement. +export class IDGen { + i = 0; + free: number[] = []; + + next(): number { + return this.free.pop() ?? this.i++; + } + + remove(i: number): void { + this.free.push(i); + } +} diff --git a/packages/capnp-ts/src/rpc/immediate-answer.ts b/packages/capnp-ts/src/rpc/immediate-answer.ts new file mode 100644 index 0000000..a600277 --- /dev/null +++ b/packages/capnp-ts/src/rpc/immediate-answer.ts @@ -0,0 +1,36 @@ +import { FixedAnswer } from "./fixed-answer"; +import { Struct, getInterfaceClientOrNull } from "../serialization/pointers/struct"; +import { PipelineOp } from "./pipeline-op"; +import { Client } from "./client"; +import { transformPtr } from "./transform-ptr"; +import { Call } from "./call"; +import { Answer } from "./answer"; + +export class ImmediateAnswer extends FixedAnswer { + s: R; + + constructor(s: R) { + super(); + this.s = s; + } + + structSync(): R { + return this.s; + } + + findClient(transform: PipelineOp[]): Client { + const p = transformPtr(this.s, transform); + return getInterfaceClientOrNull(p); + } + + pipelineCall( + transform: PipelineOp[], + call: Call + ): Answer { + return this.findClient(transform).call(call); + } + + pipelineClose(transform: PipelineOp[]): void { + this.findClient(transform).close(); + } +} diff --git a/packages/capnp-ts/src/rpc/import-client.ts b/packages/capnp-ts/src/rpc/import-client.ts new file mode 100644 index 0000000..b1346d8 --- /dev/null +++ b/packages/capnp-ts/src/rpc/import-client.ts @@ -0,0 +1,46 @@ +import { Conn } from "./conn"; +import { Client } from "./client"; +import { Struct } from "../serialization/pointers/struct"; +import { Call } from "./call"; +import { Answer } from "./answer"; +import { ErrorAnswer } from "./error-answer"; +import { newMessage } from "./capability"; +import { RPC_IMPORT_CLOSED } from "../errors"; + +// An ImportClient implements Client for a remote capability. +export class ImportClient implements Client { + conn: Conn; + id: number; + closed = false; + + constructor(conn: Conn, id: number) { + this.conn = conn; + this.id = id; + } + + call(cl: Call): Answer { + if (this.closed) { + return new ErrorAnswer(new Error(RPC_IMPORT_CLOSED)); + } + + const q = this.conn.newQuestion(cl.method); + const msg = newMessage(); + const msgCall = msg.initCall(); + msgCall.setQuestionId(q.id); + msgCall.setInterfaceId(cl.method.interfaceId); + msgCall.setMethodId(cl.method.methodId); + const target = msgCall.initTarget(); + target.setImportedCap(this.id); + const payload = msgCall.initParams(); + this.conn.fillParams(payload, cl); + // TODO: handle thrown exceptions here? + + this.conn.sendMessage(msg); + // TODO: what about q.start()? + return q; + } + + close(): void { + // TODO: figure out + } +} diff --git a/packages/capnp-ts/src/rpc/index.ts b/packages/capnp-ts/src/rpc/index.ts new file mode 100644 index 0000000..f36b785 --- /dev/null +++ b/packages/capnp-ts/src/rpc/index.ts @@ -0,0 +1,11 @@ +export * from "./call"; +export * from "./client"; +export * from "./conn"; +export * from "./deferred"; +export * from "./error-client"; +export * from "./method"; +export * from "./pipeline"; +export * from "./registry"; +export * from "./rpc-message"; +export * from "./server"; +export * from "./transport"; diff --git a/packages/capnp-ts/src/rpc/join.ts b/packages/capnp-ts/src/rpc/join.ts new file mode 100644 index 0000000..65d41da --- /dev/null +++ b/packages/capnp-ts/src/rpc/join.ts @@ -0,0 +1,18 @@ +import { Struct } from "../serialization/pointers/struct"; +import { Answer } from "./answer"; + +export interface FulfillerLike { + fulfill(r: R): void; + reject(err: Error): void; +} + +export function joinAnswer(fl: FulfillerLike, answer: Answer): void { + answer + .struct() + .then((obj) => { + fl.fulfill(obj); + }) + .catch((err) => { + fl.reject(err); + }); +} diff --git a/packages/capnp-ts/src/rpc/local-answer-client.ts b/packages/capnp-ts/src/rpc/local-answer-client.ts new file mode 100644 index 0000000..3544fc2 --- /dev/null +++ b/packages/capnp-ts/src/rpc/local-answer-client.ts @@ -0,0 +1,35 @@ +import { AnswerEntry, Answer } from "./answer"; +import { PipelineOp } from "./pipeline-op"; +import { Struct } from "../serialization/pointers/struct"; +import { Call } from "./call"; +import { Fulfiller } from "./fulfiller/fulfiller"; +import { Client, clientFromResolution } from "./client"; +import { NOT_IMPLEMENTED } from "../errors"; + +/** + * A localAnswerClient is used to provide a pipelined client of an answer. + */ +export class LocalAnswerClient implements Client { + a: AnswerEntry; + transform: PipelineOp[]; + + constructor(a: AnswerEntry, transform: PipelineOp[]) { + this.a = a; + this.transform = transform; + } + + call

(call: Call): Answer { + if (this.a.done) { + return clientFromResolution(this.transform, this.a.obj, this.a.err).call(call); + } + const f = new Fulfiller(); + // TODO: unstub + throw new Error(NOT_IMPLEMENTED); + return f; + } + + close(): void { + // TODO: unstub + throw new Error(NOT_IMPLEMENTED); + } +} diff --git a/packages/capnp-ts/src/rpc/method-error.ts b/packages/capnp-ts/src/rpc/method-error.ts new file mode 100644 index 0000000..75cd087 --- /dev/null +++ b/packages/capnp-ts/src/rpc/method-error.ts @@ -0,0 +1,13 @@ +import { Method } from "./method"; +import { Struct } from "../serialization/pointers/struct"; +import { format } from "../util"; +import { RPC_METHOD_ERROR } from "../errors"; + +export class MethodError

extends Error { + method: Method; + + constructor(method: Method, message: string) { + super(format(RPC_METHOD_ERROR, method.interfaceName, method.methodName, message)); + this.method = method; + } +} diff --git a/packages/capnp-ts/src/rpc/method.ts b/packages/capnp-ts/src/rpc/method.ts new file mode 100644 index 0000000..de397c5 --- /dev/null +++ b/packages/capnp-ts/src/rpc/method.ts @@ -0,0 +1,16 @@ +import { Struct, StructCtor } from "../serialization/pointers/struct"; + +// A Method identifies a method along with an optional +// human-readable description of the method +export interface Method

{ + interfaceId: bigint; + methodId: number; + + // Canonical name of the interface. May be empty. + interfaceName?: string; + // Method name as it appears in the schema. May be empty. + methodName?: string; + + ParamsClass: StructCtor

; + ResultsClass: StructCtor; +} diff --git a/packages/capnp-ts/src/rpc/pipeline-client.ts b/packages/capnp-ts/src/rpc/pipeline-client.ts new file mode 100644 index 0000000..fb92a74 --- /dev/null +++ b/packages/capnp-ts/src/rpc/pipeline-client.ts @@ -0,0 +1,33 @@ +import { Pipeline } from "./pipeline"; +import { Struct } from "../serialization/pointers/struct"; +import { Client } from "./client"; +import { PipelineOp } from "./pipeline-op"; +import { Call } from "./call"; +import { Answer } from "./answer"; + +/** + * PipelineClient implements Client by calling to the pipeline's answer. + */ +export class PipelineClient + implements Client +{ + pipeline: Pipeline; + + constructor(pipeline: Pipeline) { + this.pipeline = pipeline; + } + + transform(): PipelineOp[] { + return this.pipeline.transform(); + } + + call( + call: Call + ): Answer { + return this.pipeline.answer.pipelineCall(this.transform(), call); + } + + close(): void { + this.pipeline.answer.pipelineClose(this.transform()); + } +} diff --git a/packages/capnp-ts/src/rpc/pipeline-op.ts b/packages/capnp-ts/src/rpc/pipeline-op.ts new file mode 100644 index 0000000..9513270 --- /dev/null +++ b/packages/capnp-ts/src/rpc/pipeline-op.ts @@ -0,0 +1,8 @@ +import { Pointer } from "../serialization/pointers/pointer"; + +// A PipelineOp describes a step in transforming a pipeline. +// It maps closely with the PromisedAnswer.Op struct in rpc.capnp. +export interface PipelineOp { + field: number; + defaultValue?: Pointer; +} diff --git a/packages/capnp-ts/src/rpc/pipeline.ts b/packages/capnp-ts/src/rpc/pipeline.ts new file mode 100644 index 0000000..5a834cc --- /dev/null +++ b/packages/capnp-ts/src/rpc/pipeline.ts @@ -0,0 +1,81 @@ +import { PipelineClient } from "./pipeline-client"; +import { Struct, StructCtor } from "../serialization/pointers/struct"; +import { Answer } from "./answer"; +import { PipelineOp } from "./pipeline-op"; +import { transformPtr } from "./transform-ptr"; +import { Pointer } from "../serialization/pointers/pointer"; + +// TODO: figure out if we can respect no-any. +// It doesn't appear so because PipelineOp has just +// a field index, so we have no typing information. + +/** + * A Pipeline is a generic wrapper for an answer + */ +export class Pipeline { + ResultsClass: StructCtor; + answer: Answer; + op: PipelineOp; + parent?: Pipeline; + pipelineClient?: PipelineClient; + + // Returns a new Pipeline based on an answer + constructor( + ResultsClass: StructCtor, + answer: Answer, + op: PipelineOp = { field: 0 }, + parent?: Pipeline + ) { + this.ResultsClass = ResultsClass; + this.answer = answer; + this.op = op; + this.parent = parent; + } + + // transform returns the operations needed to transform the root answer + // into the value p represents. + transform(): PipelineOp[] { + const xform: PipelineOp[] = []; + for ( + // eslint-disable-next-line @typescript-eslint/no-this-alias, @typescript-eslint/no-explicit-any + let q: Pipeline | null = this; + q.parent; + q = q.parent + ) { + xform.unshift(q.op); + } + return xform; + } + + // Struct waits until the answer is resolved and returns the struct + // this pipeline represents. + async struct(): Promise { + const s = await this.answer.struct(); + const t = transformPtr(s, this.transform()); + if (!t) { + if (this.op.defaultValue) { + Pointer.copyFrom(this.op.defaultValue, t); + } else { + Struct.initStruct(this.ResultsClass._capnp.size, t); + } + } + return Struct.getAs(this.ResultsClass, t); + } + + // client returns the client version of this pipeline + client(): PipelineClient { + if (!this.pipelineClient) { + this.pipelineClient = new PipelineClient(this); + } + return this.pipelineClient; + } + + // getPipeline returns a derived pipeline which yields the pointer field given + getPipeline( + ResultsClass: StructCtor, + off: number, + defaultValue?: Pointer + ): Pipeline { + return new Pipeline(ResultsClass, this.answer, { field: off, defaultValue }, this); + } +} diff --git a/packages/capnp-ts/src/rpc/pointer-to-struct.ts b/packages/capnp-ts/src/rpc/pointer-to-struct.ts new file mode 100644 index 0000000..68db629 --- /dev/null +++ b/packages/capnp-ts/src/rpc/pointer-to-struct.ts @@ -0,0 +1,19 @@ +import { + Pointer, + getTargetPointerType +} from "../serialization/pointers/pointer"; +import { Struct } from "../serialization/pointers/struct"; +import { PointerType } from "../serialization/pointers/pointer-type"; + +// TODO: this was ported from the Go codebase, is it really needed? +export function pointerToStruct(p: Pointer): Struct | null { + if (getTargetPointerType(p) === PointerType.STRUCT) { + return new Struct( + p.segment, + p.byteOffset, + p._capnp.depthLimit, + p._capnp.compositeIndex + ); + } + return null; +} diff --git a/packages/capnp-ts/src/rpc/promised-answer.ts b/packages/capnp-ts/src/rpc/promised-answer.ts new file mode 100644 index 0000000..35e06d4 --- /dev/null +++ b/packages/capnp-ts/src/rpc/promised-answer.ts @@ -0,0 +1,33 @@ +import { PipelineOp } from "./pipeline-op"; +import { PromisedAnswer, PromisedAnswer_Op } from "../std/rpc.capnp"; +import { List } from "../serialization/pointers/list"; + +export function transformToPromisedAnswer(answer: PromisedAnswer, transform: PipelineOp[]): void { + const opList = answer.initTransform(transform.length); + for (let i = 0; i < transform.length; i++) { + const op = transform[i]; + opList.get(i).setGetPointerField(op.field); + } +} + +export function promisedAnswerOpsToTransform(list: List): PipelineOp[] { + const transform: PipelineOp[] = []; + list.forEach((op) => { + switch (op.which()) { + case PromisedAnswer_Op.GET_POINTER_FIELD: { + transform.push({ + field: op.getGetPointerField(), + }); + break; + } + case PromisedAnswer_Op.NOOP: { + // no-op + break; + } + default: { + // nothing + } + } + }); + return transform; +} diff --git a/packages/capnp-ts/src/rpc/qcalls.ts b/packages/capnp-ts/src/rpc/qcalls.ts new file mode 100644 index 0000000..de37856 --- /dev/null +++ b/packages/capnp-ts/src/rpc/qcalls.ts @@ -0,0 +1,27 @@ +import { AnswerQCall } from "./answer"; + +export type QCallSlot = AnswerQCall | null; + +export class Qcalls { + data: QCallSlot[]; + + constructor(data: QCallSlot[]) { + this.data = data; + } + + static copyOf(data: QCallSlot[]): Qcalls { + return new Qcalls([...data]); + } + + len(): number { + return this.data.length; + } + + clear(i: number): void { + this.data[i] = null; + } + + copy(): Qcalls { + return Qcalls.copyOf(this.data); + } +} diff --git a/packages/capnp-ts/src/rpc/question.ts b/packages/capnp-ts/src/rpc/question.ts new file mode 100644 index 0000000..d98bb49 --- /dev/null +++ b/packages/capnp-ts/src/rpc/question.ts @@ -0,0 +1,148 @@ +import { Struct } from "../serialization/pointers/struct"; +import { Answer } from "./answer"; +import { Conn } from "./conn"; +import { Method } from "./method"; +import { PipelineOp } from "./pipeline-op"; +import { Deferred } from "./deferred"; +import { Call } from "./call"; +import { clientFromResolution } from "./client"; +import { newMessage } from "./capability"; +import { transformToPromisedAnswer } from "./promised-answer"; +import { Pointer } from "../serialization/pointers/pointer"; +import { NOT_IMPLEMENTED, RPC_FULFILL_ALREADY_CALLED } from "../errors"; +import initTrace from "debug"; + +const trace = initTrace("capnp:rpc:question"); + +export enum QuestionState { + IN_PROGRESS, + RESOLVED, + CANCELED, +} + +export class Question

implements Answer { + conn: Conn; + id: number; + method?: Method; + paramCaps: number[] = []; + state = QuestionState.IN_PROGRESS; + obj?: R; + err?: Error; + derived: PipelineOp[][] = []; + deferred = new Deferred(); + + constructor(conn: Conn, id: number, method?: Method) { + this.conn = conn; + this.id = id; + this.method = method; + } + + async struct(): Promise { + return await this.deferred.promise; + } + + // start signals the question has been sent + start(): void { + // TODO: send finishMessage in case it gets cancelled + // see https://sourcegraph.com/github.com/capnproto/go-capnproto2@e1ae1f982d9908a41db464f02861a850a0880a5a/-/blob/rpc/question.go#L77 + } + + // fulfill is called to resolve a question successfully. + // The caller must be holding onto q.conn.mu. + fulfill(obj: Pointer): void { + // TODO: derived, see https://sourcegraph.com/github.com/capnproto/go-capnproto2@e1ae1f982d9908a41db464f02861a850a0880a5a/-/blob/rpc/question.go#L105 + if (this.state !== QuestionState.IN_PROGRESS) { + throw new Error(RPC_FULFILL_ALREADY_CALLED); + } + if (this.method) { + this.obj = Struct.getAs(this.method.ResultsClass, obj); + } else { + // ugly, but when bootstrapping, method is null + trace("method is null"); + this.obj = obj as R; + } + this.state = QuestionState.RESOLVED; + this.deferred.resolve(this.obj); + } + + // reject is called to resolve a question with failure + reject(err: Error): void { + if (!err) { + throw new Error(`Question.reject called with null`); + } + if (this.state !== QuestionState.IN_PROGRESS) { + throw new Error(`Question.reject called more than once`); + } + this.err = err; + this.state = QuestionState.RESOLVED; + this.deferred.reject(err); + } + + // cancel is called to resolve a question with cancellation. + cancel(err: Error): boolean { + if (this.state === QuestionState.IN_PROGRESS) { + this.err = err; + this.state = QuestionState.CANCELED; + this.deferred.reject(err); + return true; + } + return false; + } + + pipelineCall( + transform: PipelineOp[], + ccall: Call + ): Answer { + if (this.conn.findQuestion(this.id) !== this) { + if (this.state === QuestionState.IN_PROGRESS) { + throw new Error(`question popped but not done`); + } + + const client = clientFromResolution(transform, this.obj, this.err); + // TODO: check that this is fine - this was conn.lockedCall + return client.call(ccall); + } + + const pipeq = this.conn.newQuestion(ccall.method); + const msg = newMessage(); + const msgCall = msg.initCall(); + msgCall.setQuestionId(pipeq.id); + msgCall.setInterfaceId(ccall.method.interfaceId); + msgCall.setMethodId(ccall.method.methodId); + const target = msgCall.initTarget(); + const a = target.initPromisedAnswer(); + a.setQuestionId(this.id); + transformToPromisedAnswer(a, transform); + const payload = msgCall.initParams(); + this.conn.fillParams(payload, ccall); + this.conn.sendMessage(msg); + this.addPromise(transform); + return pipeq; + } + + addPromise(transform: PipelineOp[]): void { + for (const d of this.derived) { + if (transformsEqual(transform, d)) { + return; + } + } + this.derived.push(transform); + } + + pipelineClose(): void { + throw new Error(NOT_IMPLEMENTED); + } +} + +export function transformsEqual(t: PipelineOp[], u: PipelineOp[]): boolean { + if (t.length !== u.length) { + return false; + } + + for (let i = 0; i < t.length; i++) { + if (t[i].field !== u[i].field) { + return false; + } + } + return true; +} diff --git a/packages/capnp-ts/src/rpc/queue-client.ts b/packages/capnp-ts/src/rpc/queue-client.ts new file mode 100644 index 0000000..bfaee86 --- /dev/null +++ b/packages/capnp-ts/src/rpc/queue-client.ts @@ -0,0 +1,121 @@ +import { Client } from "./client"; +import { Conn } from "./conn"; +import { AnswerQCall, Answer, isRemoteCall, isLocalCall, isDisembargo } from "./answer"; +import { Struct } from "../serialization"; +import { Fulfiller } from "./fulfiller/fulfiller"; +import { copyCall, Call } from "./call"; +import { ErrorAnswer } from "./error-answer"; +import { Queue } from "./queue"; +import { Qcalls, QCallSlot } from "./qcalls"; +import { RPC_CALL_QUEUE_FULL } from "../errors"; +import { MessageTarget, Disembargo_Context_Which } from "../std/rpc.capnp"; +import { newDisembargoMessage } from "./capability"; +import { joinAnswer } from "./join"; + +// callQueueSize is the maximum number of calls that can be queued per answer or client. +export const callQueueSize = 64; + +export class QueueClient implements Client { + _client: Client; + conn: Conn; + calls: Qcalls; + q: Queue; + + constructor(conn: Conn, client: Client, calls: AnswerQCall[]) { + this.conn = conn; + this._client = client; + this.calls = Qcalls.copyOf(calls); + this.q = new Queue(this.calls, callQueueSize); + } + + pushCall

(call: Call): Answer { + const f = new Fulfiller(); + try { + call = copyCall(call); + } catch (err) { + return new ErrorAnswer(err as Error); + } + const i = this.q.push(); + if (i === -1) { + return new ErrorAnswer(new Error(RPC_CALL_QUEUE_FULL)); + } + this.calls.data[i] = { + call, + f, + }; + return f; + } + + pushEmbargo(id: number, tgt: MessageTarget): void { + const i = this.q.push(); + if (i === -1) { + throw new Error(RPC_CALL_QUEUE_FULL); + } + this.calls.data[i] = { + embargoID: id, + embargoTarget: tgt, + }; + } + + flushQueue(): void { + let c: QCallSlot = null; + { + const i = this.q.front(); + if (i !== -1) { + c = this.calls.data[i]; + } + } + + while (c) { + this.handle(c); + this.q.pop(); + + { + const i = this.q.front(); + if (i !== -1) { + c = this.calls.data[i]; + } else { + c = null; + } + } + } + } + + handle(c: QCallSlot): void { + if (!c) { + return; + } + + if (isRemoteCall(c)) { + const answer = this._client.call(c.call); + joinAnswer(c.a, answer); + } else if (isLocalCall(c)) { + const answer = this._client.call(c.call); + joinAnswer(c.f, answer); + } else if (isDisembargo(c)) { + const msg = newDisembargoMessage(Disembargo_Context_Which.RECEIVER_LOOPBACK, c.embargoID); + msg.getDisembargo().setTarget(c.embargoTarget); + this.conn.sendMessage(msg); + } + } + + isPassthrough(): boolean { + return this.q.len() === 0; + } + + call

(call: Call): Answer { + // Fast path: queue is flushed + if (this.isPassthrough()) { + return this._client.call(call); + } + + // Add to queue + return this.pushCall(call); + } + + // close releases any resources associated with this client. + // No further calls to the client should be made after calling Close. + close(): void { + // muffin + } +} diff --git a/packages/capnp-ts/src/rpc/queue.ts b/packages/capnp-ts/src/rpc/queue.ts new file mode 100644 index 0000000..0ba5a34 --- /dev/null +++ b/packages/capnp-ts/src/rpc/queue.ts @@ -0,0 +1,60 @@ +// A Queue wraps a QueueStorage to provide queue operations. +export class Queue { + q: QueueStorage; + start: number; + n: number; + cap: number; + + // creates a new queue that starts with n elements. + // The interface's length must not change over the course of + // the queue's usage. + constructor(q: QueueStorage, n: number) { + this.q = q; + this.start = 0; + this.n = n; + this.cap = q.len(); + } + + // len returns the length of the queue. This is different from the underlying + // interface's length, which is the queue's capacity. + len(): number { + return this.n; + } + + // push reserves space for an element on the queue, returning its index. + // if the queue is full, push returns -1. + push(): number { + if (this.n >= this.cap) { + return -1; + } + const i = (this.start + this.n) % this.cap; + this.n++; + return i; + } + + // front returns the index of the front of the queue, or -1 if the queue is empty. + front(): number { + if (this.n === 0) { + return -1; + } + return this.start; + } + + // pop pops an element from the queue, returning whether it succeeded. + pop(): boolean { + if (this.n === 0) { + return false; + } + this.q.clear(this.start); + this.start = (this.start + 1) % this.cap; + this.n--; + return true; + } +} + +export interface QueueStorage { + // len returns the number of elements available + len(): number; + // clear removes the element at i + clear(i: number): void; +} diff --git a/packages/capnp-ts/src/rpc/ref.ts b/packages/capnp-ts/src/rpc/ref.ts new file mode 100644 index 0000000..a11c164 --- /dev/null +++ b/packages/capnp-ts/src/rpc/ref.ts @@ -0,0 +1,39 @@ +import { Client } from "./client"; +import { RefCount } from "./refcount"; +import { Finalize } from "./finalize"; +import { Struct } from "../serialization/pointers/struct"; +import { Call } from "./call"; +import { Answer } from "./answer"; + +// A Ref is a single reference to a client wrapped by RefCount. +export class Ref implements Client { + rc: RefCount; + closeState: { closed: boolean }; + + constructor(rc: RefCount, finalize: Finalize) { + this.rc = rc; + const closeState = { closed: false }; + this.closeState = closeState; + finalize(this, () => { + if (!closeState.closed) { + closeState.closed = true; + rc.decref(); + } + }); + } + + call

(cl: Call): Answer { + return this.rc.call(cl); + } + + client(): Client { + return this.rc._client; + } + + close(): void { + if (!this.closeState.closed) { + this.closeState.closed = true; + this.rc.decref(); + } + } +} diff --git a/packages/capnp-ts/src/rpc/refcount.ts b/packages/capnp-ts/src/rpc/refcount.ts new file mode 100644 index 0000000..7965759 --- /dev/null +++ b/packages/capnp-ts/src/rpc/refcount.ts @@ -0,0 +1,62 @@ +import { Client } from "./client"; +import { Struct } from "../serialization/pointers/struct"; +import { Call } from "./call"; +import { Answer } from "./answer"; +import { ErrorClient } from "./error-client"; +import { RPC_ZERO_REF } from "../errors"; +import { Ref } from "./ref"; +import { Finalize } from "./finalize"; + +/** + * A RefCount will close its underlying client once all its references are + * closed. + */ +export class RefCount implements Client { + refs: number; + finalize: Finalize; + _client: Client; + + private constructor(c: Client, _finalize: Finalize) { + this._client = c; + this.finalize = _finalize; + this.refs = 1; + } + + // New creates a reference counter and the first client reference. + static new(c: Client, finalize: Finalize): [RefCount, Ref] { + const rc = new RefCount(c, finalize); + const ref = rc.newRef(); + return [rc, ref]; + } + + call

(cl: Call): Answer { + return this._client.call(cl); + } + + client(): Client { + return this._client; + } + + close(): void { + this._client.close(); + } + + ref(): Client { + if (this.refs <= 0) { + return new ErrorClient(new Error(RPC_ZERO_REF)); + } + this.refs++; + return this.newRef(); + } + + newRef(): Ref { + return new Ref(this, this.finalize); + } + + decref(): void { + this.refs--; + if (this.refs === 0) { + this._client.close(); + } + } +} diff --git a/packages/capnp-ts/src/rpc/registry.ts b/packages/capnp-ts/src/rpc/registry.ts new file mode 100644 index 0000000..983a03b --- /dev/null +++ b/packages/capnp-ts/src/rpc/registry.ts @@ -0,0 +1,20 @@ +import { Method } from "./method"; + +interface InterfaceDefinition { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + methods: Array>; +} + +// Registry keeps track of all interfaces so calls +// can be dispatched properly. +export class Registry { + static readonly interfaces: Map = new Map(); + + static register(id: bigint, def: InterfaceDefinition): void { + this.interfaces.set(id, def); + } + + static lookup(id: bigint): InterfaceDefinition | undefined { + return this.interfaces.get(id); + } +} diff --git a/packages/capnp-ts/src/rpc/rpc-error.ts b/packages/capnp-ts/src/rpc/rpc-error.ts new file mode 100644 index 0000000..0d76673 --- /dev/null +++ b/packages/capnp-ts/src/rpc/rpc-error.ts @@ -0,0 +1,22 @@ +import { RPC_ERROR } from "../errors"; +import { Exception } from "../std/rpc.capnp"; +import { format } from "../util"; + +export class RPCError extends Error { + exception: Exception; + + constructor(exception: Exception) { + super(format(RPC_ERROR, exception.getReason())); + this.exception = exception; + } +} + +export function toException(exc: Exception, err: Error): void { + if (err instanceof RPCError) { + exc.setReason(exc.getReason()); + exc.setType(exc.getType()); + return; + } + exc.setReason(err.message); + exc.setType(Exception.Type.FAILED); +} diff --git a/packages/capnp-ts/src/rpc/rpc-message.ts b/packages/capnp-ts/src/rpc/rpc-message.ts new file mode 100644 index 0000000..2e70508 --- /dev/null +++ b/packages/capnp-ts/src/rpc/rpc-message.ts @@ -0,0 +1 @@ +export { Message as RPCMessage } from "../std/rpc.capnp"; diff --git a/packages/capnp-ts/src/rpc/server.ts b/packages/capnp-ts/src/rpc/server.ts new file mode 100644 index 0000000..43c632c --- /dev/null +++ b/packages/capnp-ts/src/rpc/server.ts @@ -0,0 +1,62 @@ +import { Method } from "./method"; +import { Struct } from "../serialization/pointers/struct"; +import { Message } from "../serialization/message"; +import { DataCall, Call, copyCall } from "./call"; +import { Fulfiller } from "./fulfiller/fulfiller"; +import { Client } from "./client"; +import { Answer } from "./answer"; +import { ErrorAnswer } from "./error-answer"; +import { MethodError } from "./method-error"; +import { RPC_METHOD_NOT_IMPLEMENTED } from "../errors"; + +export interface ServerMethod

extends Method { + impl(params: P, results: R): Promise; +} + +export interface ServerCall

extends DataCall { + serverMethod: ServerMethod; + answer: Fulfiller; +} + +// A server is a locally implemented interface +export class Server implements Client { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + target: any; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + methods: Array>; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types + constructor(target: any, methods: Array>) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + this.target = target; + this.methods = methods; + } + + startCall

(call: ServerCall): void { + const msg = new Message(); + const results = msg.initRoot(call.method.ResultsClass); + call.serverMethod.impl + .call(this.target, call.params, results) + .then(() => call.answer.fulfill(results)) + .catch((err) => call.answer.reject(err as Error)); + } + + call

(call: Call): Answer { + const serverMethod = this.methods[call.method.methodId]; + if (!serverMethod) { + return new ErrorAnswer(new MethodError(call.method, RPC_METHOD_NOT_IMPLEMENTED)); + } + const serverCall: ServerCall = { + ...copyCall(call), + answer: new Fulfiller(), + serverMethod, + }; + this.startCall(serverCall); + return serverCall.answer; + } + + close(): void { + // muffin + } +} diff --git a/packages/capnp-ts/src/rpc/transform-ptr.ts b/packages/capnp-ts/src/rpc/transform-ptr.ts new file mode 100644 index 0000000..8b5eb1a --- /dev/null +++ b/packages/capnp-ts/src/rpc/transform-ptr.ts @@ -0,0 +1,22 @@ +import { Pointer } from "../serialization/pointers/pointer"; +import { Struct } from "../serialization/pointers/struct"; +import { pointerToStruct } from "./pointer-to-struct"; +import { PipelineOp } from "./pipeline-op"; + +// transformPtr applies a sequence of pipeline operations to a pointer +// and returns the result. +export function transformPtr(p: Pointer, transform: PipelineOp[]): Pointer { + if (transform.length === 0) { + return p; + } + let s = pointerToStruct(p); + if (!s) { + return p; + } + + for (const op of transform) { + s = Struct.getPointer(op.field, s); + } + + return s; +} diff --git a/packages/capnp-ts/src/rpc/transport/deferred-transport.ts b/packages/capnp-ts/src/rpc/transport/deferred-transport.ts new file mode 100644 index 0000000..10d9992 --- /dev/null +++ b/packages/capnp-ts/src/rpc/transport/deferred-transport.ts @@ -0,0 +1,35 @@ +import { Message } from "../../serialization"; +import { Deferred } from "../deferred"; +import { RPCMessage } from "../rpc-message"; +import { Transport } from "../transport"; + +export abstract class DeferredTransport implements Transport { + protected d?: Deferred; + protected closed = false; + + abstract sendMessage(msg: RPCMessage): void; + + close(): void { + this.closed = true; + this.d?.reject(); + } + + recvMessage(): Promise { + if (this.closed) return Promise.reject(); + if (this.d) this.d.reject(); + this.d = new Deferred(); + return this.d.promise; + } + + protected reject = (err: unknown): void => { + this.d?.reject(err); + }; + + protected resolve = (buf: ArrayBuffer): void => { + try { + this.d?.resolve(new Message(buf, false).getRoot(RPCMessage)); + } catch (err) { + this.d?.reject(err); + } + }; +} diff --git a/packages/capnp-ts/src/rpc/transport/index.ts b/packages/capnp-ts/src/rpc/transport/index.ts new file mode 100644 index 0000000..864f871 --- /dev/null +++ b/packages/capnp-ts/src/rpc/transport/index.ts @@ -0,0 +1,11 @@ +import { RPCMessage } from "../rpc-message"; + +export * from "./deferred-transport"; +export * from "./message-channel-transport"; +export * from "./test-network"; + +export interface Transport { + sendMessage(msg: RPCMessage): void; + recvMessage(): Promise; + close(): void; +} diff --git a/packages/capnp-ts/src/rpc/transport/message-channel-transport.ts b/packages/capnp-ts/src/rpc/transport/message-channel-transport.ts new file mode 100644 index 0000000..1cb37bc --- /dev/null +++ b/packages/capnp-ts/src/rpc/transport/message-channel-transport.ts @@ -0,0 +1,28 @@ +import { MessagePort } from "worker_threads"; +import { RPCMessage } from ".."; +import { Message } from "../.."; +import { DeferredTransport } from "./deferred-transport"; + +export class MessageChannelTransport extends DeferredTransport { + constructor(public port: MessagePort) { + super(); + this.port.on("message", this.resolve); + this.port.on("messageerror", this.reject); + this.port.on("close", this.close); + } + + close = (): void => { + this.port.off("message", this.resolve); + this.port.off("messageerror", this.reject); + this.port.off("close", this.close); + this.port.close(); + super.close(); + }; + + sendMessage(msg: RPCMessage): void { + const m = new Message(); + m.setRoot(msg); + const buf = m.toArrayBuffer(); + this.port.postMessage(buf, [buf]); + } +} diff --git a/packages/capnp-ts/src/rpc/transport/test-network.ts b/packages/capnp-ts/src/rpc/transport/test-network.ts new file mode 100644 index 0000000..fdead7b --- /dev/null +++ b/packages/capnp-ts/src/rpc/transport/test-network.ts @@ -0,0 +1,56 @@ +import { MessagePort, MessageChannel } from "worker_threads"; +import { Deferred, Conn } from ".."; +import { MessageChannelTransport } from "./message-channel-transport"; + +export class TestNetwork { + static acceptQueue = new Array>(); + static connections: Record = {}; + static connectQueue = new Array(); + static onError?: (err: Error | undefined) => void; + + static connect(id = 0): Conn { + if (TestNetwork.connections[id] !== undefined) return TestNetwork.connections[id]; + const ch = new MessageChannel(); + const conn = new Conn(new MessageChannelTransport(ch.port1)); + const accept = TestNetwork.acceptQueue.pop(); + TestNetwork.connections[id] = conn; + + if (accept !== undefined) { + accept.resolve(new Conn(new MessageChannelTransport(ch.port2))); + } else { + TestNetwork.connectQueue.push(ch.port2); + } + + return conn; + } + + static accept(): Promise { + const port2 = TestNetwork.connectQueue.pop(); + if (port2 !== undefined) { + return Promise.resolve(new Conn(new MessageChannelTransport(port2))); + } + const deferred = new Deferred(); + TestNetwork.acceptQueue.push(deferred); + return deferred.promise; + } + + static shutdown(): void { + let i = TestNetwork.acceptQueue.length; + while (--i >= 0) { + TestNetwork.acceptQueue[i].reject(); + } + + i = TestNetwork.connectQueue.length; + while (--i >= 0) { + TestNetwork.connectQueue[i].close(); + } + + for (const id in TestNetwork.connections) { + TestNetwork.connections[id].shutdown(); + } + + TestNetwork.acceptQueue.length = 0; + TestNetwork.connectQueue.length = 0; + TestNetwork.connections = {}; + } +} diff --git a/packages/capnp-ts/src/serialization/arena/arena-allocation-result.ts b/packages/capnp-ts/src/serialization/arena/arena-allocation-result.ts index a2c746c..6a307b3 100644 --- a/packages/capnp-ts/src/serialization/arena/arena-allocation-result.ts +++ b/packages/capnp-ts/src/serialization/arena/arena-allocation-result.ts @@ -2,11 +2,6 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - -const trace = initTrace("capnp:serialization:arena:arena-allocation-result"); -trace("load"); - export class ArenaAllocationResult { /** * The newly allocated buffer. This buffer might be a copy of an existing segment's buffer with free space appended. @@ -27,7 +22,5 @@ export class ArenaAllocationResult { constructor(id: number, buffer: ArrayBuffer) { this.id = id; this.buffer = buffer; - - trace("new", this); } } diff --git a/packages/capnp-ts/src/serialization/arena/arena.ts b/packages/capnp-ts/src/serialization/arena/arena.ts index 1c88859..924a1b4 100644 --- a/packages/capnp-ts/src/serialization/arena/arena.ts +++ b/packages/capnp-ts/src/serialization/arena/arena.ts @@ -2,7 +2,6 @@ * @author jdiaz5513 */ -import initTrace from "debug"; import { assertNever } from "../../errors"; import { Segment } from "../segment"; import { AnyArena } from "./any-arena"; @@ -11,11 +10,9 @@ import { ArenaKind } from "./arena-kind"; import { MultiSegmentArena } from "./multi-segment-arena"; import { SingleSegmentArena } from "./single-segment-arena"; -const trace = initTrace("capnp:arena"); -trace("load"); - export abstract class Arena { static readonly allocate = allocate; + static readonly copy = copy; static readonly getBuffer = getBuffer; static readonly getNumSegments = getNumSegments; } @@ -33,6 +30,24 @@ export function allocate(minSize: number, segments: Segment[], a: AnyArena): Are } } +export function copy(a: AnyArena): AnyArena { + switch (a.kind) { + case ArenaKind.MULTI_SEGMENT: { + let i = a.buffers.length; + const buffers = new Array(i); + while (--i >= 0) { + buffers[i] = a.buffers[i].slice(0); + } + return new MultiSegmentArena(buffers); + } + case ArenaKind.SINGLE_SEGMENT: + return new SingleSegmentArena(a.buffer.slice(0)); + + default: + return assertNever(a); + } +} + export function getBuffer(id: number, a: AnyArena): ArrayBuffer { switch (a.kind) { case ArenaKind.MULTI_SEGMENT: diff --git a/packages/capnp-ts/src/serialization/arena/multi-segment-arena.ts b/packages/capnp-ts/src/serialization/arena/multi-segment-arena.ts index 7a53e1b..507bc71 100644 --- a/packages/capnp-ts/src/serialization/arena/multi-segment-arena.ts +++ b/packages/capnp-ts/src/serialization/arena/multi-segment-arena.ts @@ -2,28 +2,26 @@ * @author jdiaz5513 */ -import initTrace from "debug"; import { DEFAULT_BUFFER_SIZE } from "../../constants"; -import { SEG_ID_OUT_OF_BOUNDS } from "../../errors"; +import { SEG_ID_OUT_OF_BOUNDS, SEG_NOT_WORD_ALIGNED } from "../../errors"; import { padToWord, format } from "../../util"; import { ArenaAllocationResult } from "./arena-allocation-result"; import { ArenaKind } from "./arena-kind"; -const trace = initTrace("capnp:arena:multi"); -trace("load"); - export class MultiSegmentArena { static readonly allocate = allocate; static readonly getBuffer = getBuffer; static readonly getNumSegments = getNumSegments; - readonly buffers: ArrayBuffer[]; readonly kind = ArenaKind.MULTI_SEGMENT; - constructor(buffers: ArrayBuffer[] = []) { - this.buffers = buffers; - - trace("new %s", this); + constructor(readonly buffers = [new ArrayBuffer(DEFAULT_BUFFER_SIZE)]) { + let i = buffers.length; + while (--i >= 0) { + if ((buffers[i].byteLength & 7) !== 0) { + throw new Error(format(SEG_NOT_WORD_ALIGNED, buffers[i].byteLength)); + } + } } toString(): string { diff --git a/packages/capnp-ts/src/serialization/arena/single-segment-arena.ts b/packages/capnp-ts/src/serialization/arena/single-segment-arena.ts index 250568c..ba19701 100644 --- a/packages/capnp-ts/src/serialization/arena/single-segment-arena.ts +++ b/packages/capnp-ts/src/serialization/arena/single-segment-arena.ts @@ -11,24 +11,18 @@ import { ArenaAllocationResult } from "./arena-allocation-result"; import { ArenaKind } from "./arena-kind"; const trace = initTrace("capnp:arena:single"); -trace("load"); export class SingleSegmentArena { static readonly allocate = allocate; static readonly getBuffer = getBuffer; static readonly getNumSegments = getNumSegments; - buffer: ArrayBuffer; readonly kind = ArenaKind.SINGLE_SEGMENT; - constructor(buffer = new ArrayBuffer(DEFAULT_BUFFER_SIZE)) { + constructor(public buffer = new ArrayBuffer(DEFAULT_BUFFER_SIZE)) { if ((buffer.byteLength & 7) !== 0) { throw new Error(format(SEG_NOT_WORD_ALIGNED, buffer.byteLength)); } - - this.buffer = buffer; - - trace("new %s", this); } toString(): string { diff --git a/packages/capnp-ts/src/serialization/message.ts b/packages/capnp-ts/src/serialization/message.ts index 20e56a2..c2de927 100644 --- a/packages/capnp-ts/src/serialization/message.ts +++ b/packages/capnp-ts/src/serialization/message.ts @@ -4,12 +4,7 @@ import initTrace from "debug"; import { DEFAULT_TRAVERSE_LIMIT, DEFAULT_BUFFER_SIZE } from "../constants"; -import { - MSG_INVALID_FRAME_HEADER, - MSG_SEGMENT_OUT_OF_BOUNDS, - MSG_SEGMENT_TOO_SMALL, - MSG_NO_SEGMENTS_IN_ARENA, -} from "../errors"; +import { MSG_INVALID_FRAME_HEADER, MSG_SEGMENT_OUT_OF_BOUNDS, MSG_SEGMENT_TOO_SMALL } from "../errors"; import { dumpBuffer, format, padToWord } from "../util"; import { AnyArena, Arena, MultiSegmentArena, SingleSegmentArena, ArenaKind } from "./arena"; import { pack, unpack } from "./packing"; @@ -17,14 +12,15 @@ import { Pointer, StructCtor, PointerType, Struct } from "./pointers"; import { Segment } from "./segment"; import { getTargetStructSize, validate } from "./pointers/pointer"; import { resize, initStruct } from "./pointers/struct"; +import { Client } from "../rpc/client"; const trace = initTrace("capnp:message"); -trace("load"); export interface _Message { readonly arena: AnyArena; segments: Segment[]; traversalLimit: number; + capTable?: Array; } export class Message { @@ -71,15 +67,22 @@ export class Message { constructor(src?: AnyArena | ArrayBufferView | ArrayBuffer, packed = true, singleSegment = false) { this._capnp = initMessage(src, packed, singleSegment); - if (src && !isAnyArena(src)) preallocateSegments(this); - - trace("new %s", this); + if (src) preallocateSegments(this); } allocateSegment(byteLength: number): Segment { return allocateSegment(byteLength, this); } + /** + * Copies the contents of this message into an identical message with its own ArrayBuffers. + * + * @returns A copy of this message. + */ + copy(): Message { + return copy(this); + } + /** * Create a pretty-printed string dump of this message; incredibly useful for debugging. * @@ -168,6 +171,15 @@ export class Message { // eslint-disable-next-line @typescript-eslint/restrict-template-expressions return `Message_arena:${this._capnp.arena}`; } + + addCap(client: Client | null): number { + if (!this._capnp.capTable) { + this._capnp.capTable = []; + } + const id = this._capnp.capTable.length; + this._capnp.capTable.push(client); + return id; + } } export interface CreateMessageOptions { @@ -192,7 +204,7 @@ export function initMessage( return { arena: src, segments: [], traversalLimit: DEFAULT_TRAVERSE_LIMIT }; } - let buf: ArrayBuffer = src as ArrayBuffer; + let buf = src; if (isArrayBufferView(buf)) { buf = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); @@ -233,8 +245,6 @@ export function getFramedSegments(message: ArrayBuffer): ArrayBuffer[] { const segments = new Array(segmentCount) as ArrayBuffer[]; - trace("reading %d framed segments from stream", segmentCount); - let byteOffset = 4 + segmentCount * 4; byteOffset += byteOffset % 8; @@ -271,13 +281,17 @@ export function getFramedSegments(message: ArrayBuffer): ArrayBuffer[] { export function preallocateSegments(m: Message): void { const numSegments = Arena.getNumSegments(m._capnp.arena); - if (numSegments < 1) throw new Error(MSG_NO_SEGMENTS_IN_ARENA); - m._capnp.segments = new Array(numSegments) as Segment[]; for (let i = 0; i < numSegments; i++) { // Set up each segment so that they're fully allocated to the extents of the existing buffers. + if (i === 0 && Arena.getBuffer(i, m._capnp.arena).byteLength < 8) { + // This is not a valid message if it can't fit a single pointer. + + throw new Error(MSG_SEGMENT_TOO_SMALL); + } + const buffer = Arena.getBuffer(i, m._capnp.arena); const segment = new Segment(i, m, buffer, buffer.byteLength); @@ -294,8 +308,6 @@ function isAnyArena(o: unknown): o is AnyArena { } export function allocateSegment(byteLength: number, m: Message): Segment { - trace("allocating %x bytes for %s", byteLength, m); - const res = Arena.allocate(byteLength, m._capnp.segments, m._capnp.arena); let s: Segment; @@ -305,16 +317,12 @@ export function allocateSegment(byteLength: number, m: Message): Segment { s = new Segment(res.id, m, res.buffer); - trace("adding new segment %s", s); - m._capnp.segments.push(s); } else if (res.id < 0 || res.id > m._capnp.segments.length) { throw new Error(format(MSG_SEGMENT_OUT_OF_BOUNDS, res.id, m)); } else { s = m._capnp.segments[res.id]; - trace("replacing segment %s with buffer (len:%d)", s, res.buffer.byteLength); - s.replaceBuffer(res.buffer); } @@ -402,8 +410,6 @@ export function initRoot(RootStruct: StructCtor, m: Message initStruct(RootStruct._capnp.size, root); - trace("Initialized root pointer %s for %s.", root, m); - return root; } @@ -493,15 +499,15 @@ export function getStreamFrame(m: Message): ArrayBuffer { const frameLength = 4 + length * 4 + (1 - (length % 2)) * 4; const out = new DataView(new ArrayBuffer(frameLength)); - trace("Writing message stream frame with segment count: %d.", length); - out.setUint32(0, length - 1, true); m._capnp.segments.forEach((s, i) => { - trace("Message segment %d word count: %d.", s.id, s.byteLength / 8); - out.setUint32(i * 4 + 4, s.byteLength / 8, true); }); return out.buffer; } + +export function copy(m: Message): Message { + return new Message(Arena.copy(m._capnp.arena)); +} diff --git a/packages/capnp-ts/src/serialization/object-size.ts b/packages/capnp-ts/src/serialization/object-size.ts index 1051a07..3844de4 100644 --- a/packages/capnp-ts/src/serialization/object-size.ts +++ b/packages/capnp-ts/src/serialization/object-size.ts @@ -2,13 +2,8 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import * as _ from "../util"; -const trace = initTrace("capnp:object-size"); -trace("load"); - /** * A simple object that describes the size of a struct. * @@ -31,11 +26,7 @@ export class ObjectSize { } toString(): string { - return _.format( - "ObjectSize_dw:%d,pc:%d", - getDataWordLength(this), - this.pointerLength - ); + return _.format("ObjectSize_dw:%d,pc:%d", getDataWordLength(this), this.pointerLength); } } diff --git a/packages/capnp-ts/src/serialization/pointers/any-struct.ts b/packages/capnp-ts/src/serialization/pointers/any-struct.ts new file mode 100644 index 0000000..9428cbd --- /dev/null +++ b/packages/capnp-ts/src/serialization/pointers/any-struct.ts @@ -0,0 +1,10 @@ +import { ObjectSize } from "../object-size"; +import { Struct } from "./struct"; + +export class AnyStruct extends Struct { + static readonly _capnp = { + displayName: "AnyStruct", + id: "0", + size: new ObjectSize(0, 0), + }; +} diff --git a/packages/capnp-ts/src/serialization/pointers/bool-list.ts b/packages/capnp-ts/src/serialization/pointers/bool-list.ts index 26836bc..73fcdab 100644 --- a/packages/capnp-ts/src/serialization/pointers/bool-list.ts +++ b/packages/capnp-ts/src/serialization/pointers/bool-list.ts @@ -2,19 +2,14 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { ListElementSize } from "../list-element-size"; import { _ListCtor, List } from "./list"; import { getContent } from "./pointer"; -const trace = initTrace("capnp:list:composite"); -trace("load"); - export class BoolList extends List { static readonly _capnp: _ListCtor = { displayName: "List" as string, - size: ListElementSize.BIT + size: ListElementSize.BIT, }; get(index: number): boolean { diff --git a/packages/capnp-ts/src/serialization/pointers/composite-list.ts b/packages/capnp-ts/src/serialization/pointers/composite-list.ts index 6338244..0b4cf1a 100644 --- a/packages/capnp-ts/src/serialization/pointers/composite-list.ts +++ b/packages/capnp-ts/src/serialization/pointers/composite-list.ts @@ -2,16 +2,11 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { ListElementSize } from "../list-element-size"; import { _ListCtor, List, ListCtor } from "./list"; import { Struct, StructCtor } from "./struct"; import { copyFrom } from "./pointer"; -const trace = initTrace("capnp:list:composite"); -trace("load"); - export function CompositeList(CompositeClass: StructCtor): ListCtor { return class extends List { static readonly _capnp: _ListCtor = { diff --git a/packages/capnp-ts/src/serialization/pointers/data.ts b/packages/capnp-ts/src/serialization/pointers/data.ts index bec7df1..90cdd04 100644 --- a/packages/capnp-ts/src/serialization/pointers/data.ts +++ b/packages/capnp-ts/src/serialization/pointers/data.ts @@ -10,7 +10,6 @@ import { Pointer, validate, getContent } from "./pointer"; import { PointerType } from "./pointer-type"; const trace = initTrace("capnp:data"); -trace("load"); /** * A generic blob of bytes. Can be converted to a DataView or Uint8Array to access its contents using `toDataView()` and @@ -29,11 +28,7 @@ export class Data extends List { } protected static _fromPointerUnchecked(pointer: Pointer): Data { - return new this( - pointer.segment, - pointer.byteOffset, - pointer._capnp.depthLimit - ); + return new this(pointer.segment, pointer.byteOffset, pointer._capnp.depthLimit); } /** @@ -56,30 +51,18 @@ export class Data extends List { const i = src instanceof ArrayBuffer ? new Uint8Array(src) - : new Uint8Array( - src.buffer, - src.byteOffset, - Math.min(dstLength, srcLength) - ); + : new Uint8Array(src.buffer, src.byteOffset, Math.min(dstLength, srcLength)); const o = new Uint8Array(c.segment.buffer, c.byteOffset, this.getLength()); o.set(i); if (dstLength > srcLength) { - trace( - "Zeroing out remaining %d bytes after copy into %s.", - dstLength - srcLength, - this - ); + trace("Zeroing out remaining %d bytes after copy into %s.", dstLength - srcLength, this); o.fill(0, srcLength, dstLength); } else if (dstLength < srcLength) { - trace( - "Truncated %d bytes from source buffer while copying to %s.", - srcLength - dstLength, - this - ); + trace("Truncated %d bytes from source buffer while copying to %s.", srcLength - dstLength, this); } } @@ -118,10 +101,7 @@ export class Data extends List { toArrayBuffer(): ArrayBuffer { const c = getContent(this); - return c.segment.buffer.slice( - c.byteOffset, - c.byteOffset + this.getLength() - ); + return c.segment.buffer.slice(c.byteOffset, c.byteOffset + this.getLength()); } /** diff --git a/packages/capnp-ts/src/serialization/pointers/float32-list.ts b/packages/capnp-ts/src/serialization/pointers/float32-list.ts index 7de7f99..14a7eda 100644 --- a/packages/capnp-ts/src/serialization/pointers/float32-list.ts +++ b/packages/capnp-ts/src/serialization/pointers/float32-list.ts @@ -2,19 +2,14 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { ListElementSize } from "../list-element-size"; import { _ListCtor, List } from "./list"; import { getContent } from "./pointer"; -const trace = initTrace("capnp:list:composite"); -trace("load"); - export class Float32List extends List { static readonly _capnp: _ListCtor = { displayName: "List" as string, - size: ListElementSize.BYTE_4 + size: ListElementSize.BYTE_4, }; get(index: number): number { diff --git a/packages/capnp-ts/src/serialization/pointers/float64-list.ts b/packages/capnp-ts/src/serialization/pointers/float64-list.ts index 3dfd4b2..6709b8f 100644 --- a/packages/capnp-ts/src/serialization/pointers/float64-list.ts +++ b/packages/capnp-ts/src/serialization/pointers/float64-list.ts @@ -2,19 +2,14 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { ListElementSize } from "../list-element-size"; import { _ListCtor, List } from "./list"; import { getContent } from "./pointer"; -const trace = initTrace("capnp:list:composite"); -trace("load"); - export class Float64List extends List { static readonly _capnp: _ListCtor = { displayName: "List" as string, - size: ListElementSize.BYTE_8 + size: ListElementSize.BYTE_8, }; get(index: number): number { diff --git a/packages/capnp-ts/src/serialization/pointers/int16-list.ts b/packages/capnp-ts/src/serialization/pointers/int16-list.ts index 45ec4a5..370afbb 100644 --- a/packages/capnp-ts/src/serialization/pointers/int16-list.ts +++ b/packages/capnp-ts/src/serialization/pointers/int16-list.ts @@ -2,19 +2,14 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { ListElementSize } from "../list-element-size"; import { _ListCtor, List } from "./list"; import { getContent } from "./pointer"; -const trace = initTrace("capnp:list:composite"); -trace("load"); - export class Int16List extends List { static readonly _capnp: _ListCtor = { displayName: "List" as string, - size: ListElementSize.BYTE_2 + size: ListElementSize.BYTE_2, }; get(index: number): number { diff --git a/packages/capnp-ts/src/serialization/pointers/int32-list.ts b/packages/capnp-ts/src/serialization/pointers/int32-list.ts index 8e65ad2..a37740f 100644 --- a/packages/capnp-ts/src/serialization/pointers/int32-list.ts +++ b/packages/capnp-ts/src/serialization/pointers/int32-list.ts @@ -2,19 +2,14 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { ListElementSize } from "../list-element-size"; import { _ListCtor, List } from "./list"; import { getContent } from "./pointer"; -const trace = initTrace("capnp:list:composite"); -trace("load"); - export class Int32List extends List { static readonly _capnp: _ListCtor = { displayName: "List" as string, - size: ListElementSize.BYTE_4 + size: ListElementSize.BYTE_4, }; get(index: number): number { diff --git a/packages/capnp-ts/src/serialization/pointers/int64-list.ts b/packages/capnp-ts/src/serialization/pointers/int64-list.ts index d0c06ce..a80da83 100644 --- a/packages/capnp-ts/src/serialization/pointers/int64-list.ts +++ b/packages/capnp-ts/src/serialization/pointers/int64-list.ts @@ -2,15 +2,10 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { ListElementSize } from "../list-element-size"; import { _ListCtor, List } from "./list"; import { getContent } from "./pointer"; -const trace = initTrace("capnp:list:composite"); -trace("load"); - export class Int64List extends List { static readonly _capnp: _ListCtor = { displayName: "List" as string, diff --git a/packages/capnp-ts/src/serialization/pointers/int8-list.ts b/packages/capnp-ts/src/serialization/pointers/int8-list.ts index ccf99eb..19f4b8e 100644 --- a/packages/capnp-ts/src/serialization/pointers/int8-list.ts +++ b/packages/capnp-ts/src/serialization/pointers/int8-list.ts @@ -2,19 +2,14 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { ListElementSize } from "../list-element-size"; import { _ListCtor, List } from "./list"; import { getContent } from "./pointer"; -const trace = initTrace("capnp:list:composite"); -trace("load"); - export class Int8List extends List { static readonly _capnp: _ListCtor = { displayName: "List" as string, - size: ListElementSize.BYTE + size: ListElementSize.BYTE, }; get(index: number): number { diff --git a/packages/capnp-ts/src/serialization/pointers/interface.ts b/packages/capnp-ts/src/serialization/pointers/interface.ts index b283869..74a68a6 100644 --- a/packages/capnp-ts/src/serialization/pointers/interface.ts +++ b/packages/capnp-ts/src/serialization/pointers/interface.ts @@ -1,17 +1,92 @@ /** * @author jdiaz5513 + * @author fasterthanlime */ -import { MAX_DEPTH } from "../../constants"; -import { NOT_IMPLEMENTED } from "../../errors"; import { format } from "../../util"; -import { Segment } from "../segment"; -import { Pointer } from "./pointer"; +import { MAX_DEPTH } from "../../constants"; +import { Pointer, getTargetPointerType } from "./pointer"; +import { PointerType } from "./pointer-type"; +import type { CapabilityID } from "../../rpc/capability"; +import type { Client, Server } from "../../rpc"; +import type { ObjectSize } from "../object-size"; +import type { Segment } from "../segment"; + +export type ServerTarget> = ConstructorParameters[0]; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export interface InterfaceCtor { + readonly _capnp: { + displayName: string; + id: string; + size: ObjectSize; + }; + readonly Client: { new (client: Client): C }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + readonly Server: { new (target: any): S }; + + new (segment: Segment, byteOffset: number, depthLimit?: number): Interface; +} export class Interface extends Pointer { + static readonly _capnp = { + displayName: "Interface" as string, + }; + static readonly getCapID = getCapID; + static readonly getAsInterface = getAsInterface; + static readonly isInterface = isInterface; + static readonly getClient = getClient; + constructor(segment: Segment, byteOffset: number, depthLimit = MAX_DEPTH) { super(segment, byteOffset, depthLimit); + } + + static fromPointer(p: Pointer): Interface | null { + return getAsInterface(p); + } + + getCapId(): CapabilityID { + return getCapID(this); + } + + getClient(): Client | null { + return getClient(this); + } + + toString(): string { + return format( + "Interface_%d@%a,%d,limit:%x", + this.segment.id, + this.byteOffset, + this.getCapId(), + this._capnp.depthLimit + ); + } +} + +export function getAsInterface(p: Pointer): Interface | null { + if (getTargetPointerType(p) === PointerType.OTHER) { + return new Interface(p.segment, p.byteOffset, p._capnp.depthLimit); + } + return null; +} + +export function isInterface(p: Pointer): boolean { + return getTargetPointerType(p) === PointerType.OTHER; +} + +export function getCapID(i: Interface): CapabilityID { + if (i.segment.getUint32(i.byteOffset) !== PointerType.OTHER) { + return -1; + } + return i.segment.getUint32(i.byteOffset + 4); +} - throw new Error(format(NOT_IMPLEMENTED, "new Interface")); +export function getClient(i: Interface): Client | null { + const capID = getCapID(i); + const { capTable } = i.segment.message._capnp; + if (!capTable) { + return null; } + return capTable[capID]; } diff --git a/packages/capnp-ts/src/serialization/pointers/list.ts b/packages/capnp-ts/src/serialization/pointers/list.ts index 1e4744b..e3d4927 100644 --- a/packages/capnp-ts/src/serialization/pointers/list.ts +++ b/packages/capnp-ts/src/serialization/pointers/list.ts @@ -18,9 +18,6 @@ import { initPointer, } from "./pointer"; -const trace = initTrace("capnp:list"); -trace("load"); - export interface _ListCtor { readonly compositeSize?: ObjectSize; readonly displayName: string; @@ -350,8 +347,6 @@ export function initList( setStructPointer(length, compositeSize, c); - trace("Wrote composite tag word %s for %s.", c, l); - break; } case ListElementSize.VOID: diff --git a/packages/capnp-ts/src/serialization/pointers/orphan.ts b/packages/capnp-ts/src/serialization/pointers/orphan.ts index 76c480c..7134e93 100644 --- a/packages/capnp-ts/src/serialization/pointers/orphan.ts +++ b/packages/capnp-ts/src/serialization/pointers/orphan.ts @@ -25,7 +25,6 @@ import { import { PointerType } from "./pointer-type"; const trace = initTrace("capnp:orphan"); -trace("load"); export interface _Orphan { capId: number; diff --git a/packages/capnp-ts/src/serialization/pointers/pointer-allocation-result.ts b/packages/capnp-ts/src/serialization/pointers/pointer-allocation-result.ts index ffa436e..ffb4c58 100644 --- a/packages/capnp-ts/src/serialization/pointers/pointer-allocation-result.ts +++ b/packages/capnp-ts/src/serialization/pointers/pointer-allocation-result.ts @@ -2,13 +2,8 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { Pointer } from "./pointer"; -const trace = initTrace("capnp:pointer-allocation-result"); -trace("load"); - /** * This is used as the return value for `Pointer.prototype.initPointer`. Turns out using a class in V8 for multiple * return values is faster than using an array or anonymous object. diff --git a/packages/capnp-ts/src/serialization/pointers/pointer-list.ts b/packages/capnp-ts/src/serialization/pointers/pointer-list.ts index d71f8b1..f8a0061 100644 --- a/packages/capnp-ts/src/serialization/pointers/pointer-list.ts +++ b/packages/capnp-ts/src/serialization/pointers/pointer-list.ts @@ -2,15 +2,10 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { ListElementSize } from "../list-element-size"; import { _ListCtor, List, ListCtor } from "./list"; import { Pointer, PointerCtor, getContent, copyFrom } from "./pointer"; -const trace = initTrace("capnp:list:composite"); -trace("load"); - export function PointerList(PointerClass: PointerCtor): ListCtor { return class extends List { static readonly _capnp: _ListCtor = { diff --git a/packages/capnp-ts/src/serialization/pointers/pointer.ts b/packages/capnp-ts/src/serialization/pointers/pointer.ts index 165f9ef..99b792a 100644 --- a/packages/capnp-ts/src/serialization/pointers/pointer.ts +++ b/packages/capnp-ts/src/serialization/pointers/pointer.ts @@ -33,7 +33,6 @@ import { } from "../../errors"; const trace = initTrace("capnp:pointer"); -trace("load"); export interface _PointerCtor { readonly displayName: string; @@ -110,8 +109,6 @@ export class Pointer { if (byteOffset < 0 || byteOffset > segment.byteLength) { throw new Error(format(PTR_OFFSET_OUT_OF_BOUNDS, byteOffset)); } - - trace("new %s", this); } toString(): string { @@ -147,12 +144,7 @@ export function disown(p: T): Orphan { } export function dump(p: Pointer): string { - const f = followFars(p); - const pHex = bufferToHex(p.segment.buffer.slice(p.byteOffset, p.byteOffset + 8)); - if (f.byteOffset === p.byteOffset && f.segment === p.segment) { - return pHex; - } - return `${pHex} > ${bufferToHex(f.segment.buffer.slice(f.byteOffset, f.byteOffset + 8))}`; + return bufferToHex(p.segment.buffer.slice(p.byteOffset, p.byteOffset + 8)); } /** @@ -259,11 +251,7 @@ export function add(offset: number, p: Pointer): Pointer { export function copyFrom(src: Pointer, p: Pointer): void { // If the pointer is the same then this is a noop. - if (p.segment === src.segment && p.byteOffset === src.byteOffset) { - trace("ignoring copy operation from identical pointer %s", src); - - return; - } + if (p.segment === src.segment && p.byteOffset === src.byteOffset) return; // Make sure we erase this pointer's contents before moving on. If src is null, that's all we do. @@ -282,6 +270,12 @@ export function copyFrom(src: Pointer, p: Pointer): void { break; + case PointerType.OTHER: { + copyFromInterface(src, p); + + break; + } + /* istanbul ignore next */ default: throw new Error(format(PTR_INVALID_POINTER_TYPE, getTargetPointerType(p))); @@ -681,14 +675,12 @@ export function initPointer(contentSegment: Segment, contentOffset: number, p: P if (p.segment !== contentSegment) { // Need a far pointer. - trace("Initializing far pointer %s -> %s.", p, contentSegment); - if (!contentSegment.hasCapacity(8)) { // GAH! Not enough space in the content segment for a landing pad so we need a double far pointer. const landingPad = p.segment.allocate(16); - trace("GAH! Initializing double-far pointer in %s from %s -> %s.", p, contentSegment, landingPad); + trace("Initializing double-far pointer in %s from %s -> %s.", p, contentSegment, landingPad); setFarPointer(true, landingPad.byteOffset / 8, landingPad.segment.id, p); setFarPointer(false, contentOffset / 8, contentSegment.id, landingPad); @@ -711,8 +703,6 @@ export function initPointer(contentSegment: Segment, contentOffset: number, p: P return new PointerAllocationResult(landingPad, (contentOffset - landingPad.byteOffset - 8) / 8); } - trace("Initializing intra-segment pointer %s -> %a.", p, contentOffset); - return new PointerAllocationResult(p, (contentOffset - p.byteOffset - 8) / 8); } @@ -801,6 +791,16 @@ export function setInterfacePointer(capId: number, p: Pointer): void { p.segment.setUint32(p.byteOffset + 4, capId); } +/** + * Reads a raw interface pointer + * + * @param {Pointer} p The pointer to read. + * @returns {number} The capability ID. + */ +export function getInterfacePointer(p: Pointer): number { + return p.segment.getUint32(p.byteOffset + 4); +} + /** * Write a raw list pointer. * @@ -892,6 +892,30 @@ export function validate(pointerType: PointerType, p: Pointer, elementSize?: Lis } } +export function copyFromInterface(src: Pointer, dst: Pointer): void { + const srcCapId = getInterfacePointer(src); + if (srcCapId < 0) { + trace("copyFromInterface: src has no capId"); + return; + } + + const srcCapTable = src.segment.message._capnp.capTable; + if (!srcCapTable) { + trace("copyFromInterface: src pointer's message has no cap table"); + return; + } + + const client = srcCapTable[srcCapId]; + if (!client) { + trace("copyFromInterface: src capId is not mapped to a client"); + return; + } + + const dstCapId = dst.segment.message.addCap(client); + trace("copyFromInterface: src capId %d => dst capId %d", srcCapId, dstCapId); + setInterfacePointer(dstCapId, dst); +} + export function copyFromList(src: Pointer, dst: Pointer): void { if (dst._capnp.depthLimit <= 0) throw new Error(PTR_DEPTH_LIMIT_EXCEEDED); diff --git a/packages/capnp-ts/src/serialization/pointers/struct.ts b/packages/capnp-ts/src/serialization/pointers/struct.ts index 2da7851..1a50f91 100644 --- a/packages/capnp-ts/src/serialization/pointers/struct.ts +++ b/packages/capnp-ts/src/serialization/pointers/struct.ts @@ -12,6 +12,8 @@ import { Segment } from "../segment"; import { Data } from "./data"; import { List, ListCtor } from "./list"; import { Orphan } from "./orphan"; +import { Client } from "../../rpc/client"; +import { clientOrNull } from "../../rpc/error-client"; import { _Pointer, _PointerCtor, @@ -22,6 +24,8 @@ import { initPointer, erase, setStructPointer, + setInterfacePointer, + getInterfacePointer, followFars, getTargetListElementSize, getTargetPointerType, @@ -46,7 +50,6 @@ import { } from "../../errors"; const trace = initTrace("capnp:struct"); -trace("load"); // Used to apply bit masks (default values). const TMP_WORD = new DataView(new ArrayBuffer(8)); @@ -104,6 +107,9 @@ export class Struct extends Pointer { static readonly setInt32 = setInt32; static readonly setInt64 = setInt64; static readonly setText = setText; + static readonly setInterfacePointer = setInterfacePointer; + static readonly getInterfaceClientOrNull = getInterfaceClientOrNull; + static readonly getInterfaceClientOrNullAt = getInterfaceClientOrNullAt; static readonly testWhich = testWhich; readonly _capnp!: _Struct; @@ -174,6 +180,20 @@ export function initStructAt(index: number, StructClass: Struc return s; } +export function getInterfaceClientOrNullAt(index: number, s: Struct): Client { + return getInterfaceClientOrNull(getPointer(index, s)); +} + +export function getInterfaceClientOrNull(p: Pointer): Client { + let client: Client | null = null; + const capId = getInterfacePointer(p); + const capTable = p.segment.message._capnp.capTable; + if (capTable && capId >= 0 && capId < capTable.length) { + client = capTable[capId]; + } + return clientOrNull(client); +} + /** * Make a shallow copy of a struct's contents and update the pointer to point to the new content. The data and pointer * sections will be resized to the provided size. diff --git a/packages/capnp-ts/src/serialization/pointers/text-list.ts b/packages/capnp-ts/src/serialization/pointers/text-list.ts index 0c2c8fd..2d0e27d 100644 --- a/packages/capnp-ts/src/serialization/pointers/text-list.ts +++ b/packages/capnp-ts/src/serialization/pointers/text-list.ts @@ -2,20 +2,15 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { ListElementSize } from "../list-element-size"; import { _ListCtor, List } from "./list"; import { Text } from "./text"; import { getContent } from "./pointer"; -const trace = initTrace("capnp:list:composite"); -trace("load"); - export class TextList extends List { static readonly _capnp: _ListCtor = { displayName: "List" as string, - size: ListElementSize.POINTER + size: ListElementSize.POINTER, }; get(index: number): string { diff --git a/packages/capnp-ts/src/serialization/pointers/text.ts b/packages/capnp-ts/src/serialization/pointers/text.ts index 2804097..fcc2f20 100644 --- a/packages/capnp-ts/src/serialization/pointers/text.ts +++ b/packages/capnp-ts/src/serialization/pointers/text.ts @@ -11,7 +11,6 @@ import { Pointer, validate, isNull, getContent, erase } from "./pointer"; import { PointerType } from "./pointer-type"; const trace = initTrace("capnp:text"); -trace("load"); export class Text extends List { static fromPointer(pointer: Pointer): Text { @@ -38,13 +37,7 @@ export class Text extends List { // Remember to exclude the NUL byte. - return decodeUtf8( - new Uint8Array( - c.segment.buffer, - c.byteOffset + index, - this.getLength() - index - ) - ); + return decodeUtf8(new Uint8Array(c.segment.buffer, c.byteOffset + index, this.getLength() - index)); } /** @@ -88,19 +81,10 @@ export class Text extends List { if (originalLength >= index) { originalLength = index; } else { - trace( - "%d byte gap exists between original text and new text in %s.", - index - originalLength, - this - ); + trace("%d byte gap exists between original text and new text in %s.", index - originalLength, this); } - original = new Uint8Array( - c.segment.buffer.slice( - c.byteOffset, - c.byteOffset + Math.min(originalLength, index) - ) - ); + original = new Uint8Array(c.segment.buffer.slice(c.byteOffset, c.byteOffset + Math.min(originalLength, index))); erase(this); } @@ -123,9 +107,5 @@ export class Text extends List { } function textFromPointerUnchecked(pointer: Pointer): Text { - return new Text( - pointer.segment, - pointer.byteOffset, - pointer._capnp.depthLimit - ); + return new Text(pointer.segment, pointer.byteOffset, pointer._capnp.depthLimit); } diff --git a/packages/capnp-ts/src/serialization/pointers/uint16-list.ts b/packages/capnp-ts/src/serialization/pointers/uint16-list.ts index 64741f0..59a0606 100644 --- a/packages/capnp-ts/src/serialization/pointers/uint16-list.ts +++ b/packages/capnp-ts/src/serialization/pointers/uint16-list.ts @@ -2,19 +2,14 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { ListElementSize } from "../list-element-size"; import { _ListCtor, List } from "./list"; import { getContent } from "./pointer"; -const trace = initTrace("capnp:list:composite"); -trace("load"); - export class Uint16List extends List { static readonly _capnp: _ListCtor = { displayName: "List", - size: ListElementSize.BYTE_2 + size: ListElementSize.BYTE_2, }; get(index: number): number { diff --git a/packages/capnp-ts/src/serialization/pointers/uint32-list.ts b/packages/capnp-ts/src/serialization/pointers/uint32-list.ts index 2a6eafc..7920edb 100644 --- a/packages/capnp-ts/src/serialization/pointers/uint32-list.ts +++ b/packages/capnp-ts/src/serialization/pointers/uint32-list.ts @@ -2,19 +2,14 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { ListElementSize } from "../list-element-size"; import { _ListCtor, List } from "./list"; import { getContent } from "./pointer"; -const trace = initTrace("capnp:list:composite"); -trace("load"); - export class Uint32List extends List { static readonly _capnp: _ListCtor = { displayName: "List" as string, - size: ListElementSize.BYTE_4 + size: ListElementSize.BYTE_4, }; get(index: number): number { diff --git a/packages/capnp-ts/src/serialization/pointers/uint64-list.ts b/packages/capnp-ts/src/serialization/pointers/uint64-list.ts index 5eb6094..465f8fc 100644 --- a/packages/capnp-ts/src/serialization/pointers/uint64-list.ts +++ b/packages/capnp-ts/src/serialization/pointers/uint64-list.ts @@ -2,15 +2,10 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { ListElementSize } from "../list-element-size"; import { _ListCtor, List } from "./list"; import { getContent } from "./pointer"; -const trace = initTrace("capnp:list:composite"); -trace("load"); - export class Uint64List extends List { static readonly _capnp: _ListCtor = { displayName: "List" as string, diff --git a/packages/capnp-ts/src/serialization/pointers/uint8-list.ts b/packages/capnp-ts/src/serialization/pointers/uint8-list.ts index 524fd9d..85e6e84 100644 --- a/packages/capnp-ts/src/serialization/pointers/uint8-list.ts +++ b/packages/capnp-ts/src/serialization/pointers/uint8-list.ts @@ -2,19 +2,14 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { ListElementSize } from "../list-element-size"; import { _ListCtor, List } from "./list"; import { getContent } from "./pointer"; -const trace = initTrace("capnp:list:composite"); -trace("load"); - export class Uint8List extends List { static readonly _capnp: _ListCtor = { displayName: "List" as string, - size: ListElementSize.BYTE + size: ListElementSize.BYTE, }; get(index: number): number { diff --git a/packages/capnp-ts/src/serialization/segment.ts b/packages/capnp-ts/src/serialization/segment.ts index 91e3840..c50a090 100644 --- a/packages/capnp-ts/src/serialization/segment.ts +++ b/packages/capnp-ts/src/serialization/segment.ts @@ -2,17 +2,12 @@ * @author jdiaz5513 */ -import initTrace from "debug"; - import { MAX_SEGMENT_LENGTH, NATIVE_LITTLE_ENDIAN } from "../constants"; import { SEG_REPLACEMENT_BUFFER_TOO_SMALL, SEG_SIZE_OVERFLOW } from "../errors"; import { format, padToWord } from "../util"; import { Message } from "./message"; import { Pointer } from "./pointers"; -const trace = initTrace("capnp:segment"); -trace("load"); - export class Segment implements DataView { buffer: ArrayBuffer; @@ -56,8 +51,6 @@ export class Segment implements DataView { */ allocate(byteLength: number): Pointer { - trace("allocate(%d)", byteLength); - // eslint-disable-next-line @typescript-eslint/no-this-alias let segment: Segment = this; @@ -75,8 +68,6 @@ export class Segment implements DataView { segment.byteLength = segment.byteLength + byteLength; - trace("Allocated %x bytes in %s (requested segment: %s).", byteLength, this, segment); - return new Pointer(segment, byteOffset); } @@ -254,8 +245,6 @@ export class Segment implements DataView { } hasCapacity(byteLength: number): boolean { - trace("hasCapacity(%d)", byteLength); - // capacity - allocated >= requested return this.buffer.byteLength - this.byteLength >= byteLength; @@ -286,8 +275,6 @@ export class Segment implements DataView { */ replaceBuffer(buffer: ArrayBuffer): void { - trace("replaceBuffer(%p)", buffer); - if (this.buffer === buffer) return; if (buffer.byteLength < this.byteLength) { diff --git a/packages/capnp-ts/src/std/c++.capnp.ts b/packages/capnp-ts/src/std/c++.capnp.ts index b372ec3..e777c9e 100644 --- a/packages/capnp-ts/src/std/c++.capnp.ts +++ b/packages/capnp-ts/src/std/c++.capnp.ts @@ -4,5 +4,5 @@ */ import * as capnp from "../index"; -import { ObjectSize as __O, Struct as __S } from "../index"; +import { ObjectSize as __O, Struct as __S, Interface as __I } from "../index"; export const _capnpFileId = BigInt("0x814e30b87b7df8bd"); diff --git a/packages/capnp-ts/src/std/persistent.capnp.ts b/packages/capnp-ts/src/std/persistent.capnp.ts index e0920a5..1de2c8b 100644 --- a/packages/capnp-ts/src/std/persistent.capnp.ts +++ b/packages/capnp-ts/src/std/persistent.capnp.ts @@ -4,7 +4,7 @@ */ import * as capnp from "../index"; -import { ObjectSize as __O, Struct as __S } from "../index"; +import { ObjectSize as __O, Struct as __S, Interface as __I } from '../index'; export const _capnpFileId = "b8630836983feed7"; export class Persistent_SaveParams extends __S { static readonly _capnp = { displayName: "SaveParams", id: "f76fba59183073a5", size: new __O(0, 1) }; @@ -24,13 +24,69 @@ export class Persistent_SaveResults extends __S { setSturdyRef(value: capnp.Pointer): void { __S.copyFrom(value, __S.getPointer(0, this)); } toString(): string { return "Persistent_SaveResults_" + super.toString(); } } -export class Persistent extends __S { +export class Persistent$Client { + client: capnp.Client; + constructor(client: capnp.Client) { + this.client = client; + } + save(): void { + } +} +export class Persistent$Server { + save(): void { + } +} +export class Persistent extends __I { static readonly SaveParams = Persistent_SaveParams; static readonly SaveResults = Persistent_SaveResults; + static readonly Client = Persistent$Client; + static readonly Server = Persistent$Server; static readonly _capnp = { displayName: "Persistent", id: "c8cb212fcd9f5691", size: new __O(0, 0) }; toString(): string { return "Persistent_" + super.toString(); } } -export class RealmGateway extends __S { +export class RealmGateway_Import$Params extends __S { + static readonly _capnp = { displayName: "import$Params", id: "f0c2cc1d3909574d", size: new __O(0, 2) }; + getCap(): Persistent { return __S.getPointerAs(0, Persistent, this); } + setCap(value: Persistent): void { __S.copyFrom(value, __S.getPointer(0, this)); } + adoptParams(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(1, this)); } + disownParams(): capnp.Orphan { return __S.disown(this.getParams()); } + getParams(): Persistent_SaveParams { return __S.getStruct(1, Persistent_SaveParams, this); } + hasParams(): boolean { return !__S.isNull(__S.getPointer(1, this)); } + initParams(): Persistent_SaveParams { return __S.initStructAt(1, Persistent_SaveParams, this); } + setParams(value: Persistent_SaveParams): void { __S.copyFrom(value, __S.getPointer(1, this)); } + toString(): string { return "RealmGateway_Import$Params_" + super.toString(); } +} +export class RealmGateway_Export$Params extends __S { + static readonly _capnp = { displayName: "export$Params", id: "ecafa18b482da3aa", size: new __O(0, 2) }; + getCap(): Persistent { return __S.getPointerAs(0, Persistent, this); } + setCap(value: Persistent): void { __S.copyFrom(value, __S.getPointer(0, this)); } + adoptParams(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(1, this)); } + disownParams(): capnp.Orphan { return __S.disown(this.getParams()); } + getParams(): Persistent_SaveParams { return __S.getStruct(1, Persistent_SaveParams, this); } + hasParams(): boolean { return !__S.isNull(__S.getPointer(1, this)); } + initParams(): Persistent_SaveParams { return __S.initStructAt(1, Persistent_SaveParams, this); } + setParams(value: Persistent_SaveParams): void { __S.copyFrom(value, __S.getPointer(1, this)); } + toString(): string { return "RealmGateway_Export$Params_" + super.toString(); } +} +export class RealmGateway$Client { + client: capnp.Client; + constructor(client: capnp.Client) { + this.client = client; + } + import(): void { + } + export(): void { + } +} +export class RealmGateway$Server { + import(): void { + } + export(): void { + } +} +export class RealmGateway extends __I { + static readonly Client = RealmGateway$Client; + static readonly Server = RealmGateway$Server; static readonly _capnp = { displayName: "RealmGateway", id: "84ff286cd00a3ed4", size: new __O(0, 0) }; toString(): string { return "RealmGateway_" + super.toString(); } } diff --git a/packages/capnp-ts/src/std/rpc-twoparty.capnp.ts b/packages/capnp-ts/src/std/rpc-twoparty.capnp.ts index e56cf78..3772848 100644 --- a/packages/capnp-ts/src/std/rpc-twoparty.capnp.ts +++ b/packages/capnp-ts/src/std/rpc-twoparty.capnp.ts @@ -4,7 +4,7 @@ */ import * as capnp from "../index"; -import { ObjectSize as __O, Struct as __S } from "../index"; +import { ObjectSize as __O, Struct as __S, Interface as __I } from '../index'; export const _capnpFileId = "a184c7885cdaf2a1"; export enum Side { SERVER, diff --git a/packages/capnp-ts/src/std/rpc.capnp.ts b/packages/capnp-ts/src/std/rpc.capnp.ts index 748e6e7..4ccf85b 100644 --- a/packages/capnp-ts/src/std/rpc.capnp.ts +++ b/packages/capnp-ts/src/std/rpc.capnp.ts @@ -4,7 +4,7 @@ */ import * as capnp from "../index"; -import { ObjectSize as __O, Struct as __S } from "../index"; +import { ObjectSize as __O, Struct as __S, Interface as __I } from '../index'; export const _capnpFileId = "b312981b2552a250"; export enum Message_Which { UNIMPLEMENTED = 0, diff --git a/packages/capnp-ts/src/std/schema.capnp.ts b/packages/capnp-ts/src/std/schema.capnp.ts index 732243f..f069dd7 100644 --- a/packages/capnp-ts/src/std/schema.capnp.ts +++ b/packages/capnp-ts/src/std/schema.capnp.ts @@ -4,1033 +4,1922 @@ */ import * as capnp from "../index"; -import { ObjectSize as __O, Struct as __S } from "../index"; -export const _capnpFileId = "d9724c6209c53fa9"; +import { ObjectSize as __O, Struct as __S, Interface as __I } from "../index"; +export const _capnpFileId = BigInt("0xd9724c6209c53fa9"); export class Node_Parameter extends __S { - static readonly _capnp = { displayName: "Parameter", id: "b9521bccf10fa3b1", size: new __O(0, 1) }; - getName(): string { return __S.getText(0, this); } - setName(value: string): void { __S.setText(0, value, this); } - toString(): string { return "Node_Parameter_" + super.toString(); } + static readonly _capnp = { displayName: "Parameter", id: "b9521bccf10fa3b1", size: new __O(0, 1) }; + getName(): string { + return __S.getText(0, this); + } + setName(value: string): void { + __S.setText(0, value, this); + } + toString(): string { + return "Node_Parameter_" + super.toString(); + } } export class Node_NestedNode extends __S { - static readonly _capnp = { displayName: "NestedNode", id: "debf55bbfa0fc242", size: new __O(8, 1) }; - getName(): string { return __S.getText(0, this); } - setName(value: string): void { __S.setText(0, value, this); } - getId(): bigint { return __S.getUint64(0, this); } - setId(value: bigint): void { __S.setUint64(0, value, this); } - toString(): string { return "Node_NestedNode_" + super.toString(); } + static readonly _capnp = { displayName: "NestedNode", id: "debf55bbfa0fc242", size: new __O(8, 1) }; + getName(): string { + return __S.getText(0, this); + } + setName(value: string): void { + __S.setText(0, value, this); + } + getId(): bigint { + return __S.getUint64(0, this); + } + setId(value: bigint): void { + __S.setUint64(0, value, this); + } + toString(): string { + return "Node_NestedNode_" + super.toString(); + } } export class Node_Struct extends __S { - static readonly _capnp = { displayName: "struct", id: "9ea0b19b37fb4435", size: new __O(40, 6) }; - static _Fields: capnp.ListCtor; - getDataWordCount(): number { return __S.getUint16(14, this); } - setDataWordCount(value: number): void { __S.setUint16(14, value, this); } - getPointerCount(): number { return __S.getUint16(24, this); } - setPointerCount(value: number): void { __S.setUint16(24, value, this); } - getPreferredListEncoding(): ElementSize { return __S.getUint16(26, this); } - setPreferredListEncoding(value: ElementSize): void { __S.setUint16(26, value, this); } - getIsGroup(): boolean { return __S.getBit(224, this); } - setIsGroup(value: boolean): void { __S.setBit(224, value, this); } - getDiscriminantCount(): number { return __S.getUint16(30, this); } - setDiscriminantCount(value: number): void { __S.setUint16(30, value, this); } - getDiscriminantOffset(): number { return __S.getUint32(32, this); } - setDiscriminantOffset(value: number): void { __S.setUint32(32, value, this); } - adoptFields(value: capnp.Orphan>): void { __S.adopt(value, __S.getPointer(3, this)); } - disownFields(): capnp.Orphan> { return __S.disown(this.getFields()); } - getFields(): capnp.List { return __S.getList(3, Node_Struct._Fields, this); } - hasFields(): boolean { return !__S.isNull(__S.getPointer(3, this)); } - initFields(length: number): capnp.List { return __S.initList(3, Node_Struct._Fields, length, this); } - setFields(value: capnp.List): void { __S.copyFrom(value, __S.getPointer(3, this)); } - toString(): string { return "Node_Struct_" + super.toString(); } + static readonly _capnp = { displayName: "struct", id: "9ea0b19b37fb4435", size: new __O(40, 6) }; + static _Fields: capnp.ListCtor; + getDataWordCount(): number { + return __S.getUint16(14, this); + } + setDataWordCount(value: number): void { + __S.setUint16(14, value, this); + } + getPointerCount(): number { + return __S.getUint16(24, this); + } + setPointerCount(value: number): void { + __S.setUint16(24, value, this); + } + getPreferredListEncoding(): ElementSize { + return __S.getUint16(26, this); + } + setPreferredListEncoding(value: ElementSize): void { + __S.setUint16(26, value, this); + } + getIsGroup(): boolean { + return __S.getBit(224, this); + } + setIsGroup(value: boolean): void { + __S.setBit(224, value, this); + } + getDiscriminantCount(): number { + return __S.getUint16(30, this); + } + setDiscriminantCount(value: number): void { + __S.setUint16(30, value, this); + } + getDiscriminantOffset(): number { + return __S.getUint32(32, this); + } + setDiscriminantOffset(value: number): void { + __S.setUint32(32, value, this); + } + adoptFields(value: capnp.Orphan>): void { + __S.adopt(value, __S.getPointer(3, this)); + } + disownFields(): capnp.Orphan> { + return __S.disown(this.getFields()); + } + getFields(): capnp.List { + return __S.getList(3, Node_Struct._Fields, this); + } + hasFields(): boolean { + return !__S.isNull(__S.getPointer(3, this)); + } + initFields(length: number): capnp.List { + return __S.initList(3, Node_Struct._Fields, length, this); + } + setFields(value: capnp.List): void { + __S.copyFrom(value, __S.getPointer(3, this)); + } + toString(): string { + return "Node_Struct_" + super.toString(); + } } export class Node_Enum extends __S { - static readonly _capnp = { displayName: "enum", id: "b54ab3364333f598", size: new __O(40, 6) }; - static _Enumerants: capnp.ListCtor; - adoptEnumerants(value: capnp.Orphan>): void { __S.adopt(value, __S.getPointer(3, this)); } - disownEnumerants(): capnp.Orphan> { return __S.disown(this.getEnumerants()); } - getEnumerants(): capnp.List { return __S.getList(3, Node_Enum._Enumerants, this); } - hasEnumerants(): boolean { return !__S.isNull(__S.getPointer(3, this)); } - initEnumerants(length: number): capnp.List { return __S.initList(3, Node_Enum._Enumerants, length, this); } - setEnumerants(value: capnp.List): void { __S.copyFrom(value, __S.getPointer(3, this)); } - toString(): string { return "Node_Enum_" + super.toString(); } + static readonly _capnp = { displayName: "enum", id: "b54ab3364333f598", size: new __O(40, 6) }; + static _Enumerants: capnp.ListCtor; + adoptEnumerants(value: capnp.Orphan>): void { + __S.adopt(value, __S.getPointer(3, this)); + } + disownEnumerants(): capnp.Orphan> { + return __S.disown(this.getEnumerants()); + } + getEnumerants(): capnp.List { + return __S.getList(3, Node_Enum._Enumerants, this); + } + hasEnumerants(): boolean { + return !__S.isNull(__S.getPointer(3, this)); + } + initEnumerants(length: number): capnp.List { + return __S.initList(3, Node_Enum._Enumerants, length, this); + } + setEnumerants(value: capnp.List): void { + __S.copyFrom(value, __S.getPointer(3, this)); + } + toString(): string { + return "Node_Enum_" + super.toString(); + } } export class Node_Interface extends __S { - static readonly _capnp = { displayName: "interface", id: "e82753cff0c2218f", size: new __O(40, 6) }; - static _Methods: capnp.ListCtor; - static _Superclasses: capnp.ListCtor; - adoptMethods(value: capnp.Orphan>): void { __S.adopt(value, __S.getPointer(3, this)); } - disownMethods(): capnp.Orphan> { return __S.disown(this.getMethods()); } - getMethods(): capnp.List { return __S.getList(3, Node_Interface._Methods, this); } - hasMethods(): boolean { return !__S.isNull(__S.getPointer(3, this)); } - initMethods(length: number): capnp.List { return __S.initList(3, Node_Interface._Methods, length, this); } - setMethods(value: capnp.List): void { __S.copyFrom(value, __S.getPointer(3, this)); } - adoptSuperclasses(value: capnp.Orphan>): void { __S.adopt(value, __S.getPointer(4, this)); } - disownSuperclasses(): capnp.Orphan> { return __S.disown(this.getSuperclasses()); } - getSuperclasses(): capnp.List { return __S.getList(4, Node_Interface._Superclasses, this); } - hasSuperclasses(): boolean { return !__S.isNull(__S.getPointer(4, this)); } - initSuperclasses(length: number): capnp.List { return __S.initList(4, Node_Interface._Superclasses, length, this); } - setSuperclasses(value: capnp.List): void { __S.copyFrom(value, __S.getPointer(4, this)); } - toString(): string { return "Node_Interface_" + super.toString(); } + static readonly _capnp = { displayName: "interface", id: "e82753cff0c2218f", size: new __O(40, 6) }; + static _Methods: capnp.ListCtor; + static _Superclasses: capnp.ListCtor; + adoptMethods(value: capnp.Orphan>): void { + __S.adopt(value, __S.getPointer(3, this)); + } + disownMethods(): capnp.Orphan> { + return __S.disown(this.getMethods()); + } + getMethods(): capnp.List { + return __S.getList(3, Node_Interface._Methods, this); + } + hasMethods(): boolean { + return !__S.isNull(__S.getPointer(3, this)); + } + initMethods(length: number): capnp.List { + return __S.initList(3, Node_Interface._Methods, length, this); + } + setMethods(value: capnp.List): void { + __S.copyFrom(value, __S.getPointer(3, this)); + } + adoptSuperclasses(value: capnp.Orphan>): void { + __S.adopt(value, __S.getPointer(4, this)); + } + disownSuperclasses(): capnp.Orphan> { + return __S.disown(this.getSuperclasses()); + } + getSuperclasses(): capnp.List { + return __S.getList(4, Node_Interface._Superclasses, this); + } + hasSuperclasses(): boolean { + return !__S.isNull(__S.getPointer(4, this)); + } + initSuperclasses(length: number): capnp.List { + return __S.initList(4, Node_Interface._Superclasses, length, this); + } + setSuperclasses(value: capnp.List): void { + __S.copyFrom(value, __S.getPointer(4, this)); + } + toString(): string { + return "Node_Interface_" + super.toString(); + } } export class Node_Const extends __S { - static readonly _capnp = { displayName: "const", id: "b18aa5ac7a0d9420", size: new __O(40, 6) }; - adoptType(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(3, this)); } - disownType(): capnp.Orphan { return __S.disown(this.getType()); } - getType(): Type { return __S.getStruct(3, Type, this); } - hasType(): boolean { return !__S.isNull(__S.getPointer(3, this)); } - initType(): Type { return __S.initStructAt(3, Type, this); } - setType(value: Type): void { __S.copyFrom(value, __S.getPointer(3, this)); } - adoptValue(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(4, this)); } - disownValue(): capnp.Orphan { return __S.disown(this.getValue()); } - getValue(): Value { return __S.getStruct(4, Value, this); } - hasValue(): boolean { return !__S.isNull(__S.getPointer(4, this)); } - initValue(): Value { return __S.initStructAt(4, Value, this); } - setValue(value: Value): void { __S.copyFrom(value, __S.getPointer(4, this)); } - toString(): string { return "Node_Const_" + super.toString(); } + static readonly _capnp = { displayName: "const", id: "b18aa5ac7a0d9420", size: new __O(40, 6) }; + adoptType(value: capnp.Orphan): void { + __S.adopt(value, __S.getPointer(3, this)); + } + disownType(): capnp.Orphan { + return __S.disown(this.getType()); + } + getType(): Type { + return __S.getStruct(3, Type, this); + } + hasType(): boolean { + return !__S.isNull(__S.getPointer(3, this)); + } + initType(): Type { + return __S.initStructAt(3, Type, this); + } + setType(value: Type): void { + __S.copyFrom(value, __S.getPointer(3, this)); + } + adoptValue(value: capnp.Orphan): void { + __S.adopt(value, __S.getPointer(4, this)); + } + disownValue(): capnp.Orphan { + return __S.disown(this.getValue()); + } + getValue(): Value { + return __S.getStruct(4, Value, this); + } + hasValue(): boolean { + return !__S.isNull(__S.getPointer(4, this)); + } + initValue(): Value { + return __S.initStructAt(4, Value, this); + } + setValue(value: Value): void { + __S.copyFrom(value, __S.getPointer(4, this)); + } + toString(): string { + return "Node_Const_" + super.toString(); + } } export class Node_Annotation extends __S { - static readonly _capnp = { displayName: "annotation", id: "ec1619d4400a0290", size: new __O(40, 6) }; - adoptType(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(3, this)); } - disownType(): capnp.Orphan { return __S.disown(this.getType()); } - getType(): Type { return __S.getStruct(3, Type, this); } - hasType(): boolean { return !__S.isNull(__S.getPointer(3, this)); } - initType(): Type { return __S.initStructAt(3, Type, this); } - setType(value: Type): void { __S.copyFrom(value, __S.getPointer(3, this)); } - getTargetsFile(): boolean { return __S.getBit(112, this); } - setTargetsFile(value: boolean): void { __S.setBit(112, value, this); } - getTargetsConst(): boolean { return __S.getBit(113, this); } - setTargetsConst(value: boolean): void { __S.setBit(113, value, this); } - getTargetsEnum(): boolean { return __S.getBit(114, this); } - setTargetsEnum(value: boolean): void { __S.setBit(114, value, this); } - getTargetsEnumerant(): boolean { return __S.getBit(115, this); } - setTargetsEnumerant(value: boolean): void { __S.setBit(115, value, this); } - getTargetsStruct(): boolean { return __S.getBit(116, this); } - setTargetsStruct(value: boolean): void { __S.setBit(116, value, this); } - getTargetsField(): boolean { return __S.getBit(117, this); } - setTargetsField(value: boolean): void { __S.setBit(117, value, this); } - getTargetsUnion(): boolean { return __S.getBit(118, this); } - setTargetsUnion(value: boolean): void { __S.setBit(118, value, this); } - getTargetsGroup(): boolean { return __S.getBit(119, this); } - setTargetsGroup(value: boolean): void { __S.setBit(119, value, this); } - getTargetsInterface(): boolean { return __S.getBit(120, this); } - setTargetsInterface(value: boolean): void { __S.setBit(120, value, this); } - getTargetsMethod(): boolean { return __S.getBit(121, this); } - setTargetsMethod(value: boolean): void { __S.setBit(121, value, this); } - getTargetsParam(): boolean { return __S.getBit(122, this); } - setTargetsParam(value: boolean): void { __S.setBit(122, value, this); } - getTargetsAnnotation(): boolean { return __S.getBit(123, this); } - setTargetsAnnotation(value: boolean): void { __S.setBit(123, value, this); } - toString(): string { return "Node_Annotation_" + super.toString(); } + static readonly _capnp = { displayName: "annotation", id: "ec1619d4400a0290", size: new __O(40, 6) }; + adoptType(value: capnp.Orphan): void { + __S.adopt(value, __S.getPointer(3, this)); + } + disownType(): capnp.Orphan { + return __S.disown(this.getType()); + } + getType(): Type { + return __S.getStruct(3, Type, this); + } + hasType(): boolean { + return !__S.isNull(__S.getPointer(3, this)); + } + initType(): Type { + return __S.initStructAt(3, Type, this); + } + setType(value: Type): void { + __S.copyFrom(value, __S.getPointer(3, this)); + } + getTargetsFile(): boolean { + return __S.getBit(112, this); + } + setTargetsFile(value: boolean): void { + __S.setBit(112, value, this); + } + getTargetsConst(): boolean { + return __S.getBit(113, this); + } + setTargetsConst(value: boolean): void { + __S.setBit(113, value, this); + } + getTargetsEnum(): boolean { + return __S.getBit(114, this); + } + setTargetsEnum(value: boolean): void { + __S.setBit(114, value, this); + } + getTargetsEnumerant(): boolean { + return __S.getBit(115, this); + } + setTargetsEnumerant(value: boolean): void { + __S.setBit(115, value, this); + } + getTargetsStruct(): boolean { + return __S.getBit(116, this); + } + setTargetsStruct(value: boolean): void { + __S.setBit(116, value, this); + } + getTargetsField(): boolean { + return __S.getBit(117, this); + } + setTargetsField(value: boolean): void { + __S.setBit(117, value, this); + } + getTargetsUnion(): boolean { + return __S.getBit(118, this); + } + setTargetsUnion(value: boolean): void { + __S.setBit(118, value, this); + } + getTargetsGroup(): boolean { + return __S.getBit(119, this); + } + setTargetsGroup(value: boolean): void { + __S.setBit(119, value, this); + } + getTargetsInterface(): boolean { + return __S.getBit(120, this); + } + setTargetsInterface(value: boolean): void { + __S.setBit(120, value, this); + } + getTargetsMethod(): boolean { + return __S.getBit(121, this); + } + setTargetsMethod(value: boolean): void { + __S.setBit(121, value, this); + } + getTargetsParam(): boolean { + return __S.getBit(122, this); + } + setTargetsParam(value: boolean): void { + __S.setBit(122, value, this); + } + getTargetsAnnotation(): boolean { + return __S.getBit(123, this); + } + setTargetsAnnotation(value: boolean): void { + __S.setBit(123, value, this); + } + toString(): string { + return "Node_Annotation_" + super.toString(); + } } export enum Node_Which { - FILE = 0, - STRUCT = 1, - ENUM = 2, - INTERFACE = 3, - CONST = 4, - ANNOTATION = 5 + FILE = 0, + STRUCT = 1, + ENUM = 2, + INTERFACE = 3, + CONST = 4, + ANNOTATION = 5, } export class Node extends __S { - static readonly FILE = Node_Which.FILE; - static readonly STRUCT = Node_Which.STRUCT; - static readonly ENUM = Node_Which.ENUM; - static readonly INTERFACE = Node_Which.INTERFACE; - static readonly CONST = Node_Which.CONST; - static readonly ANNOTATION = Node_Which.ANNOTATION; - static readonly Parameter = Node_Parameter; - static readonly NestedNode = Node_NestedNode; - static readonly _capnp = { displayName: "Node", id: "e682ab4cf923a417", size: new __O(40, 6) }; - static _Parameters: capnp.ListCtor; - static _NestedNodes: capnp.ListCtor; - static _Annotations: capnp.ListCtor; - getId(): bigint { return __S.getUint64(0, this); } - setId(value: bigint): void { __S.setUint64(0, value, this); } - getDisplayName(): string { return __S.getText(0, this); } - setDisplayName(value: string): void { __S.setText(0, value, this); } - getDisplayNamePrefixLength(): number { return __S.getUint32(8, this); } - setDisplayNamePrefixLength(value: number): void { __S.setUint32(8, value, this); } - getScopeId(): bigint { return __S.getUint64(16, this); } - setScopeId(value: bigint): void { __S.setUint64(16, value, this); } - adoptParameters(value: capnp.Orphan>): void { __S.adopt(value, __S.getPointer(5, this)); } - disownParameters(): capnp.Orphan> { return __S.disown(this.getParameters()); } - getParameters(): capnp.List { return __S.getList(5, Node._Parameters, this); } - hasParameters(): boolean { return !__S.isNull(__S.getPointer(5, this)); } - initParameters(length: number): capnp.List { return __S.initList(5, Node._Parameters, length, this); } - setParameters(value: capnp.List): void { __S.copyFrom(value, __S.getPointer(5, this)); } - getIsGeneric(): boolean { return __S.getBit(288, this); } - setIsGeneric(value: boolean): void { __S.setBit(288, value, this); } - adoptNestedNodes(value: capnp.Orphan>): void { __S.adopt(value, __S.getPointer(1, this)); } - disownNestedNodes(): capnp.Orphan> { return __S.disown(this.getNestedNodes()); } - getNestedNodes(): capnp.List { return __S.getList(1, Node._NestedNodes, this); } - hasNestedNodes(): boolean { return !__S.isNull(__S.getPointer(1, this)); } - initNestedNodes(length: number): capnp.List { return __S.initList(1, Node._NestedNodes, length, this); } - setNestedNodes(value: capnp.List): void { __S.copyFrom(value, __S.getPointer(1, this)); } - adoptAnnotations(value: capnp.Orphan>): void { __S.adopt(value, __S.getPointer(2, this)); } - disownAnnotations(): capnp.Orphan> { return __S.disown(this.getAnnotations()); } - getAnnotations(): capnp.List { return __S.getList(2, Node._Annotations, this); } - hasAnnotations(): boolean { return !__S.isNull(__S.getPointer(2, this)); } - initAnnotations(length: number): capnp.List { return __S.initList(2, Node._Annotations, length, this); } - setAnnotations(value: capnp.List): void { __S.copyFrom(value, __S.getPointer(2, this)); } - isFile(): boolean { return __S.getUint16(12, this) === 0; } - setFile(): void { __S.setUint16(12, 0, this); } - getStruct(): Node_Struct { - __S.testWhich("struct", __S.getUint16(12, this), 1, this); - return __S.getAs(Node_Struct, this); - } - initStruct(): Node_Struct { - __S.setUint16(12, 1, this); - return __S.getAs(Node_Struct, this); - } - isStruct(): boolean { return __S.getUint16(12, this) === 1; } - setStruct(): void { __S.setUint16(12, 1, this); } - getEnum(): Node_Enum { - __S.testWhich("enum", __S.getUint16(12, this), 2, this); - return __S.getAs(Node_Enum, this); - } - initEnum(): Node_Enum { - __S.setUint16(12, 2, this); - return __S.getAs(Node_Enum, this); - } - isEnum(): boolean { return __S.getUint16(12, this) === 2; } - setEnum(): void { __S.setUint16(12, 2, this); } - getInterface(): Node_Interface { - __S.testWhich("interface", __S.getUint16(12, this), 3, this); - return __S.getAs(Node_Interface, this); - } - initInterface(): Node_Interface { - __S.setUint16(12, 3, this); - return __S.getAs(Node_Interface, this); - } - isInterface(): boolean { return __S.getUint16(12, this) === 3; } - setInterface(): void { __S.setUint16(12, 3, this); } - getConst(): Node_Const { - __S.testWhich("const", __S.getUint16(12, this), 4, this); - return __S.getAs(Node_Const, this); - } - initConst(): Node_Const { - __S.setUint16(12, 4, this); - return __S.getAs(Node_Const, this); - } - isConst(): boolean { return __S.getUint16(12, this) === 4; } - setConst(): void { __S.setUint16(12, 4, this); } - getAnnotation(): Node_Annotation { - __S.testWhich("annotation", __S.getUint16(12, this), 5, this); - return __S.getAs(Node_Annotation, this); - } - initAnnotation(): Node_Annotation { - __S.setUint16(12, 5, this); - return __S.getAs(Node_Annotation, this); - } - isAnnotation(): boolean { return __S.getUint16(12, this) === 5; } - setAnnotation(): void { __S.setUint16(12, 5, this); } - toString(): string { return "Node_" + super.toString(); } - which(): Node_Which { return __S.getUint16(12, this); } + static readonly FILE = Node_Which.FILE; + static readonly STRUCT = Node_Which.STRUCT; + static readonly ENUM = Node_Which.ENUM; + static readonly INTERFACE = Node_Which.INTERFACE; + static readonly CONST = Node_Which.CONST; + static readonly ANNOTATION = Node_Which.ANNOTATION; + static readonly Parameter = Node_Parameter; + static readonly NestedNode = Node_NestedNode; + static readonly _capnp = { displayName: "Node", id: "e682ab4cf923a417", size: new __O(40, 6) }; + static _Parameters: capnp.ListCtor; + static _NestedNodes: capnp.ListCtor; + static _Annotations: capnp.ListCtor; + getId(): bigint { + return __S.getUint64(0, this); + } + setId(value: bigint): void { + __S.setUint64(0, value, this); + } + getDisplayName(): string { + return __S.getText(0, this); + } + setDisplayName(value: string): void { + __S.setText(0, value, this); + } + getDisplayNamePrefixLength(): number { + return __S.getUint32(8, this); + } + setDisplayNamePrefixLength(value: number): void { + __S.setUint32(8, value, this); + } + getScopeId(): bigint { + return __S.getUint64(16, this); + } + setScopeId(value: bigint): void { + __S.setUint64(16, value, this); + } + adoptParameters(value: capnp.Orphan>): void { + __S.adopt(value, __S.getPointer(5, this)); + } + disownParameters(): capnp.Orphan> { + return __S.disown(this.getParameters()); + } + getParameters(): capnp.List { + return __S.getList(5, Node._Parameters, this); + } + hasParameters(): boolean { + return !__S.isNull(__S.getPointer(5, this)); + } + initParameters(length: number): capnp.List { + return __S.initList(5, Node._Parameters, length, this); + } + setParameters(value: capnp.List): void { + __S.copyFrom(value, __S.getPointer(5, this)); + } + getIsGeneric(): boolean { + return __S.getBit(288, this); + } + setIsGeneric(value: boolean): void { + __S.setBit(288, value, this); + } + adoptNestedNodes(value: capnp.Orphan>): void { + __S.adopt(value, __S.getPointer(1, this)); + } + disownNestedNodes(): capnp.Orphan> { + return __S.disown(this.getNestedNodes()); + } + getNestedNodes(): capnp.List { + return __S.getList(1, Node._NestedNodes, this); + } + hasNestedNodes(): boolean { + return !__S.isNull(__S.getPointer(1, this)); + } + initNestedNodes(length: number): capnp.List { + return __S.initList(1, Node._NestedNodes, length, this); + } + setNestedNodes(value: capnp.List): void { + __S.copyFrom(value, __S.getPointer(1, this)); + } + adoptAnnotations(value: capnp.Orphan>): void { + __S.adopt(value, __S.getPointer(2, this)); + } + disownAnnotations(): capnp.Orphan> { + return __S.disown(this.getAnnotations()); + } + getAnnotations(): capnp.List { + return __S.getList(2, Node._Annotations, this); + } + hasAnnotations(): boolean { + return !__S.isNull(__S.getPointer(2, this)); + } + initAnnotations(length: number): capnp.List { + return __S.initList(2, Node._Annotations, length, this); + } + setAnnotations(value: capnp.List): void { + __S.copyFrom(value, __S.getPointer(2, this)); + } + isFile(): boolean { + return __S.getUint16(12, this) === 0; + } + setFile(): void { + __S.setUint16(12, 0, this); + } + getStruct(): Node_Struct { + __S.testWhich("struct", __S.getUint16(12, this), 1, this); + return __S.getAs(Node_Struct, this); + } + initStruct(): Node_Struct { + __S.setUint16(12, 1, this); + return __S.getAs(Node_Struct, this); + } + isStruct(): boolean { + return __S.getUint16(12, this) === 1; + } + setStruct(): void { + __S.setUint16(12, 1, this); + } + getEnum(): Node_Enum { + __S.testWhich("enum", __S.getUint16(12, this), 2, this); + return __S.getAs(Node_Enum, this); + } + initEnum(): Node_Enum { + __S.setUint16(12, 2, this); + return __S.getAs(Node_Enum, this); + } + isEnum(): boolean { + return __S.getUint16(12, this) === 2; + } + setEnum(): void { + __S.setUint16(12, 2, this); + } + getInterface(): Node_Interface { + __S.testWhich("interface", __S.getUint16(12, this), 3, this); + return __S.getAs(Node_Interface, this); + } + initInterface(): Node_Interface { + __S.setUint16(12, 3, this); + return __S.getAs(Node_Interface, this); + } + isInterface(): boolean { + return __S.getUint16(12, this) === 3; + } + setInterface(): void { + __S.setUint16(12, 3, this); + } + getConst(): Node_Const { + __S.testWhich("const", __S.getUint16(12, this), 4, this); + return __S.getAs(Node_Const, this); + } + initConst(): Node_Const { + __S.setUint16(12, 4, this); + return __S.getAs(Node_Const, this); + } + isConst(): boolean { + return __S.getUint16(12, this) === 4; + } + setConst(): void { + __S.setUint16(12, 4, this); + } + getAnnotation(): Node_Annotation { + __S.testWhich("annotation", __S.getUint16(12, this), 5, this); + return __S.getAs(Node_Annotation, this); + } + initAnnotation(): Node_Annotation { + __S.setUint16(12, 5, this); + return __S.getAs(Node_Annotation, this); + } + isAnnotation(): boolean { + return __S.getUint16(12, this) === 5; + } + setAnnotation(): void { + __S.setUint16(12, 5, this); + } + toString(): string { + return "Node_" + super.toString(); + } + which(): Node_Which { + return __S.getUint16(12, this); + } } export class Field_Slot extends __S { - static readonly _capnp = { displayName: "slot", id: "c42305476bb4746f", size: new __O(24, 4) }; - getOffset(): number { return __S.getUint32(4, this); } - setOffset(value: number): void { __S.setUint32(4, value, this); } - adoptType(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(2, this)); } - disownType(): capnp.Orphan { return __S.disown(this.getType()); } - getType(): Type { return __S.getStruct(2, Type, this); } - hasType(): boolean { return !__S.isNull(__S.getPointer(2, this)); } - initType(): Type { return __S.initStructAt(2, Type, this); } - setType(value: Type): void { __S.copyFrom(value, __S.getPointer(2, this)); } - adoptDefaultValue(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(3, this)); } - disownDefaultValue(): capnp.Orphan { return __S.disown(this.getDefaultValue()); } - getDefaultValue(): Value { return __S.getStruct(3, Value, this); } - hasDefaultValue(): boolean { return !__S.isNull(__S.getPointer(3, this)); } - initDefaultValue(): Value { return __S.initStructAt(3, Value, this); } - setDefaultValue(value: Value): void { __S.copyFrom(value, __S.getPointer(3, this)); } - getHadExplicitDefault(): boolean { return __S.getBit(128, this); } - setHadExplicitDefault(value: boolean): void { __S.setBit(128, value, this); } - toString(): string { return "Field_Slot_" + super.toString(); } + static readonly _capnp = { displayName: "slot", id: "c42305476bb4746f", size: new __O(24, 4) }; + getOffset(): number { + return __S.getUint32(4, this); + } + setOffset(value: number): void { + __S.setUint32(4, value, this); + } + adoptType(value: capnp.Orphan): void { + __S.adopt(value, __S.getPointer(2, this)); + } + disownType(): capnp.Orphan { + return __S.disown(this.getType()); + } + getType(): Type { + return __S.getStruct(2, Type, this); + } + hasType(): boolean { + return !__S.isNull(__S.getPointer(2, this)); + } + initType(): Type { + return __S.initStructAt(2, Type, this); + } + setType(value: Type): void { + __S.copyFrom(value, __S.getPointer(2, this)); + } + adoptDefaultValue(value: capnp.Orphan): void { + __S.adopt(value, __S.getPointer(3, this)); + } + disownDefaultValue(): capnp.Orphan { + return __S.disown(this.getDefaultValue()); + } + getDefaultValue(): Value { + return __S.getStruct(3, Value, this); + } + hasDefaultValue(): boolean { + return !__S.isNull(__S.getPointer(3, this)); + } + initDefaultValue(): Value { + return __S.initStructAt(3, Value, this); + } + setDefaultValue(value: Value): void { + __S.copyFrom(value, __S.getPointer(3, this)); + } + getHadExplicitDefault(): boolean { + return __S.getBit(128, this); + } + setHadExplicitDefault(value: boolean): void { + __S.setBit(128, value, this); + } + toString(): string { + return "Field_Slot_" + super.toString(); + } } export class Field_Group extends __S { - static readonly _capnp = { displayName: "group", id: "cafccddb68db1d11", size: new __O(24, 4) }; - getTypeId(): bigint { return __S.getUint64(16, this); } - setTypeId(value: bigint): void { __S.setUint64(16, value, this); } - toString(): string { return "Field_Group_" + super.toString(); } + static readonly _capnp = { displayName: "group", id: "cafccddb68db1d11", size: new __O(24, 4) }; + getTypeId(): bigint { + return __S.getUint64(16, this); + } + setTypeId(value: bigint): void { + __S.setUint64(16, value, this); + } + toString(): string { + return "Field_Group_" + super.toString(); + } } export enum Field_Ordinal_Which { - IMPLICIT = 0, - EXPLICIT = 1 + IMPLICIT = 0, + EXPLICIT = 1, } export class Field_Ordinal extends __S { - static readonly IMPLICIT = Field_Ordinal_Which.IMPLICIT; - static readonly EXPLICIT = Field_Ordinal_Which.EXPLICIT; - static readonly _capnp = { displayName: "ordinal", id: "bb90d5c287870be6", size: new __O(24, 4) }; - isImplicit(): boolean { return __S.getUint16(10, this) === 0; } - setImplicit(): void { __S.setUint16(10, 0, this); } - getExplicit(): number { - __S.testWhich("explicit", __S.getUint16(10, this), 1, this); - return __S.getUint16(12, this); - } - isExplicit(): boolean { return __S.getUint16(10, this) === 1; } - setExplicit(value: number): void { - __S.setUint16(10, 1, this); - __S.setUint16(12, value, this); - } - toString(): string { return "Field_Ordinal_" + super.toString(); } - which(): Field_Ordinal_Which { return __S.getUint16(10, this); } + static readonly IMPLICIT = Field_Ordinal_Which.IMPLICIT; + static readonly EXPLICIT = Field_Ordinal_Which.EXPLICIT; + static readonly _capnp = { displayName: "ordinal", id: "bb90d5c287870be6", size: new __O(24, 4) }; + isImplicit(): boolean { + return __S.getUint16(10, this) === 0; + } + setImplicit(): void { + __S.setUint16(10, 0, this); + } + getExplicit(): number { + __S.testWhich("explicit", __S.getUint16(10, this), 1, this); + return __S.getUint16(12, this); + } + isExplicit(): boolean { + return __S.getUint16(10, this) === 1; + } + setExplicit(value: number): void { + __S.setUint16(10, 1, this); + __S.setUint16(12, value, this); + } + toString(): string { + return "Field_Ordinal_" + super.toString(); + } + which(): Field_Ordinal_Which { + return __S.getUint16(10, this); + } } export enum Field_Which { - SLOT = 0, - GROUP = 1 + SLOT = 0, + GROUP = 1, } export class Field extends __S { - static readonly NO_DISCRIMINANT = 65535; - static readonly SLOT = Field_Which.SLOT; - static readonly GROUP = Field_Which.GROUP; - static readonly _capnp = { displayName: "Field", id: "9aad50a41f4af45f", size: new __O(24, 4), defaultDiscriminantValue: capnp.getUint16Mask(65535) }; - static _Annotations: capnp.ListCtor; - getName(): string { return __S.getText(0, this); } - setName(value: string): void { __S.setText(0, value, this); } - getCodeOrder(): number { return __S.getUint16(0, this); } - setCodeOrder(value: number): void { __S.setUint16(0, value, this); } - adoptAnnotations(value: capnp.Orphan>): void { __S.adopt(value, __S.getPointer(1, this)); } - disownAnnotations(): capnp.Orphan> { return __S.disown(this.getAnnotations()); } - getAnnotations(): capnp.List { return __S.getList(1, Field._Annotations, this); } - hasAnnotations(): boolean { return !__S.isNull(__S.getPointer(1, this)); } - initAnnotations(length: number): capnp.List { return __S.initList(1, Field._Annotations, length, this); } - setAnnotations(value: capnp.List): void { __S.copyFrom(value, __S.getPointer(1, this)); } - getDiscriminantValue(): number { return __S.getUint16(2, this, Field._capnp.defaultDiscriminantValue); } - setDiscriminantValue(value: number): void { __S.setUint16(2, value, this); } - getSlot(): Field_Slot { - __S.testWhich("slot", __S.getUint16(8, this), 0, this); - return __S.getAs(Field_Slot, this); - } - initSlot(): Field_Slot { - __S.setUint16(8, 0, this); - return __S.getAs(Field_Slot, this); - } - isSlot(): boolean { return __S.getUint16(8, this) === 0; } - setSlot(): void { __S.setUint16(8, 0, this); } - getGroup(): Field_Group { - __S.testWhich("group", __S.getUint16(8, this), 1, this); - return __S.getAs(Field_Group, this); - } - initGroup(): Field_Group { - __S.setUint16(8, 1, this); - return __S.getAs(Field_Group, this); - } - isGroup(): boolean { return __S.getUint16(8, this) === 1; } - setGroup(): void { __S.setUint16(8, 1, this); } - getOrdinal(): Field_Ordinal { return __S.getAs(Field_Ordinal, this); } - initOrdinal(): Field_Ordinal { return __S.getAs(Field_Ordinal, this); } - toString(): string { return "Field_" + super.toString(); } - which(): Field_Which { return __S.getUint16(8, this); } + static readonly NO_DISCRIMINANT = 65535; + static readonly SLOT = Field_Which.SLOT; + static readonly GROUP = Field_Which.GROUP; + static readonly _capnp = { + displayName: "Field", + id: "9aad50a41f4af45f", + size: new __O(24, 4), + defaultDiscriminantValue: capnp.getUint16Mask(65535), + }; + static _Annotations: capnp.ListCtor; + getName(): string { + return __S.getText(0, this); + } + setName(value: string): void { + __S.setText(0, value, this); + } + getCodeOrder(): number { + return __S.getUint16(0, this); + } + setCodeOrder(value: number): void { + __S.setUint16(0, value, this); + } + adoptAnnotations(value: capnp.Orphan>): void { + __S.adopt(value, __S.getPointer(1, this)); + } + disownAnnotations(): capnp.Orphan> { + return __S.disown(this.getAnnotations()); + } + getAnnotations(): capnp.List { + return __S.getList(1, Field._Annotations, this); + } + hasAnnotations(): boolean { + return !__S.isNull(__S.getPointer(1, this)); + } + initAnnotations(length: number): capnp.List { + return __S.initList(1, Field._Annotations, length, this); + } + setAnnotations(value: capnp.List): void { + __S.copyFrom(value, __S.getPointer(1, this)); + } + getDiscriminantValue(): number { + return __S.getUint16(2, this, Field._capnp.defaultDiscriminantValue); + } + setDiscriminantValue(value: number): void { + __S.setUint16(2, value, this); + } + getSlot(): Field_Slot { + __S.testWhich("slot", __S.getUint16(8, this), 0, this); + return __S.getAs(Field_Slot, this); + } + initSlot(): Field_Slot { + __S.setUint16(8, 0, this); + return __S.getAs(Field_Slot, this); + } + isSlot(): boolean { + return __S.getUint16(8, this) === 0; + } + setSlot(): void { + __S.setUint16(8, 0, this); + } + getGroup(): Field_Group { + __S.testWhich("group", __S.getUint16(8, this), 1, this); + return __S.getAs(Field_Group, this); + } + initGroup(): Field_Group { + __S.setUint16(8, 1, this); + return __S.getAs(Field_Group, this); + } + isGroup(): boolean { + return __S.getUint16(8, this) === 1; + } + setGroup(): void { + __S.setUint16(8, 1, this); + } + getOrdinal(): Field_Ordinal { + return __S.getAs(Field_Ordinal, this); + } + initOrdinal(): Field_Ordinal { + return __S.getAs(Field_Ordinal, this); + } + toString(): string { + return "Field_" + super.toString(); + } + which(): Field_Which { + return __S.getUint16(8, this); + } } export class Enumerant extends __S { - static readonly _capnp = { displayName: "Enumerant", id: "978a7cebdc549a4d", size: new __O(8, 2) }; - static _Annotations: capnp.ListCtor; - getName(): string { return __S.getText(0, this); } - setName(value: string): void { __S.setText(0, value, this); } - getCodeOrder(): number { return __S.getUint16(0, this); } - setCodeOrder(value: number): void { __S.setUint16(0, value, this); } - adoptAnnotations(value: capnp.Orphan>): void { __S.adopt(value, __S.getPointer(1, this)); } - disownAnnotations(): capnp.Orphan> { return __S.disown(this.getAnnotations()); } - getAnnotations(): capnp.List { return __S.getList(1, Enumerant._Annotations, this); } - hasAnnotations(): boolean { return !__S.isNull(__S.getPointer(1, this)); } - initAnnotations(length: number): capnp.List { return __S.initList(1, Enumerant._Annotations, length, this); } - setAnnotations(value: capnp.List): void { __S.copyFrom(value, __S.getPointer(1, this)); } - toString(): string { return "Enumerant_" + super.toString(); } + static readonly _capnp = { displayName: "Enumerant", id: "978a7cebdc549a4d", size: new __O(8, 2) }; + static _Annotations: capnp.ListCtor; + getName(): string { + return __S.getText(0, this); + } + setName(value: string): void { + __S.setText(0, value, this); + } + getCodeOrder(): number { + return __S.getUint16(0, this); + } + setCodeOrder(value: number): void { + __S.setUint16(0, value, this); + } + adoptAnnotations(value: capnp.Orphan>): void { + __S.adopt(value, __S.getPointer(1, this)); + } + disownAnnotations(): capnp.Orphan> { + return __S.disown(this.getAnnotations()); + } + getAnnotations(): capnp.List { + return __S.getList(1, Enumerant._Annotations, this); + } + hasAnnotations(): boolean { + return !__S.isNull(__S.getPointer(1, this)); + } + initAnnotations(length: number): capnp.List { + return __S.initList(1, Enumerant._Annotations, length, this); + } + setAnnotations(value: capnp.List): void { + __S.copyFrom(value, __S.getPointer(1, this)); + } + toString(): string { + return "Enumerant_" + super.toString(); + } } export class Superclass extends __S { - static readonly _capnp = { displayName: "Superclass", id: "a9962a9ed0a4d7f8", size: new __O(8, 1) }; - getId(): bigint { return __S.getUint64(0, this); } - setId(value: bigint): void { __S.setUint64(0, value, this); } - adoptBrand(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(0, this)); } - disownBrand(): capnp.Orphan { return __S.disown(this.getBrand()); } - getBrand(): Brand { return __S.getStruct(0, Brand, this); } - hasBrand(): boolean { return !__S.isNull(__S.getPointer(0, this)); } - initBrand(): Brand { return __S.initStructAt(0, Brand, this); } - setBrand(value: Brand): void { __S.copyFrom(value, __S.getPointer(0, this)); } - toString(): string { return "Superclass_" + super.toString(); } + static readonly _capnp = { displayName: "Superclass", id: "a9962a9ed0a4d7f8", size: new __O(8, 1) }; + getId(): bigint { + return __S.getUint64(0, this); + } + setId(value: bigint): void { + __S.setUint64(0, value, this); + } + adoptBrand(value: capnp.Orphan): void { + __S.adopt(value, __S.getPointer(0, this)); + } + disownBrand(): capnp.Orphan { + return __S.disown(this.getBrand()); + } + getBrand(): Brand { + return __S.getStruct(0, Brand, this); + } + hasBrand(): boolean { + return !__S.isNull(__S.getPointer(0, this)); + } + initBrand(): Brand { + return __S.initStructAt(0, Brand, this); + } + setBrand(value: Brand): void { + __S.copyFrom(value, __S.getPointer(0, this)); + } + toString(): string { + return "Superclass_" + super.toString(); + } } export class Method extends __S { - static readonly _capnp = { displayName: "Method", id: "9500cce23b334d80", size: new __O(24, 5) }; - static _ImplicitParameters: capnp.ListCtor; - static _Annotations: capnp.ListCtor; - getName(): string { return __S.getText(0, this); } - setName(value: string): void { __S.setText(0, value, this); } - getCodeOrder(): number { return __S.getUint16(0, this); } - setCodeOrder(value: number): void { __S.setUint16(0, value, this); } - adoptImplicitParameters(value: capnp.Orphan>): void { __S.adopt(value, __S.getPointer(4, this)); } - disownImplicitParameters(): capnp.Orphan> { return __S.disown(this.getImplicitParameters()); } - getImplicitParameters(): capnp.List { return __S.getList(4, Method._ImplicitParameters, this); } - hasImplicitParameters(): boolean { return !__S.isNull(__S.getPointer(4, this)); } - initImplicitParameters(length: number): capnp.List { return __S.initList(4, Method._ImplicitParameters, length, this); } - setImplicitParameters(value: capnp.List): void { __S.copyFrom(value, __S.getPointer(4, this)); } - getParamStructType(): bigint { return __S.getUint64(8, this); } - setParamStructType(value: bigint): void { __S.setUint64(8, value, this); } - adoptParamBrand(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(2, this)); } - disownParamBrand(): capnp.Orphan { return __S.disown(this.getParamBrand()); } - getParamBrand(): Brand { return __S.getStruct(2, Brand, this); } - hasParamBrand(): boolean { return !__S.isNull(__S.getPointer(2, this)); } - initParamBrand(): Brand { return __S.initStructAt(2, Brand, this); } - setParamBrand(value: Brand): void { __S.copyFrom(value, __S.getPointer(2, this)); } - getResultStructType(): bigint { return __S.getUint64(16, this); } - setResultStructType(value: bigint): void { __S.setUint64(16, value, this); } - adoptResultBrand(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(3, this)); } - disownResultBrand(): capnp.Orphan { return __S.disown(this.getResultBrand()); } - getResultBrand(): Brand { return __S.getStruct(3, Brand, this); } - hasResultBrand(): boolean { return !__S.isNull(__S.getPointer(3, this)); } - initResultBrand(): Brand { return __S.initStructAt(3, Brand, this); } - setResultBrand(value: Brand): void { __S.copyFrom(value, __S.getPointer(3, this)); } - adoptAnnotations(value: capnp.Orphan>): void { __S.adopt(value, __S.getPointer(1, this)); } - disownAnnotations(): capnp.Orphan> { return __S.disown(this.getAnnotations()); } - getAnnotations(): capnp.List { return __S.getList(1, Method._Annotations, this); } - hasAnnotations(): boolean { return !__S.isNull(__S.getPointer(1, this)); } - initAnnotations(length: number): capnp.List { return __S.initList(1, Method._Annotations, length, this); } - setAnnotations(value: capnp.List): void { __S.copyFrom(value, __S.getPointer(1, this)); } - toString(): string { return "Method_" + super.toString(); } + static readonly _capnp = { displayName: "Method", id: "9500cce23b334d80", size: new __O(24, 5) }; + static _ImplicitParameters: capnp.ListCtor; + static _Annotations: capnp.ListCtor; + getName(): string { + return __S.getText(0, this); + } + setName(value: string): void { + __S.setText(0, value, this); + } + getCodeOrder(): number { + return __S.getUint16(0, this); + } + setCodeOrder(value: number): void { + __S.setUint16(0, value, this); + } + adoptImplicitParameters(value: capnp.Orphan>): void { + __S.adopt(value, __S.getPointer(4, this)); + } + disownImplicitParameters(): capnp.Orphan> { + return __S.disown(this.getImplicitParameters()); + } + getImplicitParameters(): capnp.List { + return __S.getList(4, Method._ImplicitParameters, this); + } + hasImplicitParameters(): boolean { + return !__S.isNull(__S.getPointer(4, this)); + } + initImplicitParameters(length: number): capnp.List { + return __S.initList(4, Method._ImplicitParameters, length, this); + } + setImplicitParameters(value: capnp.List): void { + __S.copyFrom(value, __S.getPointer(4, this)); + } + getParamStructType(): bigint { + return __S.getUint64(8, this); + } + setParamStructType(value: bigint): void { + __S.setUint64(8, value, this); + } + adoptParamBrand(value: capnp.Orphan): void { + __S.adopt(value, __S.getPointer(2, this)); + } + disownParamBrand(): capnp.Orphan { + return __S.disown(this.getParamBrand()); + } + getParamBrand(): Brand { + return __S.getStruct(2, Brand, this); + } + hasParamBrand(): boolean { + return !__S.isNull(__S.getPointer(2, this)); + } + initParamBrand(): Brand { + return __S.initStructAt(2, Brand, this); + } + setParamBrand(value: Brand): void { + __S.copyFrom(value, __S.getPointer(2, this)); + } + getResultStructType(): bigint { + return __S.getUint64(16, this); + } + setResultStructType(value: bigint): void { + __S.setUint64(16, value, this); + } + adoptResultBrand(value: capnp.Orphan): void { + __S.adopt(value, __S.getPointer(3, this)); + } + disownResultBrand(): capnp.Orphan { + return __S.disown(this.getResultBrand()); + } + getResultBrand(): Brand { + return __S.getStruct(3, Brand, this); + } + hasResultBrand(): boolean { + return !__S.isNull(__S.getPointer(3, this)); + } + initResultBrand(): Brand { + return __S.initStructAt(3, Brand, this); + } + setResultBrand(value: Brand): void { + __S.copyFrom(value, __S.getPointer(3, this)); + } + adoptAnnotations(value: capnp.Orphan>): void { + __S.adopt(value, __S.getPointer(1, this)); + } + disownAnnotations(): capnp.Orphan> { + return __S.disown(this.getAnnotations()); + } + getAnnotations(): capnp.List { + return __S.getList(1, Method._Annotations, this); + } + hasAnnotations(): boolean { + return !__S.isNull(__S.getPointer(1, this)); + } + initAnnotations(length: number): capnp.List { + return __S.initList(1, Method._Annotations, length, this); + } + setAnnotations(value: capnp.List): void { + __S.copyFrom(value, __S.getPointer(1, this)); + } + toString(): string { + return "Method_" + super.toString(); + } } export class Type_List extends __S { - static readonly _capnp = { displayName: "list", id: "87e739250a60ea97", size: new __O(24, 1) }; - adoptElementType(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(0, this)); } - disownElementType(): capnp.Orphan { return __S.disown(this.getElementType()); } - getElementType(): Type { return __S.getStruct(0, Type, this); } - hasElementType(): boolean { return !__S.isNull(__S.getPointer(0, this)); } - initElementType(): Type { return __S.initStructAt(0, Type, this); } - setElementType(value: Type): void { __S.copyFrom(value, __S.getPointer(0, this)); } - toString(): string { return "Type_List_" + super.toString(); } + static readonly _capnp = { displayName: "list", id: "87e739250a60ea97", size: new __O(24, 1) }; + adoptElementType(value: capnp.Orphan): void { + __S.adopt(value, __S.getPointer(0, this)); + } + disownElementType(): capnp.Orphan { + return __S.disown(this.getElementType()); + } + getElementType(): Type { + return __S.getStruct(0, Type, this); + } + hasElementType(): boolean { + return !__S.isNull(__S.getPointer(0, this)); + } + initElementType(): Type { + return __S.initStructAt(0, Type, this); + } + setElementType(value: Type): void { + __S.copyFrom(value, __S.getPointer(0, this)); + } + toString(): string { + return "Type_List_" + super.toString(); + } } export class Type_Enum extends __S { - static readonly _capnp = { displayName: "enum", id: "9e0e78711a7f87a9", size: new __O(24, 1) }; - getTypeId(): bigint { return __S.getUint64(8, this); } - setTypeId(value: bigint): void { __S.setUint64(8, value, this); } - adoptBrand(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(0, this)); } - disownBrand(): capnp.Orphan { return __S.disown(this.getBrand()); } - getBrand(): Brand { return __S.getStruct(0, Brand, this); } - hasBrand(): boolean { return !__S.isNull(__S.getPointer(0, this)); } - initBrand(): Brand { return __S.initStructAt(0, Brand, this); } - setBrand(value: Brand): void { __S.copyFrom(value, __S.getPointer(0, this)); } - toString(): string { return "Type_Enum_" + super.toString(); } + static readonly _capnp = { displayName: "enum", id: "9e0e78711a7f87a9", size: new __O(24, 1) }; + getTypeId(): bigint { + return __S.getUint64(8, this); + } + setTypeId(value: bigint): void { + __S.setUint64(8, value, this); + } + adoptBrand(value: capnp.Orphan): void { + __S.adopt(value, __S.getPointer(0, this)); + } + disownBrand(): capnp.Orphan { + return __S.disown(this.getBrand()); + } + getBrand(): Brand { + return __S.getStruct(0, Brand, this); + } + hasBrand(): boolean { + return !__S.isNull(__S.getPointer(0, this)); + } + initBrand(): Brand { + return __S.initStructAt(0, Brand, this); + } + setBrand(value: Brand): void { + __S.copyFrom(value, __S.getPointer(0, this)); + } + toString(): string { + return "Type_Enum_" + super.toString(); + } } export class Type_Struct extends __S { - static readonly _capnp = { displayName: "struct", id: "ac3a6f60ef4cc6d3", size: new __O(24, 1) }; - getTypeId(): bigint { return __S.getUint64(8, this); } - setTypeId(value: bigint): void { __S.setUint64(8, value, this); } - adoptBrand(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(0, this)); } - disownBrand(): capnp.Orphan { return __S.disown(this.getBrand()); } - getBrand(): Brand { return __S.getStruct(0, Brand, this); } - hasBrand(): boolean { return !__S.isNull(__S.getPointer(0, this)); } - initBrand(): Brand { return __S.initStructAt(0, Brand, this); } - setBrand(value: Brand): void { __S.copyFrom(value, __S.getPointer(0, this)); } - toString(): string { return "Type_Struct_" + super.toString(); } + static readonly _capnp = { displayName: "struct", id: "ac3a6f60ef4cc6d3", size: new __O(24, 1) }; + getTypeId(): bigint { + return __S.getUint64(8, this); + } + setTypeId(value: bigint): void { + __S.setUint64(8, value, this); + } + adoptBrand(value: capnp.Orphan): void { + __S.adopt(value, __S.getPointer(0, this)); + } + disownBrand(): capnp.Orphan { + return __S.disown(this.getBrand()); + } + getBrand(): Brand { + return __S.getStruct(0, Brand, this); + } + hasBrand(): boolean { + return !__S.isNull(__S.getPointer(0, this)); + } + initBrand(): Brand { + return __S.initStructAt(0, Brand, this); + } + setBrand(value: Brand): void { + __S.copyFrom(value, __S.getPointer(0, this)); + } + toString(): string { + return "Type_Struct_" + super.toString(); + } } export class Type_Interface extends __S { - static readonly _capnp = { displayName: "interface", id: "ed8bca69f7fb0cbf", size: new __O(24, 1) }; - getTypeId(): bigint { return __S.getUint64(8, this); } - setTypeId(value: bigint): void { __S.setUint64(8, value, this); } - adoptBrand(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(0, this)); } - disownBrand(): capnp.Orphan { return __S.disown(this.getBrand()); } - getBrand(): Brand { return __S.getStruct(0, Brand, this); } - hasBrand(): boolean { return !__S.isNull(__S.getPointer(0, this)); } - initBrand(): Brand { return __S.initStructAt(0, Brand, this); } - setBrand(value: Brand): void { __S.copyFrom(value, __S.getPointer(0, this)); } - toString(): string { return "Type_Interface_" + super.toString(); } + static readonly _capnp = { displayName: "interface", id: "ed8bca69f7fb0cbf", size: new __O(24, 1) }; + getTypeId(): bigint { + return __S.getUint64(8, this); + } + setTypeId(value: bigint): void { + __S.setUint64(8, value, this); + } + adoptBrand(value: capnp.Orphan): void { + __S.adopt(value, __S.getPointer(0, this)); + } + disownBrand(): capnp.Orphan { + return __S.disown(this.getBrand()); + } + getBrand(): Brand { + return __S.getStruct(0, Brand, this); + } + hasBrand(): boolean { + return !__S.isNull(__S.getPointer(0, this)); + } + initBrand(): Brand { + return __S.initStructAt(0, Brand, this); + } + setBrand(value: Brand): void { + __S.copyFrom(value, __S.getPointer(0, this)); + } + toString(): string { + return "Type_Interface_" + super.toString(); + } } export enum Type_AnyPointer_Unconstrained_Which { - ANY_KIND = 0, - STRUCT = 1, - LIST = 2, - CAPABILITY = 3 + ANY_KIND = 0, + STRUCT = 1, + LIST = 2, + CAPABILITY = 3, } export class Type_AnyPointer_Unconstrained extends __S { - static readonly ANY_KIND = Type_AnyPointer_Unconstrained_Which.ANY_KIND; - static readonly STRUCT = Type_AnyPointer_Unconstrained_Which.STRUCT; - static readonly LIST = Type_AnyPointer_Unconstrained_Which.LIST; - static readonly CAPABILITY = Type_AnyPointer_Unconstrained_Which.CAPABILITY; - static readonly _capnp = { displayName: "unconstrained", id: "8e3b5f79fe593656", size: new __O(24, 1) }; - isAnyKind(): boolean { return __S.getUint16(10, this) === 0; } - setAnyKind(): void { __S.setUint16(10, 0, this); } - isStruct(): boolean { return __S.getUint16(10, this) === 1; } - setStruct(): void { __S.setUint16(10, 1, this); } - isList(): boolean { return __S.getUint16(10, this) === 2; } - setList(): void { __S.setUint16(10, 2, this); } - isCapability(): boolean { return __S.getUint16(10, this) === 3; } - setCapability(): void { __S.setUint16(10, 3, this); } - toString(): string { return "Type_AnyPointer_Unconstrained_" + super.toString(); } - which(): Type_AnyPointer_Unconstrained_Which { return __S.getUint16(10, this); } + static readonly ANY_KIND = Type_AnyPointer_Unconstrained_Which.ANY_KIND; + static readonly STRUCT = Type_AnyPointer_Unconstrained_Which.STRUCT; + static readonly LIST = Type_AnyPointer_Unconstrained_Which.LIST; + static readonly CAPABILITY = Type_AnyPointer_Unconstrained_Which.CAPABILITY; + static readonly _capnp = { displayName: "unconstrained", id: "8e3b5f79fe593656", size: new __O(24, 1) }; + isAnyKind(): boolean { + return __S.getUint16(10, this) === 0; + } + setAnyKind(): void { + __S.setUint16(10, 0, this); + } + isStruct(): boolean { + return __S.getUint16(10, this) === 1; + } + setStruct(): void { + __S.setUint16(10, 1, this); + } + isList(): boolean { + return __S.getUint16(10, this) === 2; + } + setList(): void { + __S.setUint16(10, 2, this); + } + isCapability(): boolean { + return __S.getUint16(10, this) === 3; + } + setCapability(): void { + __S.setUint16(10, 3, this); + } + toString(): string { + return "Type_AnyPointer_Unconstrained_" + super.toString(); + } + which(): Type_AnyPointer_Unconstrained_Which { + return __S.getUint16(10, this); + } } export class Type_AnyPointer_Parameter extends __S { - static readonly _capnp = { displayName: "parameter", id: "9dd1f724f4614a85", size: new __O(24, 1) }; - getScopeId(): bigint { return __S.getUint64(16, this); } - setScopeId(value: bigint): void { __S.setUint64(16, value, this); } - getParameterIndex(): number { return __S.getUint16(10, this); } - setParameterIndex(value: number): void { __S.setUint16(10, value, this); } - toString(): string { return "Type_AnyPointer_Parameter_" + super.toString(); } + static readonly _capnp = { displayName: "parameter", id: "9dd1f724f4614a85", size: new __O(24, 1) }; + getScopeId(): bigint { + return __S.getUint64(16, this); + } + setScopeId(value: bigint): void { + __S.setUint64(16, value, this); + } + getParameterIndex(): number { + return __S.getUint16(10, this); + } + setParameterIndex(value: number): void { + __S.setUint16(10, value, this); + } + toString(): string { + return "Type_AnyPointer_Parameter_" + super.toString(); + } } export class Type_AnyPointer_ImplicitMethodParameter extends __S { - static readonly _capnp = { displayName: "implicitMethodParameter", id: "baefc9120c56e274", size: new __O(24, 1) }; - getParameterIndex(): number { return __S.getUint16(10, this); } - setParameterIndex(value: number): void { __S.setUint16(10, value, this); } - toString(): string { return "Type_AnyPointer_ImplicitMethodParameter_" + super.toString(); } + static readonly _capnp = { displayName: "implicitMethodParameter", id: "baefc9120c56e274", size: new __O(24, 1) }; + getParameterIndex(): number { + return __S.getUint16(10, this); + } + setParameterIndex(value: number): void { + __S.setUint16(10, value, this); + } + toString(): string { + return "Type_AnyPointer_ImplicitMethodParameter_" + super.toString(); + } } export enum Type_AnyPointer_Which { - UNCONSTRAINED = 0, - PARAMETER = 1, - IMPLICIT_METHOD_PARAMETER = 2 + UNCONSTRAINED = 0, + PARAMETER = 1, + IMPLICIT_METHOD_PARAMETER = 2, } export class Type_AnyPointer extends __S { - static readonly UNCONSTRAINED = Type_AnyPointer_Which.UNCONSTRAINED; - static readonly PARAMETER = Type_AnyPointer_Which.PARAMETER; - static readonly IMPLICIT_METHOD_PARAMETER = Type_AnyPointer_Which.IMPLICIT_METHOD_PARAMETER; - static readonly _capnp = { displayName: "anyPointer", id: "c2573fe8a23e49f1", size: new __O(24, 1) }; - getUnconstrained(): Type_AnyPointer_Unconstrained { - __S.testWhich("unconstrained", __S.getUint16(8, this), 0, this); - return __S.getAs(Type_AnyPointer_Unconstrained, this); - } - initUnconstrained(): Type_AnyPointer_Unconstrained { - __S.setUint16(8, 0, this); - return __S.getAs(Type_AnyPointer_Unconstrained, this); - } - isUnconstrained(): boolean { return __S.getUint16(8, this) === 0; } - setUnconstrained(): void { __S.setUint16(8, 0, this); } - getParameter(): Type_AnyPointer_Parameter { - __S.testWhich("parameter", __S.getUint16(8, this), 1, this); - return __S.getAs(Type_AnyPointer_Parameter, this); - } - initParameter(): Type_AnyPointer_Parameter { - __S.setUint16(8, 1, this); - return __S.getAs(Type_AnyPointer_Parameter, this); - } - isParameter(): boolean { return __S.getUint16(8, this) === 1; } - setParameter(): void { __S.setUint16(8, 1, this); } - getImplicitMethodParameter(): Type_AnyPointer_ImplicitMethodParameter { - __S.testWhich("implicitMethodParameter", __S.getUint16(8, this), 2, this); - return __S.getAs(Type_AnyPointer_ImplicitMethodParameter, this); - } - initImplicitMethodParameter(): Type_AnyPointer_ImplicitMethodParameter { - __S.setUint16(8, 2, this); - return __S.getAs(Type_AnyPointer_ImplicitMethodParameter, this); - } - isImplicitMethodParameter(): boolean { return __S.getUint16(8, this) === 2; } - setImplicitMethodParameter(): void { __S.setUint16(8, 2, this); } - toString(): string { return "Type_AnyPointer_" + super.toString(); } - which(): Type_AnyPointer_Which { return __S.getUint16(8, this); } + static readonly UNCONSTRAINED = Type_AnyPointer_Which.UNCONSTRAINED; + static readonly PARAMETER = Type_AnyPointer_Which.PARAMETER; + static readonly IMPLICIT_METHOD_PARAMETER = Type_AnyPointer_Which.IMPLICIT_METHOD_PARAMETER; + static readonly _capnp = { displayName: "anyPointer", id: "c2573fe8a23e49f1", size: new __O(24, 1) }; + getUnconstrained(): Type_AnyPointer_Unconstrained { + __S.testWhich("unconstrained", __S.getUint16(8, this), 0, this); + return __S.getAs(Type_AnyPointer_Unconstrained, this); + } + initUnconstrained(): Type_AnyPointer_Unconstrained { + __S.setUint16(8, 0, this); + return __S.getAs(Type_AnyPointer_Unconstrained, this); + } + isUnconstrained(): boolean { + return __S.getUint16(8, this) === 0; + } + setUnconstrained(): void { + __S.setUint16(8, 0, this); + } + getParameter(): Type_AnyPointer_Parameter { + __S.testWhich("parameter", __S.getUint16(8, this), 1, this); + return __S.getAs(Type_AnyPointer_Parameter, this); + } + initParameter(): Type_AnyPointer_Parameter { + __S.setUint16(8, 1, this); + return __S.getAs(Type_AnyPointer_Parameter, this); + } + isParameter(): boolean { + return __S.getUint16(8, this) === 1; + } + setParameter(): void { + __S.setUint16(8, 1, this); + } + getImplicitMethodParameter(): Type_AnyPointer_ImplicitMethodParameter { + __S.testWhich("implicitMethodParameter", __S.getUint16(8, this), 2, this); + return __S.getAs(Type_AnyPointer_ImplicitMethodParameter, this); + } + initImplicitMethodParameter(): Type_AnyPointer_ImplicitMethodParameter { + __S.setUint16(8, 2, this); + return __S.getAs(Type_AnyPointer_ImplicitMethodParameter, this); + } + isImplicitMethodParameter(): boolean { + return __S.getUint16(8, this) === 2; + } + setImplicitMethodParameter(): void { + __S.setUint16(8, 2, this); + } + toString(): string { + return "Type_AnyPointer_" + super.toString(); + } + which(): Type_AnyPointer_Which { + return __S.getUint16(8, this); + } } export enum Type_Which { - VOID = 0, - BOOL = 1, - INT8 = 2, - INT16 = 3, - INT32 = 4, - INT64 = 5, - UINT8 = 6, - UINT16 = 7, - UINT32 = 8, - UINT64 = 9, - FLOAT32 = 10, - FLOAT64 = 11, - TEXT = 12, - DATA = 13, - LIST = 14, - ENUM = 15, - STRUCT = 16, - INTERFACE = 17, - ANY_POINTER = 18 + VOID = 0, + BOOL = 1, + INT8 = 2, + INT16 = 3, + INT32 = 4, + INT64 = 5, + UINT8 = 6, + UINT16 = 7, + UINT32 = 8, + UINT64 = 9, + FLOAT32 = 10, + FLOAT64 = 11, + TEXT = 12, + DATA = 13, + LIST = 14, + ENUM = 15, + STRUCT = 16, + INTERFACE = 17, + ANY_POINTER = 18, } export class Type extends __S { - static readonly VOID = Type_Which.VOID; - static readonly BOOL = Type_Which.BOOL; - static readonly INT8 = Type_Which.INT8; - static readonly INT16 = Type_Which.INT16; - static readonly INT32 = Type_Which.INT32; - static readonly INT64 = Type_Which.INT64; - static readonly UINT8 = Type_Which.UINT8; - static readonly UINT16 = Type_Which.UINT16; - static readonly UINT32 = Type_Which.UINT32; - static readonly UINT64 = Type_Which.UINT64; - static readonly FLOAT32 = Type_Which.FLOAT32; - static readonly FLOAT64 = Type_Which.FLOAT64; - static readonly TEXT = Type_Which.TEXT; - static readonly DATA = Type_Which.DATA; - static readonly LIST = Type_Which.LIST; - static readonly ENUM = Type_Which.ENUM; - static readonly STRUCT = Type_Which.STRUCT; - static readonly INTERFACE = Type_Which.INTERFACE; - static readonly ANY_POINTER = Type_Which.ANY_POINTER; - static readonly _capnp = { displayName: "Type", id: "d07378ede1f9cc60", size: new __O(24, 1) }; - isVoid(): boolean { return __S.getUint16(0, this) === 0; } - setVoid(): void { __S.setUint16(0, 0, this); } - isBool(): boolean { return __S.getUint16(0, this) === 1; } - setBool(): void { __S.setUint16(0, 1, this); } - isInt8(): boolean { return __S.getUint16(0, this) === 2; } - setInt8(): void { __S.setUint16(0, 2, this); } - isInt16(): boolean { return __S.getUint16(0, this) === 3; } - setInt16(): void { __S.setUint16(0, 3, this); } - isInt32(): boolean { return __S.getUint16(0, this) === 4; } - setInt32(): void { __S.setUint16(0, 4, this); } - isInt64(): boolean { return __S.getUint16(0, this) === 5; } - setInt64(): void { __S.setUint16(0, 5, this); } - isUint8(): boolean { return __S.getUint16(0, this) === 6; } - setUint8(): void { __S.setUint16(0, 6, this); } - isUint16(): boolean { return __S.getUint16(0, this) === 7; } - setUint16(): void { __S.setUint16(0, 7, this); } - isUint32(): boolean { return __S.getUint16(0, this) === 8; } - setUint32(): void { __S.setUint16(0, 8, this); } - isUint64(): boolean { return __S.getUint16(0, this) === 9; } - setUint64(): void { __S.setUint16(0, 9, this); } - isFloat32(): boolean { return __S.getUint16(0, this) === 10; } - setFloat32(): void { __S.setUint16(0, 10, this); } - isFloat64(): boolean { return __S.getUint16(0, this) === 11; } - setFloat64(): void { __S.setUint16(0, 11, this); } - isText(): boolean { return __S.getUint16(0, this) === 12; } - setText(): void { __S.setUint16(0, 12, this); } - isData(): boolean { return __S.getUint16(0, this) === 13; } - setData(): void { __S.setUint16(0, 13, this); } - getList(): Type_List { - __S.testWhich("list", __S.getUint16(0, this), 14, this); - return __S.getAs(Type_List, this); - } - initList(): Type_List { - __S.setUint16(0, 14, this); - return __S.getAs(Type_List, this); - } - isList(): boolean { return __S.getUint16(0, this) === 14; } - setList(): void { __S.setUint16(0, 14, this); } - getEnum(): Type_Enum { - __S.testWhich("enum", __S.getUint16(0, this), 15, this); - return __S.getAs(Type_Enum, this); - } - initEnum(): Type_Enum { - __S.setUint16(0, 15, this); - return __S.getAs(Type_Enum, this); - } - isEnum(): boolean { return __S.getUint16(0, this) === 15; } - setEnum(): void { __S.setUint16(0, 15, this); } - getStruct(): Type_Struct { - __S.testWhich("struct", __S.getUint16(0, this), 16, this); - return __S.getAs(Type_Struct, this); - } - initStruct(): Type_Struct { - __S.setUint16(0, 16, this); - return __S.getAs(Type_Struct, this); - } - isStruct(): boolean { return __S.getUint16(0, this) === 16; } - setStruct(): void { __S.setUint16(0, 16, this); } - getInterface(): Type_Interface { - __S.testWhich("interface", __S.getUint16(0, this), 17, this); - return __S.getAs(Type_Interface, this); - } - initInterface(): Type_Interface { - __S.setUint16(0, 17, this); - return __S.getAs(Type_Interface, this); - } - isInterface(): boolean { return __S.getUint16(0, this) === 17; } - setInterface(): void { __S.setUint16(0, 17, this); } - getAnyPointer(): Type_AnyPointer { - __S.testWhich("anyPointer", __S.getUint16(0, this), 18, this); - return __S.getAs(Type_AnyPointer, this); - } - initAnyPointer(): Type_AnyPointer { - __S.setUint16(0, 18, this); - return __S.getAs(Type_AnyPointer, this); - } - isAnyPointer(): boolean { return __S.getUint16(0, this) === 18; } - setAnyPointer(): void { __S.setUint16(0, 18, this); } - toString(): string { return "Type_" + super.toString(); } - which(): Type_Which { return __S.getUint16(0, this); } + static readonly VOID = Type_Which.VOID; + static readonly BOOL = Type_Which.BOOL; + static readonly INT8 = Type_Which.INT8; + static readonly INT16 = Type_Which.INT16; + static readonly INT32 = Type_Which.INT32; + static readonly INT64 = Type_Which.INT64; + static readonly UINT8 = Type_Which.UINT8; + static readonly UINT16 = Type_Which.UINT16; + static readonly UINT32 = Type_Which.UINT32; + static readonly UINT64 = Type_Which.UINT64; + static readonly FLOAT32 = Type_Which.FLOAT32; + static readonly FLOAT64 = Type_Which.FLOAT64; + static readonly TEXT = Type_Which.TEXT; + static readonly DATA = Type_Which.DATA; + static readonly LIST = Type_Which.LIST; + static readonly ENUM = Type_Which.ENUM; + static readonly STRUCT = Type_Which.STRUCT; + static readonly INTERFACE = Type_Which.INTERFACE; + static readonly ANY_POINTER = Type_Which.ANY_POINTER; + static readonly _capnp = { displayName: "Type", id: "d07378ede1f9cc60", size: new __O(24, 1) }; + isVoid(): boolean { + return __S.getUint16(0, this) === 0; + } + setVoid(): void { + __S.setUint16(0, 0, this); + } + isBool(): boolean { + return __S.getUint16(0, this) === 1; + } + setBool(): void { + __S.setUint16(0, 1, this); + } + isInt8(): boolean { + return __S.getUint16(0, this) === 2; + } + setInt8(): void { + __S.setUint16(0, 2, this); + } + isInt16(): boolean { + return __S.getUint16(0, this) === 3; + } + setInt16(): void { + __S.setUint16(0, 3, this); + } + isInt32(): boolean { + return __S.getUint16(0, this) === 4; + } + setInt32(): void { + __S.setUint16(0, 4, this); + } + isInt64(): boolean { + return __S.getUint16(0, this) === 5; + } + setInt64(): void { + __S.setUint16(0, 5, this); + } + isUint8(): boolean { + return __S.getUint16(0, this) === 6; + } + setUint8(): void { + __S.setUint16(0, 6, this); + } + isUint16(): boolean { + return __S.getUint16(0, this) === 7; + } + setUint16(): void { + __S.setUint16(0, 7, this); + } + isUint32(): boolean { + return __S.getUint16(0, this) === 8; + } + setUint32(): void { + __S.setUint16(0, 8, this); + } + isUint64(): boolean { + return __S.getUint16(0, this) === 9; + } + setUint64(): void { + __S.setUint16(0, 9, this); + } + isFloat32(): boolean { + return __S.getUint16(0, this) === 10; + } + setFloat32(): void { + __S.setUint16(0, 10, this); + } + isFloat64(): boolean { + return __S.getUint16(0, this) === 11; + } + setFloat64(): void { + __S.setUint16(0, 11, this); + } + isText(): boolean { + return __S.getUint16(0, this) === 12; + } + setText(): void { + __S.setUint16(0, 12, this); + } + isData(): boolean { + return __S.getUint16(0, this) === 13; + } + setData(): void { + __S.setUint16(0, 13, this); + } + getList(): Type_List { + __S.testWhich("list", __S.getUint16(0, this), 14, this); + return __S.getAs(Type_List, this); + } + initList(): Type_List { + __S.setUint16(0, 14, this); + return __S.getAs(Type_List, this); + } + isList(): boolean { + return __S.getUint16(0, this) === 14; + } + setList(): void { + __S.setUint16(0, 14, this); + } + getEnum(): Type_Enum { + __S.testWhich("enum", __S.getUint16(0, this), 15, this); + return __S.getAs(Type_Enum, this); + } + initEnum(): Type_Enum { + __S.setUint16(0, 15, this); + return __S.getAs(Type_Enum, this); + } + isEnum(): boolean { + return __S.getUint16(0, this) === 15; + } + setEnum(): void { + __S.setUint16(0, 15, this); + } + getStruct(): Type_Struct { + __S.testWhich("struct", __S.getUint16(0, this), 16, this); + return __S.getAs(Type_Struct, this); + } + initStruct(): Type_Struct { + __S.setUint16(0, 16, this); + return __S.getAs(Type_Struct, this); + } + isStruct(): boolean { + return __S.getUint16(0, this) === 16; + } + setStruct(): void { + __S.setUint16(0, 16, this); + } + getInterface(): Type_Interface { + __S.testWhich("interface", __S.getUint16(0, this), 17, this); + return __S.getAs(Type_Interface, this); + } + initInterface(): Type_Interface { + __S.setUint16(0, 17, this); + return __S.getAs(Type_Interface, this); + } + isInterface(): boolean { + return __S.getUint16(0, this) === 17; + } + setInterface(): void { + __S.setUint16(0, 17, this); + } + getAnyPointer(): Type_AnyPointer { + __S.testWhich("anyPointer", __S.getUint16(0, this), 18, this); + return __S.getAs(Type_AnyPointer, this); + } + initAnyPointer(): Type_AnyPointer { + __S.setUint16(0, 18, this); + return __S.getAs(Type_AnyPointer, this); + } + isAnyPointer(): boolean { + return __S.getUint16(0, this) === 18; + } + setAnyPointer(): void { + __S.setUint16(0, 18, this); + } + toString(): string { + return "Type_" + super.toString(); + } + which(): Type_Which { + return __S.getUint16(0, this); + } } export enum Brand_Scope_Which { - BIND = 0, - INHERIT = 1 + BIND = 0, + INHERIT = 1, } export class Brand_Scope extends __S { - static readonly BIND = Brand_Scope_Which.BIND; - static readonly INHERIT = Brand_Scope_Which.INHERIT; - static readonly _capnp = { displayName: "Scope", id: "abd73485a9636bc9", size: new __O(16, 1) }; - static _Bind: capnp.ListCtor; - getScopeId(): bigint { return __S.getUint64(0, this); } - setScopeId(value: bigint): void { __S.setUint64(0, value, this); } - adoptBind(value: capnp.Orphan>): void { - __S.setUint16(8, 0, this); - __S.adopt(value, __S.getPointer(0, this)); - } - disownBind(): capnp.Orphan> { return __S.disown(this.getBind()); } - getBind(): capnp.List { - __S.testWhich("bind", __S.getUint16(8, this), 0, this); - return __S.getList(0, Brand_Scope._Bind, this); - } - hasBind(): boolean { return !__S.isNull(__S.getPointer(0, this)); } - initBind(length: number): capnp.List { - __S.setUint16(8, 0, this); - return __S.initList(0, Brand_Scope._Bind, length, this); - } - isBind(): boolean { return __S.getUint16(8, this) === 0; } - setBind(value: capnp.List): void { - __S.setUint16(8, 0, this); - __S.copyFrom(value, __S.getPointer(0, this)); - } - isInherit(): boolean { return __S.getUint16(8, this) === 1; } - setInherit(): void { __S.setUint16(8, 1, this); } - toString(): string { return "Brand_Scope_" + super.toString(); } - which(): Brand_Scope_Which { return __S.getUint16(8, this); } + static readonly BIND = Brand_Scope_Which.BIND; + static readonly INHERIT = Brand_Scope_Which.INHERIT; + static readonly _capnp = { displayName: "Scope", id: "abd73485a9636bc9", size: new __O(16, 1) }; + static _Bind: capnp.ListCtor; + getScopeId(): bigint { + return __S.getUint64(0, this); + } + setScopeId(value: bigint): void { + __S.setUint64(0, value, this); + } + adoptBind(value: capnp.Orphan>): void { + __S.setUint16(8, 0, this); + __S.adopt(value, __S.getPointer(0, this)); + } + disownBind(): capnp.Orphan> { + return __S.disown(this.getBind()); + } + getBind(): capnp.List { + __S.testWhich("bind", __S.getUint16(8, this), 0, this); + return __S.getList(0, Brand_Scope._Bind, this); + } + hasBind(): boolean { + return !__S.isNull(__S.getPointer(0, this)); + } + initBind(length: number): capnp.List { + __S.setUint16(8, 0, this); + return __S.initList(0, Brand_Scope._Bind, length, this); + } + isBind(): boolean { + return __S.getUint16(8, this) === 0; + } + setBind(value: capnp.List): void { + __S.setUint16(8, 0, this); + __S.copyFrom(value, __S.getPointer(0, this)); + } + isInherit(): boolean { + return __S.getUint16(8, this) === 1; + } + setInherit(): void { + __S.setUint16(8, 1, this); + } + toString(): string { + return "Brand_Scope_" + super.toString(); + } + which(): Brand_Scope_Which { + return __S.getUint16(8, this); + } } export enum Brand_Binding_Which { - UNBOUND = 0, - TYPE = 1 + UNBOUND = 0, + TYPE = 1, } export class Brand_Binding extends __S { - static readonly UNBOUND = Brand_Binding_Which.UNBOUND; - static readonly TYPE = Brand_Binding_Which.TYPE; - static readonly _capnp = { displayName: "Binding", id: "c863cd16969ee7fc", size: new __O(8, 1) }; - isUnbound(): boolean { return __S.getUint16(0, this) === 0; } - setUnbound(): void { __S.setUint16(0, 0, this); } - adoptType(value: capnp.Orphan): void { - __S.setUint16(0, 1, this); - __S.adopt(value, __S.getPointer(0, this)); - } - disownType(): capnp.Orphan { return __S.disown(this.getType()); } - getType(): Type { - __S.testWhich("type", __S.getUint16(0, this), 1, this); - return __S.getStruct(0, Type, this); - } - hasType(): boolean { return !__S.isNull(__S.getPointer(0, this)); } - initType(): Type { - __S.setUint16(0, 1, this); - return __S.initStructAt(0, Type, this); - } - isType(): boolean { return __S.getUint16(0, this) === 1; } - setType(value: Type): void { - __S.setUint16(0, 1, this); - __S.copyFrom(value, __S.getPointer(0, this)); - } - toString(): string { return "Brand_Binding_" + super.toString(); } - which(): Brand_Binding_Which { return __S.getUint16(0, this); } + static readonly UNBOUND = Brand_Binding_Which.UNBOUND; + static readonly TYPE = Brand_Binding_Which.TYPE; + static readonly _capnp = { displayName: "Binding", id: "c863cd16969ee7fc", size: new __O(8, 1) }; + isUnbound(): boolean { + return __S.getUint16(0, this) === 0; + } + setUnbound(): void { + __S.setUint16(0, 0, this); + } + adoptType(value: capnp.Orphan): void { + __S.setUint16(0, 1, this); + __S.adopt(value, __S.getPointer(0, this)); + } + disownType(): capnp.Orphan { + return __S.disown(this.getType()); + } + getType(): Type { + __S.testWhich("type", __S.getUint16(0, this), 1, this); + return __S.getStruct(0, Type, this); + } + hasType(): boolean { + return !__S.isNull(__S.getPointer(0, this)); + } + initType(): Type { + __S.setUint16(0, 1, this); + return __S.initStructAt(0, Type, this); + } + isType(): boolean { + return __S.getUint16(0, this) === 1; + } + setType(value: Type): void { + __S.setUint16(0, 1, this); + __S.copyFrom(value, __S.getPointer(0, this)); + } + toString(): string { + return "Brand_Binding_" + super.toString(); + } + which(): Brand_Binding_Which { + return __S.getUint16(0, this); + } } export class Brand extends __S { - static readonly Scope = Brand_Scope; - static readonly Binding = Brand_Binding; - static readonly _capnp = { displayName: "Brand", id: "903455f06065422b", size: new __O(0, 1) }; - static _Scopes: capnp.ListCtor; - adoptScopes(value: capnp.Orphan>): void { __S.adopt(value, __S.getPointer(0, this)); } - disownScopes(): capnp.Orphan> { return __S.disown(this.getScopes()); } - getScopes(): capnp.List { return __S.getList(0, Brand._Scopes, this); } - hasScopes(): boolean { return !__S.isNull(__S.getPointer(0, this)); } - initScopes(length: number): capnp.List { return __S.initList(0, Brand._Scopes, length, this); } - setScopes(value: capnp.List): void { __S.copyFrom(value, __S.getPointer(0, this)); } - toString(): string { return "Brand_" + super.toString(); } + static readonly Scope = Brand_Scope; + static readonly Binding = Brand_Binding; + static readonly _capnp = { displayName: "Brand", id: "903455f06065422b", size: new __O(0, 1) }; + static _Scopes: capnp.ListCtor; + adoptScopes(value: capnp.Orphan>): void { + __S.adopt(value, __S.getPointer(0, this)); + } + disownScopes(): capnp.Orphan> { + return __S.disown(this.getScopes()); + } + getScopes(): capnp.List { + return __S.getList(0, Brand._Scopes, this); + } + hasScopes(): boolean { + return !__S.isNull(__S.getPointer(0, this)); + } + initScopes(length: number): capnp.List { + return __S.initList(0, Brand._Scopes, length, this); + } + setScopes(value: capnp.List): void { + __S.copyFrom(value, __S.getPointer(0, this)); + } + toString(): string { + return "Brand_" + super.toString(); + } } export enum Value_Which { - VOID = 0, - BOOL = 1, - INT8 = 2, - INT16 = 3, - INT32 = 4, - INT64 = 5, - UINT8 = 6, - UINT16 = 7, - UINT32 = 8, - UINT64 = 9, - FLOAT32 = 10, - FLOAT64 = 11, - TEXT = 12, - DATA = 13, - LIST = 14, - ENUM = 15, - STRUCT = 16, - INTERFACE = 17, - ANY_POINTER = 18 + VOID = 0, + BOOL = 1, + INT8 = 2, + INT16 = 3, + INT32 = 4, + INT64 = 5, + UINT8 = 6, + UINT16 = 7, + UINT32 = 8, + UINT64 = 9, + FLOAT32 = 10, + FLOAT64 = 11, + TEXT = 12, + DATA = 13, + LIST = 14, + ENUM = 15, + STRUCT = 16, + INTERFACE = 17, + ANY_POINTER = 18, } export class Value extends __S { - static readonly VOID = Value_Which.VOID; - static readonly BOOL = Value_Which.BOOL; - static readonly INT8 = Value_Which.INT8; - static readonly INT16 = Value_Which.INT16; - static readonly INT32 = Value_Which.INT32; - static readonly INT64 = Value_Which.INT64; - static readonly UINT8 = Value_Which.UINT8; - static readonly UINT16 = Value_Which.UINT16; - static readonly UINT32 = Value_Which.UINT32; - static readonly UINT64 = Value_Which.UINT64; - static readonly FLOAT32 = Value_Which.FLOAT32; - static readonly FLOAT64 = Value_Which.FLOAT64; - static readonly TEXT = Value_Which.TEXT; - static readonly DATA = Value_Which.DATA; - static readonly LIST = Value_Which.LIST; - static readonly ENUM = Value_Which.ENUM; - static readonly STRUCT = Value_Which.STRUCT; - static readonly INTERFACE = Value_Which.INTERFACE; - static readonly ANY_POINTER = Value_Which.ANY_POINTER; - static readonly _capnp = { displayName: "Value", id: "ce23dcd2d7b00c9b", size: new __O(16, 1) }; - isVoid(): boolean { return __S.getUint16(0, this) === 0; } - setVoid(): void { __S.setUint16(0, 0, this); } - getBool(): boolean { - __S.testWhich("bool", __S.getUint16(0, this), 1, this); - return __S.getBit(16, this); - } - isBool(): boolean { return __S.getUint16(0, this) === 1; } - setBool(value: boolean): void { - __S.setUint16(0, 1, this); - __S.setBit(16, value, this); - } - getInt8(): number { - __S.testWhich("int8", __S.getUint16(0, this), 2, this); - return __S.getInt8(2, this); - } - isInt8(): boolean { return __S.getUint16(0, this) === 2; } - setInt8(value: number): void { - __S.setUint16(0, 2, this); - __S.setInt8(2, value, this); - } - getInt16(): number { - __S.testWhich("int16", __S.getUint16(0, this), 3, this); - return __S.getInt16(2, this); - } - isInt16(): boolean { return __S.getUint16(0, this) === 3; } - setInt16(value: number): void { - __S.setUint16(0, 3, this); - __S.setInt16(2, value, this); - } - getInt32(): number { - __S.testWhich("int32", __S.getUint16(0, this), 4, this); - return __S.getInt32(4, this); - } - isInt32(): boolean { return __S.getUint16(0, this) === 4; } - setInt32(value: number): void { - __S.setUint16(0, 4, this); - __S.setInt32(4, value, this); - } - getInt64(): bigint { - __S.testWhich("int64", __S.getUint16(0, this), 5, this); - return __S.getInt64(8, this); - } - isInt64(): boolean { return __S.getUint16(0, this) === 5; } - setInt64(value: bigint): void { - __S.setUint16(0, 5, this); - __S.setInt64(8, value, this); - } - getUint8(): number { - __S.testWhich("uint8", __S.getUint16(0, this), 6, this); - return __S.getUint8(2, this); - } - isUint8(): boolean { return __S.getUint16(0, this) === 6; } - setUint8(value: number): void { - __S.setUint16(0, 6, this); - __S.setUint8(2, value, this); - } - getUint16(): number { - __S.testWhich("uint16", __S.getUint16(0, this), 7, this); - return __S.getUint16(2, this); - } - isUint16(): boolean { return __S.getUint16(0, this) === 7; } - setUint16(value: number): void { - __S.setUint16(0, 7, this); - __S.setUint16(2, value, this); - } - getUint32(): number { - __S.testWhich("uint32", __S.getUint16(0, this), 8, this); - return __S.getUint32(4, this); - } - isUint32(): boolean { return __S.getUint16(0, this) === 8; } - setUint32(value: number): void { - __S.setUint16(0, 8, this); - __S.setUint32(4, value, this); - } - getUint64(): bigint { - __S.testWhich("uint64", __S.getUint16(0, this), 9, this); - return __S.getUint64(8, this); - } - isUint64(): boolean { return __S.getUint16(0, this) === 9; } - setUint64(value: bigint): void { - __S.setUint16(0, 9, this); - __S.setUint64(8, value, this); - } - getFloat32(): number { - __S.testWhich("float32", __S.getUint16(0, this), 10, this); - return __S.getFloat32(4, this); - } - isFloat32(): boolean { return __S.getUint16(0, this) === 10; } - setFloat32(value: number): void { - __S.setUint16(0, 10, this); - __S.setFloat32(4, value, this); - } - getFloat64(): number { - __S.testWhich("float64", __S.getUint16(0, this), 11, this); - return __S.getFloat64(8, this); - } - isFloat64(): boolean { return __S.getUint16(0, this) === 11; } - setFloat64(value: number): void { - __S.setUint16(0, 11, this); - __S.setFloat64(8, value, this); - } - getText(): string { - __S.testWhich("text", __S.getUint16(0, this), 12, this); - return __S.getText(0, this); - } - isText(): boolean { return __S.getUint16(0, this) === 12; } - setText(value: string): void { - __S.setUint16(0, 12, this); - __S.setText(0, value, this); - } - adoptData(value: capnp.Orphan): void { - __S.setUint16(0, 13, this); - __S.adopt(value, __S.getPointer(0, this)); - } - disownData(): capnp.Orphan { return __S.disown(this.getData()); } - getData(): capnp.Data { - __S.testWhich("data", __S.getUint16(0, this), 13, this); - return __S.getData(0, this); - } - hasData(): boolean { return !__S.isNull(__S.getPointer(0, this)); } - initData(length: number): capnp.Data { - __S.setUint16(0, 13, this); - return __S.initData(0, length, this); - } - isData(): boolean { return __S.getUint16(0, this) === 13; } - setData(value: capnp.Data): void { - __S.setUint16(0, 13, this); - __S.copyFrom(value, __S.getPointer(0, this)); - } - adoptList(value: capnp.Orphan): void { - __S.setUint16(0, 14, this); - __S.adopt(value, __S.getPointer(0, this)); - } - disownList(): capnp.Orphan { return __S.disown(this.getList()); } - getList(): capnp.Pointer { - __S.testWhich("list", __S.getUint16(0, this), 14, this); - return __S.getPointer(0, this); - } - hasList(): boolean { return !__S.isNull(__S.getPointer(0, this)); } - isList(): boolean { return __S.getUint16(0, this) === 14; } - setList(value: capnp.Pointer): void { - __S.setUint16(0, 14, this); - __S.copyFrom(value, __S.getPointer(0, this)); - } - getEnum(): number { - __S.testWhich("enum", __S.getUint16(0, this), 15, this); - return __S.getUint16(2, this); - } - isEnum(): boolean { return __S.getUint16(0, this) === 15; } - setEnum(value: number): void { - __S.setUint16(0, 15, this); - __S.setUint16(2, value, this); - } - adoptStruct(value: capnp.Orphan): void { - __S.setUint16(0, 16, this); - __S.adopt(value, __S.getPointer(0, this)); - } - disownStruct(): capnp.Orphan { return __S.disown(this.getStruct()); } - getStruct(): capnp.Pointer { - __S.testWhich("struct", __S.getUint16(0, this), 16, this); - return __S.getPointer(0, this); - } - hasStruct(): boolean { return !__S.isNull(__S.getPointer(0, this)); } - isStruct(): boolean { return __S.getUint16(0, this) === 16; } - setStruct(value: capnp.Pointer): void { - __S.setUint16(0, 16, this); - __S.copyFrom(value, __S.getPointer(0, this)); - } - isInterface(): boolean { return __S.getUint16(0, this) === 17; } - setInterface(): void { __S.setUint16(0, 17, this); } - adoptAnyPointer(value: capnp.Orphan): void { - __S.setUint16(0, 18, this); - __S.adopt(value, __S.getPointer(0, this)); - } - disownAnyPointer(): capnp.Orphan { return __S.disown(this.getAnyPointer()); } - getAnyPointer(): capnp.Pointer { - __S.testWhich("anyPointer", __S.getUint16(0, this), 18, this); - return __S.getPointer(0, this); - } - hasAnyPointer(): boolean { return !__S.isNull(__S.getPointer(0, this)); } - isAnyPointer(): boolean { return __S.getUint16(0, this) === 18; } - setAnyPointer(value: capnp.Pointer): void { - __S.setUint16(0, 18, this); - __S.copyFrom(value, __S.getPointer(0, this)); - } - toString(): string { return "Value_" + super.toString(); } - which(): Value_Which { return __S.getUint16(0, this); } + static readonly VOID = Value_Which.VOID; + static readonly BOOL = Value_Which.BOOL; + static readonly INT8 = Value_Which.INT8; + static readonly INT16 = Value_Which.INT16; + static readonly INT32 = Value_Which.INT32; + static readonly INT64 = Value_Which.INT64; + static readonly UINT8 = Value_Which.UINT8; + static readonly UINT16 = Value_Which.UINT16; + static readonly UINT32 = Value_Which.UINT32; + static readonly UINT64 = Value_Which.UINT64; + static readonly FLOAT32 = Value_Which.FLOAT32; + static readonly FLOAT64 = Value_Which.FLOAT64; + static readonly TEXT = Value_Which.TEXT; + static readonly DATA = Value_Which.DATA; + static readonly LIST = Value_Which.LIST; + static readonly ENUM = Value_Which.ENUM; + static readonly STRUCT = Value_Which.STRUCT; + static readonly INTERFACE = Value_Which.INTERFACE; + static readonly ANY_POINTER = Value_Which.ANY_POINTER; + static readonly _capnp = { displayName: "Value", id: "ce23dcd2d7b00c9b", size: new __O(16, 1) }; + isVoid(): boolean { + return __S.getUint16(0, this) === 0; + } + setVoid(): void { + __S.setUint16(0, 0, this); + } + getBool(): boolean { + __S.testWhich("bool", __S.getUint16(0, this), 1, this); + return __S.getBit(16, this); + } + isBool(): boolean { + return __S.getUint16(0, this) === 1; + } + setBool(value: boolean): void { + __S.setUint16(0, 1, this); + __S.setBit(16, value, this); + } + getInt8(): number { + __S.testWhich("int8", __S.getUint16(0, this), 2, this); + return __S.getInt8(2, this); + } + isInt8(): boolean { + return __S.getUint16(0, this) === 2; + } + setInt8(value: number): void { + __S.setUint16(0, 2, this); + __S.setInt8(2, value, this); + } + getInt16(): number { + __S.testWhich("int16", __S.getUint16(0, this), 3, this); + return __S.getInt16(2, this); + } + isInt16(): boolean { + return __S.getUint16(0, this) === 3; + } + setInt16(value: number): void { + __S.setUint16(0, 3, this); + __S.setInt16(2, value, this); + } + getInt32(): number { + __S.testWhich("int32", __S.getUint16(0, this), 4, this); + return __S.getInt32(4, this); + } + isInt32(): boolean { + return __S.getUint16(0, this) === 4; + } + setInt32(value: number): void { + __S.setUint16(0, 4, this); + __S.setInt32(4, value, this); + } + getInt64(): bigint { + __S.testWhich("int64", __S.getUint16(0, this), 5, this); + return __S.getInt64(8, this); + } + isInt64(): boolean { + return __S.getUint16(0, this) === 5; + } + setInt64(value: bigint): void { + __S.setUint16(0, 5, this); + __S.setInt64(8, value, this); + } + getUint8(): number { + __S.testWhich("uint8", __S.getUint16(0, this), 6, this); + return __S.getUint8(2, this); + } + isUint8(): boolean { + return __S.getUint16(0, this) === 6; + } + setUint8(value: number): void { + __S.setUint16(0, 6, this); + __S.setUint8(2, value, this); + } + getUint16(): number { + __S.testWhich("uint16", __S.getUint16(0, this), 7, this); + return __S.getUint16(2, this); + } + isUint16(): boolean { + return __S.getUint16(0, this) === 7; + } + setUint16(value: number): void { + __S.setUint16(0, 7, this); + __S.setUint16(2, value, this); + } + getUint32(): number { + __S.testWhich("uint32", __S.getUint16(0, this), 8, this); + return __S.getUint32(4, this); + } + isUint32(): boolean { + return __S.getUint16(0, this) === 8; + } + setUint32(value: number): void { + __S.setUint16(0, 8, this); + __S.setUint32(4, value, this); + } + getUint64(): bigint { + __S.testWhich("uint64", __S.getUint16(0, this), 9, this); + return __S.getUint64(8, this); + } + isUint64(): boolean { + return __S.getUint16(0, this) === 9; + } + setUint64(value: bigint): void { + __S.setUint16(0, 9, this); + __S.setUint64(8, value, this); + } + getFloat32(): number { + __S.testWhich("float32", __S.getUint16(0, this), 10, this); + return __S.getFloat32(4, this); + } + isFloat32(): boolean { + return __S.getUint16(0, this) === 10; + } + setFloat32(value: number): void { + __S.setUint16(0, 10, this); + __S.setFloat32(4, value, this); + } + getFloat64(): number { + __S.testWhich("float64", __S.getUint16(0, this), 11, this); + return __S.getFloat64(8, this); + } + isFloat64(): boolean { + return __S.getUint16(0, this) === 11; + } + setFloat64(value: number): void { + __S.setUint16(0, 11, this); + __S.setFloat64(8, value, this); + } + getText(): string { + __S.testWhich("text", __S.getUint16(0, this), 12, this); + return __S.getText(0, this); + } + isText(): boolean { + return __S.getUint16(0, this) === 12; + } + setText(value: string): void { + __S.setUint16(0, 12, this); + __S.setText(0, value, this); + } + adoptData(value: capnp.Orphan): void { + __S.setUint16(0, 13, this); + __S.adopt(value, __S.getPointer(0, this)); + } + disownData(): capnp.Orphan { + return __S.disown(this.getData()); + } + getData(): capnp.Data { + __S.testWhich("data", __S.getUint16(0, this), 13, this); + return __S.getData(0, this); + } + hasData(): boolean { + return !__S.isNull(__S.getPointer(0, this)); + } + initData(length: number): capnp.Data { + __S.setUint16(0, 13, this); + return __S.initData(0, length, this); + } + isData(): boolean { + return __S.getUint16(0, this) === 13; + } + setData(value: capnp.Data): void { + __S.setUint16(0, 13, this); + __S.copyFrom(value, __S.getPointer(0, this)); + } + adoptList(value: capnp.Orphan): void { + __S.setUint16(0, 14, this); + __S.adopt(value, __S.getPointer(0, this)); + } + disownList(): capnp.Orphan { + return __S.disown(this.getList()); + } + getList(): capnp.Pointer { + __S.testWhich("list", __S.getUint16(0, this), 14, this); + return __S.getPointer(0, this); + } + hasList(): boolean { + return !__S.isNull(__S.getPointer(0, this)); + } + isList(): boolean { + return __S.getUint16(0, this) === 14; + } + setList(value: capnp.Pointer): void { + __S.setUint16(0, 14, this); + __S.copyFrom(value, __S.getPointer(0, this)); + } + getEnum(): number { + __S.testWhich("enum", __S.getUint16(0, this), 15, this); + return __S.getUint16(2, this); + } + isEnum(): boolean { + return __S.getUint16(0, this) === 15; + } + setEnum(value: number): void { + __S.setUint16(0, 15, this); + __S.setUint16(2, value, this); + } + adoptStruct(value: capnp.Orphan): void { + __S.setUint16(0, 16, this); + __S.adopt(value, __S.getPointer(0, this)); + } + disownStruct(): capnp.Orphan { + return __S.disown(this.getStruct()); + } + getStruct(): capnp.Pointer { + __S.testWhich("struct", __S.getUint16(0, this), 16, this); + return __S.getPointer(0, this); + } + hasStruct(): boolean { + return !__S.isNull(__S.getPointer(0, this)); + } + isStruct(): boolean { + return __S.getUint16(0, this) === 16; + } + setStruct(value: capnp.Pointer): void { + __S.setUint16(0, 16, this); + __S.copyFrom(value, __S.getPointer(0, this)); + } + isInterface(): boolean { + return __S.getUint16(0, this) === 17; + } + setInterface(): void { + __S.setUint16(0, 17, this); + } + adoptAnyPointer(value: capnp.Orphan): void { + __S.setUint16(0, 18, this); + __S.adopt(value, __S.getPointer(0, this)); + } + disownAnyPointer(): capnp.Orphan { + return __S.disown(this.getAnyPointer()); + } + getAnyPointer(): capnp.Pointer { + __S.testWhich("anyPointer", __S.getUint16(0, this), 18, this); + return __S.getPointer(0, this); + } + hasAnyPointer(): boolean { + return !__S.isNull(__S.getPointer(0, this)); + } + isAnyPointer(): boolean { + return __S.getUint16(0, this) === 18; + } + setAnyPointer(value: capnp.Pointer): void { + __S.setUint16(0, 18, this); + __S.copyFrom(value, __S.getPointer(0, this)); + } + toString(): string { + return "Value_" + super.toString(); + } + which(): Value_Which { + return __S.getUint16(0, this); + } } export class Annotation extends __S { - static readonly _capnp = { displayName: "Annotation", id: "f1c8950dab257542", size: new __O(8, 2) }; - getId(): bigint { return __S.getUint64(0, this); } - setId(value: bigint): void { __S.setUint64(0, value, this); } - adoptBrand(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(1, this)); } - disownBrand(): capnp.Orphan { return __S.disown(this.getBrand()); } - getBrand(): Brand { return __S.getStruct(1, Brand, this); } - hasBrand(): boolean { return !__S.isNull(__S.getPointer(1, this)); } - initBrand(): Brand { return __S.initStructAt(1, Brand, this); } - setBrand(value: Brand): void { __S.copyFrom(value, __S.getPointer(1, this)); } - adoptValue(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(0, this)); } - disownValue(): capnp.Orphan { return __S.disown(this.getValue()); } - getValue(): Value { return __S.getStruct(0, Value, this); } - hasValue(): boolean { return !__S.isNull(__S.getPointer(0, this)); } - initValue(): Value { return __S.initStructAt(0, Value, this); } - setValue(value: Value): void { __S.copyFrom(value, __S.getPointer(0, this)); } - toString(): string { return "Annotation_" + super.toString(); } + static readonly _capnp = { displayName: "Annotation", id: "f1c8950dab257542", size: new __O(8, 2) }; + getId(): bigint { + return __S.getUint64(0, this); + } + setId(value: bigint): void { + __S.setUint64(0, value, this); + } + adoptBrand(value: capnp.Orphan): void { + __S.adopt(value, __S.getPointer(1, this)); + } + disownBrand(): capnp.Orphan { + return __S.disown(this.getBrand()); + } + getBrand(): Brand { + return __S.getStruct(1, Brand, this); + } + hasBrand(): boolean { + return !__S.isNull(__S.getPointer(1, this)); + } + initBrand(): Brand { + return __S.initStructAt(1, Brand, this); + } + setBrand(value: Brand): void { + __S.copyFrom(value, __S.getPointer(1, this)); + } + adoptValue(value: capnp.Orphan): void { + __S.adopt(value, __S.getPointer(0, this)); + } + disownValue(): capnp.Orphan { + return __S.disown(this.getValue()); + } + getValue(): Value { + return __S.getStruct(0, Value, this); + } + hasValue(): boolean { + return !__S.isNull(__S.getPointer(0, this)); + } + initValue(): Value { + return __S.initStructAt(0, Value, this); + } + setValue(value: Value): void { + __S.copyFrom(value, __S.getPointer(0, this)); + } + toString(): string { + return "Annotation_" + super.toString(); + } } export enum ElementSize { - EMPTY, - BIT, - BYTE, - TWO_BYTES, - FOUR_BYTES, - EIGHT_BYTES, - POINTER, - INLINE_COMPOSITE + EMPTY, + BIT, + BYTE, + TWO_BYTES, + FOUR_BYTES, + EIGHT_BYTES, + POINTER, + INLINE_COMPOSITE, } export class CapnpVersion extends __S { - static readonly _capnp = { displayName: "CapnpVersion", id: "d85d305b7d839963", size: new __O(8, 0) }; - getMajor(): number { return __S.getUint16(0, this); } - setMajor(value: number): void { __S.setUint16(0, value, this); } - getMinor(): number { return __S.getUint8(2, this); } - setMinor(value: number): void { __S.setUint8(2, value, this); } - getMicro(): number { return __S.getUint8(3, this); } - setMicro(value: number): void { __S.setUint8(3, value, this); } - toString(): string { return "CapnpVersion_" + super.toString(); } + static readonly _capnp = { displayName: "CapnpVersion", id: "d85d305b7d839963", size: new __O(8, 0) }; + getMajor(): number { + return __S.getUint16(0, this); + } + setMajor(value: number): void { + __S.setUint16(0, value, this); + } + getMinor(): number { + return __S.getUint8(2, this); + } + setMinor(value: number): void { + __S.setUint8(2, value, this); + } + getMicro(): number { + return __S.getUint8(3, this); + } + setMicro(value: number): void { + __S.setUint8(3, value, this); + } + toString(): string { + return "CapnpVersion_" + super.toString(); + } } export class CodeGeneratorRequest_RequestedFile_Import extends __S { - static readonly _capnp = { displayName: "Import", id: "ae504193122357e5", size: new __O(8, 1) }; - getId(): bigint { return __S.getUint64(0, this); } - setId(value: bigint): void { __S.setUint64(0, value, this); } - getName(): string { return __S.getText(0, this); } - setName(value: string): void { __S.setText(0, value, this); } - toString(): string { return "CodeGeneratorRequest_RequestedFile_Import_" + super.toString(); } + static readonly _capnp = { displayName: "Import", id: "ae504193122357e5", size: new __O(8, 1) }; + getId(): bigint { + return __S.getUint64(0, this); + } + setId(value: bigint): void { + __S.setUint64(0, value, this); + } + getName(): string { + return __S.getText(0, this); + } + setName(value: string): void { + __S.setText(0, value, this); + } + toString(): string { + return "CodeGeneratorRequest_RequestedFile_Import_" + super.toString(); + } } export class CodeGeneratorRequest_RequestedFile extends __S { - static readonly Import = CodeGeneratorRequest_RequestedFile_Import; - static readonly _capnp = { displayName: "RequestedFile", id: "cfea0eb02e810062", size: new __O(8, 2) }; - static _Imports: capnp.ListCtor; - getId(): bigint { return __S.getUint64(0, this); } - setId(value: bigint): void { __S.setUint64(0, value, this); } - getFilename(): string { return __S.getText(0, this); } - setFilename(value: string): void { __S.setText(0, value, this); } - adoptImports(value: capnp.Orphan>): void { __S.adopt(value, __S.getPointer(1, this)); } - disownImports(): capnp.Orphan> { return __S.disown(this.getImports()); } - getImports(): capnp.List { return __S.getList(1, CodeGeneratorRequest_RequestedFile._Imports, this); } - hasImports(): boolean { return !__S.isNull(__S.getPointer(1, this)); } - initImports(length: number): capnp.List { return __S.initList(1, CodeGeneratorRequest_RequestedFile._Imports, length, this); } - setImports(value: capnp.List): void { __S.copyFrom(value, __S.getPointer(1, this)); } - toString(): string { return "CodeGeneratorRequest_RequestedFile_" + super.toString(); } + static readonly Import = CodeGeneratorRequest_RequestedFile_Import; + static readonly _capnp = { displayName: "RequestedFile", id: "cfea0eb02e810062", size: new __O(8, 2) }; + static _Imports: capnp.ListCtor; + getId(): bigint { + return __S.getUint64(0, this); + } + setId(value: bigint): void { + __S.setUint64(0, value, this); + } + getFilename(): string { + return __S.getText(0, this); + } + setFilename(value: string): void { + __S.setText(0, value, this); + } + adoptImports(value: capnp.Orphan>): void { + __S.adopt(value, __S.getPointer(1, this)); + } + disownImports(): capnp.Orphan> { + return __S.disown(this.getImports()); + } + getImports(): capnp.List { + return __S.getList(1, CodeGeneratorRequest_RequestedFile._Imports, this); + } + hasImports(): boolean { + return !__S.isNull(__S.getPointer(1, this)); + } + initImports(length: number): capnp.List { + return __S.initList(1, CodeGeneratorRequest_RequestedFile._Imports, length, this); + } + setImports(value: capnp.List): void { + __S.copyFrom(value, __S.getPointer(1, this)); + } + toString(): string { + return "CodeGeneratorRequest_RequestedFile_" + super.toString(); + } } export class CodeGeneratorRequest extends __S { - static readonly RequestedFile = CodeGeneratorRequest_RequestedFile; - static readonly _capnp = { displayName: "CodeGeneratorRequest", id: "bfc546f6210ad7ce", size: new __O(0, 3) }; - static _Nodes: capnp.ListCtor; - static _RequestedFiles: capnp.ListCtor; - adoptCapnpVersion(value: capnp.Orphan): void { __S.adopt(value, __S.getPointer(2, this)); } - disownCapnpVersion(): capnp.Orphan { return __S.disown(this.getCapnpVersion()); } - getCapnpVersion(): CapnpVersion { return __S.getStruct(2, CapnpVersion, this); } - hasCapnpVersion(): boolean { return !__S.isNull(__S.getPointer(2, this)); } - initCapnpVersion(): CapnpVersion { return __S.initStructAt(2, CapnpVersion, this); } - setCapnpVersion(value: CapnpVersion): void { __S.copyFrom(value, __S.getPointer(2, this)); } - adoptNodes(value: capnp.Orphan>): void { __S.adopt(value, __S.getPointer(0, this)); } - disownNodes(): capnp.Orphan> { return __S.disown(this.getNodes()); } - getNodes(): capnp.List { return __S.getList(0, CodeGeneratorRequest._Nodes, this); } - hasNodes(): boolean { return !__S.isNull(__S.getPointer(0, this)); } - initNodes(length: number): capnp.List { return __S.initList(0, CodeGeneratorRequest._Nodes, length, this); } - setNodes(value: capnp.List): void { __S.copyFrom(value, __S.getPointer(0, this)); } - adoptRequestedFiles(value: capnp.Orphan>): void { __S.adopt(value, __S.getPointer(1, this)); } - disownRequestedFiles(): capnp.Orphan> { return __S.disown(this.getRequestedFiles()); } - getRequestedFiles(): capnp.List { return __S.getList(1, CodeGeneratorRequest._RequestedFiles, this); } - hasRequestedFiles(): boolean { return !__S.isNull(__S.getPointer(1, this)); } - initRequestedFiles(length: number): capnp.List { return __S.initList(1, CodeGeneratorRequest._RequestedFiles, length, this); } - setRequestedFiles(value: capnp.List): void { __S.copyFrom(value, __S.getPointer(1, this)); } - toString(): string { return "CodeGeneratorRequest_" + super.toString(); } + static readonly RequestedFile = CodeGeneratorRequest_RequestedFile; + static readonly _capnp = { displayName: "CodeGeneratorRequest", id: "bfc546f6210ad7ce", size: new __O(0, 3) }; + static _Nodes: capnp.ListCtor; + static _RequestedFiles: capnp.ListCtor; + adoptCapnpVersion(value: capnp.Orphan): void { + __S.adopt(value, __S.getPointer(2, this)); + } + disownCapnpVersion(): capnp.Orphan { + return __S.disown(this.getCapnpVersion()); + } + getCapnpVersion(): CapnpVersion { + return __S.getStruct(2, CapnpVersion, this); + } + hasCapnpVersion(): boolean { + return !__S.isNull(__S.getPointer(2, this)); + } + initCapnpVersion(): CapnpVersion { + return __S.initStructAt(2, CapnpVersion, this); + } + setCapnpVersion(value: CapnpVersion): void { + __S.copyFrom(value, __S.getPointer(2, this)); + } + adoptNodes(value: capnp.Orphan>): void { + __S.adopt(value, __S.getPointer(0, this)); + } + disownNodes(): capnp.Orphan> { + return __S.disown(this.getNodes()); + } + getNodes(): capnp.List { + return __S.getList(0, CodeGeneratorRequest._Nodes, this); + } + hasNodes(): boolean { + return !__S.isNull(__S.getPointer(0, this)); + } + initNodes(length: number): capnp.List { + return __S.initList(0, CodeGeneratorRequest._Nodes, length, this); + } + setNodes(value: capnp.List): void { + __S.copyFrom(value, __S.getPointer(0, this)); + } + adoptRequestedFiles(value: capnp.Orphan>): void { + __S.adopt(value, __S.getPointer(1, this)); + } + disownRequestedFiles(): capnp.Orphan> { + return __S.disown(this.getRequestedFiles()); + } + getRequestedFiles(): capnp.List { + return __S.getList(1, CodeGeneratorRequest._RequestedFiles, this); + } + hasRequestedFiles(): boolean { + return !__S.isNull(__S.getPointer(1, this)); + } + initRequestedFiles(length: number): capnp.List { + return __S.initList(1, CodeGeneratorRequest._RequestedFiles, length, this); + } + setRequestedFiles(value: capnp.List): void { + __S.copyFrom(value, __S.getPointer(1, this)); + } + toString(): string { + return "CodeGeneratorRequest_" + super.toString(); + } } Node_Struct._Fields = capnp.CompositeList(Field); Node_Enum._Enumerants = capnp.CompositeList(Enumerant); diff --git a/packages/capnp-ts/src/std/ts.capnp.ts b/packages/capnp-ts/src/std/ts.capnp.ts index c8713de..4b9cecf 100644 --- a/packages/capnp-ts/src/std/ts.capnp.ts +++ b/packages/capnp-ts/src/std/ts.capnp.ts @@ -4,5 +4,5 @@ */ import * as capnp from "../index"; -import { ObjectSize as __O, Struct as __S } from "../index"; +import { ObjectSize as __O, Struct as __S, Interface as __I } from '../index'; export const _capnpFileId = "e37ded525a68a7c9"; diff --git a/packages/capnp-ts/src/util.ts b/packages/capnp-ts/src/util.ts index dae1dac..34c64dc 100644 --- a/packages/capnp-ts/src/util.ts +++ b/packages/capnp-ts/src/util.ts @@ -2,16 +2,11 @@ * @author jdiaz5513 */ -// LINT: a lot of the util functions need the any type. -/* tslint:disable:no-any no-unsafe-any */ import initTrace from "debug"; import { MAX_BUFFER_DUMP_BYTES, MAX_INT32, MAX_UINT32 } from "./constants"; import { RANGE_INT32_OVERFLOW, RANGE_INVALID_UTF8, RANGE_UINT32_OVERFLOW } from "./errors"; -const trace = initTrace("capnp:util"); -trace("load"); - /** * Dump a hex string from the given buffer. * diff --git a/packages/capnpc-ts/src/ast-creators.ts b/packages/capnpc-ts/src/ast-creators.ts index 20a4a15..25631cb 100644 --- a/packages/capnpc-ts/src/ast-creators.ts +++ b/packages/capnpc-ts/src/ast-creators.ts @@ -6,14 +6,21 @@ import * as s from "capnp-ts/src/std/schema.capnp.js"; import * as capnp from "capnp-ts"; import { format, pad } from "capnp-ts/src/util"; import ts, { factory as f } from "typescript"; -import initTrace from "debug"; import { CodeGeneratorFileContext } from "./code-generator-file-context"; import { __, READONLY, STATIC, VOID_TYPE, CAPNP } from "./constants"; import * as E from "./errors"; import { getDisplayNamePrefix, getFullClassName, getJsType } from "./file"; import * as util from "./util"; -const trace = initTrace("capnpc:ast-creators"); +export function createBigIntExpression(value: bigint): ts.Expression { + let v = value.toString(16); + let neg = ""; + if (v[0] === "-") { + v = v.slice(1); + neg = "-"; + } + return f.createCallExpression(f.createIdentifier(`${neg}BigInt`), __, [f.createStringLiteral(`0x${v}`)]); +} export function createClassExtends(identifierText: string): ts.HeritageClause { const types = [f.createExpressionWithTypeArguments(f.createIdentifier(identifierText), [])]; @@ -81,8 +88,6 @@ export function createUnionConstProperty(fullClassName: string, field: s.Field): } export function createValueExpression(value: s.Value): ts.Expression { - trace("createValueExpression(%s)", value); - let p: capnp.Pointer; switch (value.which()) { @@ -105,13 +110,7 @@ export function createValueExpression(value: s.Value): ts.Expression { return f.createNumericLiteral(value.getInt32().toString()); case s.Value.INT64: { - let v = value.getInt64().toString(16); - let neg = ""; - if (v[0] === "-") { - v = v.slice(1); - neg = "-"; - } - return f.createCallExpression(f.createIdentifier(`${neg}BigInt`), __, [f.createStringLiteral(`0x${v}`)]); + return createBigIntExpression(value.getInt64()); } case s.Value.INT8: return f.createNumericLiteral(value.getInt8().toString()); @@ -126,9 +125,7 @@ export function createValueExpression(value: s.Value): ts.Expression { return f.createNumericLiteral(value.getUint32().toString()); case s.Value.UINT64: { - return f.createCallExpression(f.createIdentifier("BigInt"), __, [ - f.createStringLiteral(`0x${value.getUint64().toString(16)}`), - ]); + return createBigIntExpression(value.getUint64()); } case s.Value.UINT8: return f.createNumericLiteral(value.getUint8().toString()); @@ -157,6 +154,14 @@ export function createValueExpression(value: s.Value): ts.Expression { break; case s.Value.INTERFACE: + { + const __S = capnp.Struct; + __S.testWhich("interface", __S.getUint16(0, value), 17, value); + p = __S.getPointer(0, value); + } + + break; + default: throw new Error(format(E.GEN_SERIALIZE_UNKNOWN_VALUE, s.Value_Which[value.which()])); } diff --git a/packages/capnpc-ts/src/code-generator-file-context.ts b/packages/capnpc-ts/src/code-generator-file-context.ts index 05665a4..a0bf77c 100644 --- a/packages/capnpc-ts/src/code-generator-file-context.ts +++ b/packages/capnpc-ts/src/code-generator-file-context.ts @@ -9,6 +9,7 @@ export class CodeGeneratorFileContext { concreteLists: Array<[string, s.Field]>; file: s.CodeGeneratorRequest_RequestedFile; generatedNodeIds: string[]; + generatedResultsPromiseIds: Set; imports: s.CodeGeneratorRequest_RequestedFile_Import[]; nodes: s.Node[]; req: s.CodeGeneratorRequest; @@ -21,6 +22,7 @@ export class CodeGeneratorFileContext { this.nodes = req.getNodes().toArray(); this.concreteLists = []; this.generatedNodeIds = []; + this.generatedResultsPromiseIds = new Set(); this.statements = []; this.tsPath = ""; this.imports = file.getImports().toArray(); diff --git a/packages/capnpc-ts/src/compiler.ts b/packages/capnpc-ts/src/compiler.ts index 54d463b..33ec992 100644 --- a/packages/capnpc-ts/src/compiler.ts +++ b/packages/capnpc-ts/src/compiler.ts @@ -18,7 +18,6 @@ import { } from "./generators"; const trace = initTrace("capnpc:compile"); -trace("load"); export function compile(ctx: CodeGeneratorFileContext): string { generateCapnpImport(ctx); @@ -42,8 +41,6 @@ export function compile(ctx: CodeGeneratorFileContext): string { } export function loadRequest(req: s.CodeGeneratorRequest): CodeGeneratorContext { - trace("loadRequest(%s)", req); - const ctx = new CodeGeneratorContext(); ctx.files = req.getRequestedFiles().map((file) => loadRequestedFile(req, file)); @@ -52,14 +49,10 @@ export function loadRequest(req: s.CodeGeneratorRequest): CodeGeneratorContext { } export function printSourceFiles(ctx: CodeGeneratorContext): string[] { - trace("printSourceFiles()"); - return ctx.files.map(compile); } export function writeTsFiles(ctx: CodeGeneratorContext): void { - trace("writeTsFiles()"); - ctx.files.forEach((f) => { trace("writing %s", f.tsPath); diff --git a/packages/capnpc-ts/src/constants.ts b/packages/capnpc-ts/src/constants.ts index 7cdea3b..f03caf9 100644 --- a/packages/capnpc-ts/src/constants.ts +++ b/packages/capnpc-ts/src/constants.ts @@ -3,12 +3,8 @@ */ import * as s from "capnp-ts/src/std/schema.capnp.js"; -import initTrace from "debug"; import ts, { factory as f } from "typescript"; -const trace = initTrace("capnpc:constants"); -trace("load"); - /** undefined */ export const __ = undefined; @@ -154,8 +150,7 @@ export const READONLY = f.createToken(ts.SyntaxKind.ReadonlyKeyword); /** No... comment? */ -export const SOURCE_COMMENT = `/* tslint:disable */ - +export const SOURCE_COMMENT = ` /** * This file has been automatically generated by the [capnpc-ts utility](https://github.com/jdiaz5513/capnp-ts). */ @@ -166,6 +161,14 @@ export const SOURCE_COMMENT = `/* tslint:disable */ export const STATIC = f.createToken(ts.SyntaxKind.StaticKeyword); +/** async */ + +export const ASYNC = ts.createToken(ts.SyntaxKind.AsyncKeyword); + +/** ? */ + +export const QUESTION_TOKEN = ts.createToken(ts.SyntaxKind.QuestionToken); + /** string */ export const STRING_TYPE = f.createTypeReferenceNode("string", __); @@ -192,4 +195,8 @@ export const VALUE = f.createIdentifier("value"); /** void */ -export const VOID_TYPE = f.createTypeReferenceNode("void", __); +export const VOID_TYPE = ts.createTypeReferenceNode("void", __); + +/** any */ + +export const ANY_TYPE = ts.createTypeReferenceNode("any", __); diff --git a/packages/capnpc-ts/src/errors.ts b/packages/capnpc-ts/src/errors.ts index 3d5ad17..d24c2a0 100644 --- a/packages/capnpc-ts/src/errors.ts +++ b/packages/capnpc-ts/src/errors.ts @@ -1,27 +1,14 @@ -import initTrace from "debug"; - -const trace = initTrace("capnpc:errors"); -trace("load"); - export const GEN_EXPLICIT_DEFAULT_NON_PRIMITIVE = "CAPNPC-TS000 Don't know how to generate a %s field with an explicit default value."; -export const GEN_FIELD_NON_INLINE_STRUCT_LIST = - "CAPNPC-TS001 Don't know how to generate non-inline struct lists."; -export const GEN_NODE_LOOKUP_FAIL = - "CAPNPC-TS002 Failed to look up node id %s."; -export const GEN_NODE_UNKNOWN_TYPE = - 'CAPNPC-TS003 Don\'t know how to generate a "%s" node.'; -export const GEN_SERIALIZE_UNKNOWN_VALUE = - "CAPNPC-TS004 Don't know how to serialize a value of kind %s."; -export const GEN_UNKNOWN_STRUCT_FIELD = - "CAPNPC-TS005 Don't know how to generate a struct field of kind %d."; -export const GEN_UNKNOWN_TYPE = - "CAPNPC-TS006 Unknown slot type encountered: %d"; -export const GEN_UNSUPPORTED_LIST_ELEMENT_TYPE = - "CAPNPC-TS007 Encountered an unsupported list element type: %d"; +export const GEN_FIELD_NON_INLINE_STRUCT_LIST = "CAPNPC-TS001 Don't know how to generate non-inline struct lists."; +export const GEN_NODE_LOOKUP_FAIL = "CAPNPC-TS002 Failed to look up node id %s."; +export const GEN_NODE_UNKNOWN_TYPE = 'CAPNPC-TS003 Don\'t know how to generate a "%s" node.'; +export const GEN_SERIALIZE_UNKNOWN_VALUE = "CAPNPC-TS004 Don't know how to serialize a value of kind %s."; +export const GEN_UNKNOWN_STRUCT_FIELD = "CAPNPC-TS005 Don't know how to generate a struct field of kind %d."; +export const GEN_UNKNOWN_TYPE = "CAPNPC-TS006 Unknown slot type encountered: %d"; +export const GEN_UNSUPPORTED_LIST_ELEMENT_TYPE = "CAPNPC-TS007 Encountered an unsupported list element type: %d"; export const GEN_CAPNP_TS_IMPORT_CORRUPT = "CAPNPC-TS008 Was able to import ts.capnp but could not locate the importPath annotation definition."; export const GEN_TS_EMIT_FAILED = "CAPNPC-TS009 Failed to transpile emitted schema source code; see above for error messages."; -export const GEN_UNKNOWN_DEFAULT = - "CAPNPC-TS010 Don't know how to generate a default value for %s fields."; +export const GEN_UNKNOWN_DEFAULT = "CAPNPC-TS010 Don't know how to generate a default value for %s fields."; diff --git a/packages/capnpc-ts/src/file.ts b/packages/capnpc-ts/src/file.ts index 1c3721f..c08f2fd 100644 --- a/packages/capnpc-ts/src/file.ts +++ b/packages/capnpc-ts/src/file.ts @@ -8,7 +8,6 @@ import * as E from "./errors"; import * as util from "./util"; const trace = initTrace("capnpc:file"); -trace("load"); export function compareCodeOrder(a: { getCodeOrder(): number }, b: { getCodeOrder(): number }): number { return a.getCodeOrder() - b.getCodeOrder(); @@ -74,7 +73,7 @@ export function getJsType(ctx: CodeGeneratorFileContext, type: s.Type, construct return "bigint"; case s.Type.INTERFACE: - return "capnp.Interface"; + return getFullClassName(lookupNode(ctx, type.getInterface().getTypeId())); case s.Type.LIST: return `capnp.List${constructor ? "Ctor" : ""}<${getJsType(ctx, type.getList().getElementType(), false)}>`; diff --git a/packages/capnpc-ts/src/generators.ts b/packages/capnpc-ts/src/generators.ts index 7f7e41d..7417bfd 100644 --- a/packages/capnpc-ts/src/generators.ts +++ b/packages/capnpc-ts/src/generators.ts @@ -4,9 +4,11 @@ import initTrace from "debug"; import ts, { factory as f } from "typescript"; import { + createBigIntExpression, createClassExtends, createConcreteListProperty, createConstProperty, + createExpressionBlock, createMethod, createNestedNodeProperty, createUnionConstProperty, @@ -15,6 +17,7 @@ import { import { CodeGeneratorFileContext } from "./code-generator-file-context"; import { __, + ASYNC, BOOLEAN_TYPE, CAPNP, ConcreteListType, @@ -22,6 +25,7 @@ import { LENGTH, NUMBER_TYPE, Primitive, + QUESTION_TOKEN, READONLY, STATIC, STRING_TYPE, @@ -30,6 +34,7 @@ import { TS_FILE_ID, VALUE, VOID_TYPE, + ANY_TYPE, OBJECT_SIZE, BIGINT, } from "./constants"; @@ -48,7 +53,6 @@ import { import * as util from "./util"; const trace = initTrace("capnpc:generators"); -trace("load"); export function generateCapnpImport(ctx: CodeGeneratorFileContext): void { // Look for the special importPath annotation on the file to see if we need a different import path for capnp-ts. @@ -75,9 +79,11 @@ export function generateCapnpImport(ctx: CodeGeneratorFileContext): void { ) ); - // import { ObjectSize as __O, Struct as __S } from '${importPath}'; + // import { ObjectSize as __O, Struct as __S, Interface as __I } from '${importPath}'; ctx.statements.push( - f.createExpressionStatement(f.createIdentifier(`import { ObjectSize as __O, Struct as __S } from '${importPath}'`)) + ts.createStatement( + ts.createIdentifier(`import { ObjectSize as __O, Struct as __S, Interface as __I } from '${importPath}'`) + ) ); } @@ -98,7 +104,6 @@ export function generateNestedImports(ctx: CodeGeneratorFileContext): void { const importStatement = `import { ${imports} } from "${importPath}"`; - trace("emitting import statement:", importStatement); ctx.statements.push(f.createExpressionStatement(f.createIdentifier(importStatement))); }); } @@ -126,6 +131,7 @@ export function generateDefaultValue(field: s.Field): ts.PropertyAssignment { case s.Type_Which.DATA: case s.Type_Which.LIST: case s.Type_Which.STRUCT: + case s.Type_Which.INTERFACE: initializer = createValueExpression(slot.getDefaultValue()); break; @@ -168,8 +174,6 @@ export function generateDefaultValue(field: s.Field): ts.PropertyAssignment { } export function generateEnumNode(ctx: CodeGeneratorFileContext, node: s.Node): void { - trace("generateEnumNode(%s) [%s]", node, node.getDisplayName()); - const members = node .getEnum() .getEnumerants() @@ -182,8 +186,6 @@ export function generateEnumNode(ctx: CodeGeneratorFileContext, node: s.Node): v } export function generateFileId(ctx: CodeGeneratorFileContext): void { - trace("generateFileId()"); - // export const _capnpFileId = BigInt('0xabcdef'); const fileId = f.createCallExpression(BIGINT, __, [f.createStringLiteral(`0x${ctx.file.getId().toString(16)}`)]); ctx.statements.push( @@ -194,16 +196,404 @@ export function generateFileId(ctx: CodeGeneratorFileContext): void { ); } -export function generateInterfaceClasses(_ctx: CodeGeneratorFileContext, node: s.Node): void { - trace("Interface generation is not yet implemented."); +export function generateInterfaceClasses(ctx: CodeGeneratorFileContext, node: s.Node): void { + // Generate the parameter and result structs first + generateMethodStructs(ctx, node); - /* tslint:disable-next-line */ - console.error(`CAPNP-TS: Warning! Interface generation (${node.getDisplayName()}) is not yet implemented.`); + // Now generate the client & server classes + generateClient(ctx, node); + generateServer(ctx, node); } -export function generateNode(ctx: CodeGeneratorFileContext, node: s.Node): void { - trace("generateNode(%s, %s)", ctx, node.getId().toString(16)); +export function generateMethodStructs(ctx: CodeGeneratorFileContext, node: s.Node): void { + node + .getInterface() + .getMethods() + .forEach((method) => { + const paramNode = lookupNode(ctx, method.getParamStructType()); + const resultNode = lookupNode(ctx, method.getResultStructType()); + + generateNode(ctx, paramNode); + generateNode(ctx, resultNode); + generateResultPromise(ctx, resultNode); + }); +} + +export function generateServer(ctx: CodeGeneratorFileContext, node: s.Node): void { + // TODO: handle superclasses + const fullClassName = getFullClassName(node); + const serverName = `${fullClassName}$Server`; + const serverTargetName = `${serverName}$Target`; + const clientName = `${fullClassName}$Client`; + + // Generate the `Foobar$Server$Target` interface + { + const elements = node + .getInterface() + .getMethods() + .map((method) => { + const paramTypeName = getFullClassName(lookupNode(ctx, method.getParamStructType())); + const resultTypeName = getFullClassName(lookupNode(ctx, method.getResultStructType())); + + return ts.createMethodSignature( + __, // typeParams + [ + ts.createParameter( + __, // decorators + __, // modifiers + __, // dotDotToken + "params", // name + __, // questionToken + ts.createTypeReferenceNode(paramTypeName, __), // type, + __ // initializer + ), + ts.createParameter( + __, // decorators + __, // modifiers + __, // dotDotToken + "results", // name + __, // questionToken + ts.createTypeReferenceNode(resultTypeName, __), // type, + __ // initializer + ), + ], // params + ts.createTypeReferenceNode("Promise", [VOID_TYPE]), // type + method.getName(), // name + __ // questionToken + ); + }); + + ctx.statements.push( + ts.createInterfaceDeclaration( + __, // decorators + [EXPORT], // modifiers + serverTargetName, // name + __, // typeParams + __, // heritageClauses + elements + ) + ); + } + + const members: ts.ClassElement[] = []; + + members.push( + ts.createProperty( + __, // decorators + [READONLY], // modifiers + "target", // name + __, // questionOrExclamationmark + ts.createTypeReferenceNode(serverTargetName, __), // type + __ // initializer + ) + ); + + // Generate server constructor + { + const serverMethods: ts.Expression[] = []; + node + .getInterface() + .getMethods() + .forEach((method, index) => { + serverMethods.push( + ts.createObjectLiteral( + [ + ts.createSpreadAssignment( + ts.createElementAccess(ts.createPropertyAccess(ts.createIdentifier(clientName), "methods"), index) + ), + ts.createPropertyAssignment( + "impl", + ts.createPropertyAccess(ts.createIdentifier("target"), method.getName()) + ), + ], + true // multiline + ) + ); + }); + + members.push( + ts.createConstructor( + __, // decorators + __, // modifiers + [ + ts.createParameter( + __, // decorators + __, // modifiers + __, // dotDotToken + "target", // name + __, // questionToken + ts.createTypeReferenceNode(serverTargetName, __), // type + __ // initializer + ), + ], // parameters + ts.createBlock( + [ + ts.createExpressionStatement( + ts.createCall( + ts.createIdentifier("super"), + __, // typeArguments + [ts.createIdentifier("target"), ts.createArrayLiteral(serverMethods, true /* multiline */)] // arguments + ) + ), + ts.createExpressionStatement( + ts.createAssignment(ts.createPropertyAccess(THIS, "target"), ts.createIdentifier("target")) + ), + ], + true // multiline + ) // body + ) + ); + } + + members.push( + ts.createMethod( + __, // decorators + __, // modifiers + __, // asteriskToken + "client", // name + __, // questionToken + __, // typeParams + [], // params + ts.createTypeReferenceNode(clientName, __), // type + ts.createBlock( + [ + ts.createReturn( + ts.createNew( + ts.createIdentifier(clientName), + __, // typeArgs + [THIS] // args + ) + ), + ], + false // multiline + ) + ) + ); + + ctx.statements.push( + ts.createClassDeclaration( + __, // decorators + [EXPORT], // modifiers + serverName, // name + __, // typeParams + [createClassExtends("capnp.Server")], // heritageClauses + members // members + ) + ); +} + +export function generateClientMethod( + ctx: CodeGeneratorFileContext, + node: s.Node, + clientName: string, + members: ts.ClassElement[], + methodDefs: ts.Expression[], + methodDefTypes: ts.TypeNode[], + method: s.Method, + index: number +): void { + const name = method.getName(); + + const paramTypeName = getFullClassName(lookupNode(ctx, method.getParamStructType())); + const resultTypeName = getFullClassName(lookupNode(ctx, method.getResultStructType())); + + methodDefTypes.push( + ts.createTypeReferenceNode( + "capnp.Method", + [ts.createTypeReferenceNode(paramTypeName, __), ts.createTypeReferenceNode(resultTypeName, __)] // typeArgs + ) + ); + methodDefs.push( + ts.createObjectLiteral( + [ + ts.createPropertyAssignment("ParamsClass", ts.createIdentifier(paramTypeName)), + ts.createPropertyAssignment("ResultsClass", ts.createIdentifier(resultTypeName)), + ts.createPropertyAssignment( + "interfaceId", + ts.createPropertyAccess(ts.createIdentifier(clientName), "interfaceId") + ), + ts.createPropertyAssignment("methodId", ts.createNumericLiteral(index.toString())), + ts.createPropertyAssignment("interfaceName", ts.createStringLiteral(node.getDisplayName())), + ts.createPropertyAssignment("methodName", ts.createStringLiteral(method.getName())), + ], + true /* multiline */ + ) + ); + + members.push( + ts.createMethod( + __, // decorators + __, // modifiers + __, // asteriskToken + name, + __, // typeParameters + __, // questionToken + [ + ts.createParameter( + __, // decorators + __, // modifiers + __, // dotDotToken + "paramsFunc", + QUESTION_TOKEN, // questionToken + ts.createFunctionTypeNode( + __, // typeParameters + [ + ts.createParameter( + __, // decorators + __, // modifiers + __, // dotDotToken + "params", // name + __, // questionToken + ts.createTypeReferenceNode(paramTypeName, __) // type + ), + ], + VOID_TYPE // type + ) + ), + ], // parameters + ts.createTypeReferenceNode(`${resultTypeName}$Promise`, __), + ts.createBlock( + [ + ts.createVariableStatement( + __, // modifiers + ts.createVariableDeclarationList( + [ + ts.createVariableDeclaration( + "answer", + __, + ts.createCall( + ts.createPropertyAccess(ts.createPropertyAccess(THIS, "client"), "call"), + __, // typeArgs + [ + ts.createObjectLiteral( + [ + ts.createPropertyAssignment( + "method", + ts.createElementAccess( + ts.createPropertyAccess(ts.createIdentifier(clientName), "methods"), + index + ) + ), + ts.createPropertyAssignment("paramsFunc", ts.createIdentifier("paramsFunc")), + ], + true // multiline + ), + ] + ) + ), + ], + ts.NodeFlags.Const + ) + ), // const answer = ... + + ts.createVariableStatement( + __, // modifiers + ts.createVariableDeclarationList( + [ + ts.createVariableDeclaration( + "pipeline", + __, + ts.createNew( + ts.createIdentifier("capnp.Pipeline"), + __, // typeArgs + [ts.createIdentifier(resultTypeName), ts.createIdentifier("answer")] + ) + ), + ], + ts.NodeFlags.Const + ) + ), // const pipeline = ... + + ts.createReturn( + ts.createNew( + ts.createIdentifier(`${resultTypeName}$Promise`), + __, // typeArguments + [ts.createIdentifier("pipeline")] + ) + ), + ], + true // multiline + ) + ) + ); +} + +export function generateClient(ctx: CodeGeneratorFileContext, node: s.Node): void { + const fullClassName = getFullClassName(node); + const clientName = `${fullClassName}$Client`; + + // TODO: handle superclasses + const members: ts.ClassElement[] = []; + + const ClientType = ts.createTypeReferenceNode("capnp.Client", __); + + members.push(ts.createProperty(__, __, "client", __, ClientType, __)); + + members.push( + ts.createProperty( + __, + [STATIC, READONLY], + "interfaceId", + __, + ts.createTypeReferenceNode("bigint", __), + createBigIntExpression(node.getId()) + ) + ); + + members.push( + ts.createConstructor( + __, // decorators + __, // modifiers + [ts.createParameter(__, __, __, "client", __, ClientType)], // parameters + ts.createBlock( + [ + ts.createStatement( + ts.createAssignment(ts.createPropertyAccess(THIS, "client"), ts.createIdentifier("client")) + ), + ], + true // multiline + ) // body + ) + ); + const methodDefs: ts.Expression[] = []; + const methodDefTypes: ts.TypeNode[] = []; + + members.push( + ts.createProperty( + __, // decorators + [STATIC, READONLY], // modifiers + "methods", // name + __, // questionOrExclamationToken + ts.createTupleTypeNode(methodDefTypes), // type + ts.createArrayLiteral( + methodDefs, + true // multiline + ) // initializer + ) + ); + + node + .getInterface() + .getMethods() + .forEach((method, index) => { + generateClientMethod(ctx, node, clientName, members, methodDefs, methodDefTypes, method, index); + }); + + ctx.statements.push(ts.createClassDeclaration(__, [EXPORT], clientName, __, [], members)); + + ctx.statements.push( + ts.createExpressionStatement( + ts.createCall( + ts.createPropertyAccess(ts.createIdentifier("capnp.Registry"), "register"), + __, // typeArgs + [ts.createPropertyAccess(ts.createIdentifier(clientName), "interfaceId"), ts.createIdentifier(clientName)] + ) + ) + ); +} + +export function generateNode(ctx: CodeGeneratorFileContext, node: s.Node): void { const nodeId = node.getId(); const nodeIdHex = nodeId.toString(16); @@ -256,6 +646,160 @@ export function generateNode(ctx: CodeGeneratorFileContext, node: s.Node): void } } +export function generateResultPromise(ctx: CodeGeneratorFileContext, node: s.Node): void { + const nodeId = node.getId(); + + if (ctx.generatedResultsPromiseIds.has(nodeId)) return; + + ctx.generatedResultsPromiseIds.add(nodeId); + + const resultsClassName = getFullClassName(node); + const fullClassName = `${resultsClassName}$Promise`; + + const PipelineType = ts.createTypeReferenceNode("capnp.Pipeline", [ + ANY_TYPE, + ANY_TYPE, + ts.createTypeReferenceNode(resultsClassName, __), + ]); + + const members: ts.ClassElement[] = []; + members.push(ts.createProperty(__, [], "pipeline", __, PipelineType, __)); + + members.push( + ts.createConstructor( + __, // decorators + __, // modifiers + [ts.createParameter(__, __, __, "pipeline", __, PipelineType)], // parameters + ts.createBlock( + [ + ts.createStatement( + ts.createAssignment(ts.createPropertyAccess(THIS, "pipeline"), ts.createIdentifier("pipeline")) + ), + ], + true // multiline + ) // body + ) + ); + + const struct = node.getStruct(); + const fields = struct.getFields().toArray().sort(compareCodeOrder); + + const generatePromiseFieldMethod = (field: s.Field) => { + let jsType: string; + let isInterface = false; + let slot: s.Field_Slot; + + if (field.isSlot()) { + slot = field.getSlot(); + const slotType = slot.getType(); + if (slotType.which() !== s.Type.INTERFACE) { + // TODO: return a Promise for non-interface slots + return; + } + isInterface = true; + jsType = getJsType(ctx, slotType, false); + } else if (field.isGroup()) { + // TODO: how should groups be handled? + return; + } else { + throw new Error(format(E.GEN_UNKNOWN_STRUCT_FIELD, field.which())); + } + + const promisedJsType = jsType; + if (isInterface) { + jsType = `${jsType}$Client`; + } + + const name = field.getName(); + const properName = util.c2t(name); + const jsTypeReference = ts.createTypeReferenceNode(jsType, __); + + { + // const pipeline = this.pipeline.getPipeline(SlotType, offset) + const pipeline = ts.createCall( + ts.createPropertyAccess(ts.createPropertyAccess(THIS, "pipeline"), "getPipeline"), + __, // typeArguments + [ts.createIdentifier(promisedJsType), ts.createNumericLiteral(slot.getOffset().toString())] // arguments + ); // call + + // const client = pipeline.client() + const client = ts.createCall( + ts.createPropertyAccess(pipeline, ts.createIdentifier("client")), + __, // typeArguments + __ // arguments + ); + + // new RemoteInterface(client) + const remoteInterface = ts.createNew( + ts.createIdentifier(jsType), // expression + __, // typeArguments + [client] // argumentsArray + ); + + members.push( + ts.createMethod( + __, // decorators + __, // modifiers + __, // asteriskToken + `get${properName}`, + __, + __, + [], // parameters + jsTypeReference, + ts.createBlock( + [ts.createReturn(remoteInterface)], + true // multiLine + ) + ) + ); + } + }; + + fields.forEach(generatePromiseFieldMethod); + + { + members.push( + ts.createMethod( + __, // decorators + [ASYNC], // modifiers + __, // asteriskToken + `promise`, + __, + __, + [], // parameters + ts.createTypeReferenceNode( + "Promise", + [ts.createTypeReferenceNode(resultsClassName, __)] // typeArguments + ), + createExpressionBlock( + [ + ts.createAwait( + ts.createCall( + ts.createPropertyAccess(ts.createPropertyAccess(THIS, "pipeline"), "struct"), + __, // typeArguments + __ // parameters + ) // call + ), // await + ], + true, // returns + false // allowSingleLine + ) + ) + ); + } + + const c = ts.createClassDeclaration( + __, + [EXPORT], + fullClassName, + __, + [], // TODO: inheritance + members + ); + + ctx.statements.push(c); +} + const listLengthParameterName = "length"; export function generateStructFieldMethods( @@ -277,8 +821,14 @@ export function generateStructFieldMethods( } else { throw new Error(format(E.GEN_UNKNOWN_STRUCT_FIELD, field.which())); } + let jsTypeReference = ts.createTypeReferenceNode(jsType, __); + + const isInterface = whichType === s.Type.INTERFACE; + if (isInterface) { + jsType = `${jsType}$Client`; + jsTypeReference = ts.createTypeReferenceNode(jsType, __); + } - const jsTypeReference = f.createTypeReferenceNode(jsType, __); const discriminantOffset = node.getStruct().getDiscriminantOffset(); const name = field.getName(); const properName = util.c2t(name); @@ -393,18 +943,43 @@ export function generateStructFieldMethods( break; case s.Type.INTERFACE: - if (hadExplicitDefault) { - throw new Error(format(E.GEN_EXPLICIT_DEFAULT_NON_PRIMITIVE, "INTERFACE")); + // new SomeInterface$Client(__S.getInterfaceClientOrNullAt(0, this)); + { + const client = ts.createCall( + ts.createPropertyAccess(STRUCT, "getInterfaceClientOrNullAt"), + __, // typeParams + [offsetLiteral, THIS] + ); + const newClient = ts.createNew( + ts.createIdentifier(jsType), + __, // typeParams + [client] + ); + get = newClient; } - /** __S.getPointerAs(0, Foo, this) */ - get = f.createCallExpression(f.createPropertyAccessExpression(STRUCT, "getPointerAs"), __, [ - offsetLiteral, - f.createIdentifier(jsType), - THIS, - ]); - set = copyFromValue; - + { + const message = ts.createPropertyAccess( + ts.createPropertyAccess(THIS, ts.createIdentifier("segment")), + ts.createIdentifier("message") + ); + const capId = ts.createCall( + ts.createPropertyAccess(message, "addCap"), + __, // typeParams + [ts.createPropertyAccess(ts.createIdentifier("value"), "client")] + ); + const ptr = ts.createCall( + ts.createPropertyAccess(STRUCT, "getPointer"), + __, // typeParams + [offsetLiteral, THIS] + ); + + set = ts.createCall( + ts.createPropertyAccess(STRUCT, "setInterfacePointer"), + __, // typeParams + [capId, ptr] + ); + } break; case s.Type.LIST: { @@ -500,7 +1075,7 @@ export function generateStructFieldMethods( break; } - // adoptFoo(value: capnp.Orphan): void { __S.adopt(value, this._getPointer(3)); }} + // adoptFoo(value: capnp.Orphan): void { __S.adopt(value, this._getPointer(3)); } if (adopt) { const parameters = [f.createParameterDeclaration(__, __, __, VALUE, __, orphanType, __)]; const expressions = [ @@ -593,8 +1168,6 @@ export function generateStructFieldMethods( } export function generateStructNode(ctx: CodeGeneratorFileContext, node: s.Node, interfaceNode: boolean): void { - trace("generateStructNode(%s) [%s]", node, node.getDisplayName()); - const displayNamePrefix = getDisplayNamePrefix(node); const fullClassName = getFullClassName(node); const nestedNodes = node @@ -634,16 +1207,16 @@ export function generateStructNode(ctx: CodeGeneratorFileContext, node: s.Node, // static readonly NestedStruct = MyStruct_NestedStruct; members.push(...nestedNodes.map(createNestedNodeProperty)); - // static readonly Client = MyInterface_Client; - // static readonly Server = MyInterface_Server; - // if (interfaceNode) { - - // members.push( - // f.createPropertyDeclaration(__, [STATIC, READONLY], 'Client', __, __, f.createStringLiteral(`${fullClassName}_Client`))); - // members.push( - // f.createPropertyDeclaration(__, [STATIC, READONLY], 'Server', __, __, f.createStringLiteral(`${fullClassName}_Server`))); - - // } + // static readonly Client = MyInterface$Client; + // static readonly Server = MyInterface$Server; + if (interfaceNode) { + members.push( + ts.createProperty(__, [STATIC, READONLY], "Client", __, __, ts.createIdentifier(`${fullClassName}$Client`)) + ); + members.push( + ts.createProperty(__, [STATIC, READONLY], "Server", __, __, ts.createIdentifier(`${fullClassName}$Server`)) + ); + } const defaultValues = fields.reduce( (acc, f) => @@ -702,7 +1275,14 @@ export function generateStructNode(ctx: CodeGeneratorFileContext, node: s.Node, ); } - const c = f.createClassDeclaration(__, [EXPORT], fullClassName, __, [createClassExtends("__S")], members); + const c = ts.createClassDeclaration( + __, + [EXPORT], + fullClassName, + __, + [interfaceNode ? createClassExtends("__I") : createClassExtends("__S")], + members + ); // Make sure the interface classes are generated first. diff --git a/packages/capnpc-ts/src/index.ts b/packages/capnpc-ts/src/index.ts index ebe7a67..c95d17d 100644 --- a/packages/capnpc-ts/src/index.ts +++ b/packages/capnpc-ts/src/index.ts @@ -8,7 +8,6 @@ import { loadRequest, writeTsFiles } from "./compiler"; import * as E from "./errors"; const trace = initTrace("capnpc"); -trace("load"); /** * The equivalent of tsconfig.json used when compiling the emitted .ts file to .js. @@ -50,7 +49,6 @@ export async function run(): Promise { const chunks: Buffer[] = []; process.stdin.on("data", (chunk: Buffer) => { - trace("reading data chunk (%d bytes)", chunk.byteLength); chunks.push(chunk); }); @@ -66,16 +64,8 @@ export async function run(): Promise { i += chunk.byteLength; }); - trace("reqBuffer (length: %d)", reqBuffer.length, reqBuffer); - const message = new capnp.Message(reqBuffer, false); - - trace("message: %s", message.dump()); - const req = message.getRoot(s.CodeGeneratorRequest); - - trace("%s", req); - const ctx = loadRequest(req); writeTsFiles(ctx); @@ -84,8 +74,6 @@ export async function run(): Promise { } export function transpileAll(ctx: CodeGeneratorContext): void { - trace("transpileAll()", ctx.files); - const tsFilePaths = ctx.files.map((f) => f.tsPath); const program = ts.createProgram(tsFilePaths, COMPILE_OPTIONS); @@ -114,10 +102,8 @@ export function transpileAll(ctx: CodeGeneratorContext): void { if (diagnostic.file && diagnostic.start) { const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); - /* tslint:disable-next-line:no-console */ console.log(`${diagnostic.file.fileName}:${line + 1}:${character + 1} ${message}`); } else { - /* tslint:disable-next-line:no-console */ console.log(`==> ${message}`); } }); diff --git a/packages/capnpc-ts/src/util.ts b/packages/capnpc-ts/src/util.ts index 7de49ed..e313031 100644 --- a/packages/capnpc-ts/src/util.ts +++ b/packages/capnpc-ts/src/util.ts @@ -1,5 +1,4 @@ import { pad } from "capnp-ts/src/util"; -import initTrace from "debug"; // Yep, this is silly. :) @@ -13,9 +12,6 @@ interface Hex2Dec { const { decToHex, hexToDec } = require("hex2dec") as Hex2Dec; /* eslint-enable */ -const trace = initTrace("capnpc:util"); -trace("load"); - export function c2s(s: string): string { return splitCamel(s) .map((x) => x.toUpperCase()) diff --git a/packages/js-examples/addressbook.capnp.js b/packages/js-examples/addressbook.capnp.js index 3969e7f..c105be9 100644 --- a/packages/js-examples/addressbook.capnp.js +++ b/packages/js-examples/addressbook.capnp.js @@ -1,10 +1,9 @@ "use strict"; -/* tslint:disable */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.AddressBook = exports.Person = exports.Person_Employment = exports.Person_Employment_Which = exports.Person_PhoneNumber = exports.Person_PhoneNumber_Type = exports._capnpFileId = void 0; /** * This file has been automatically generated by the [capnpc-ts utility](https://github.com/jdiaz5513/capnp-ts). */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AddressBook = exports.Person = exports.Person_Employment = exports.Person_Employment_Which = exports.Person_PhoneNumber = exports.Person_PhoneNumber_Type = exports._capnpFileId = void 0; const capnp = require("capnp-ts"); const capnp_ts_1 = require("capnp-ts"); exports._capnpFileId = BigInt("0xef1b5abe02e1f8d4"); diff --git a/tsconfig.json b/tsconfig.json index 593badc..ccdff2b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,12 @@ { "compilerOptions": { + "baseUrl": "packages", "declaration": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "importHelpers": true, "incremental": true, - "lib": ["es2015"], + "lib": ["es2015", "ES2021.WeakRef"], "module": "CommonJS", "moduleResolution": "Node", "newLine": "LF", @@ -14,6 +15,10 @@ "noImplicitReturns": true, "noUnusedLocals": false, "noUnusedParameters": true, + "paths": { + "capnp-ts": ["capnp-ts/src"], + "capnpc-ts": ["capnpc-ts/src"] + }, "pretty": true, "sourceMap": true, "strict": true, diff --git a/tsconfig.test.json b/tsconfig.test.json index 0707b0b..7188323 100644 --- a/tsconfig.test.json +++ b/tsconfig.test.json @@ -1,4 +1,5 @@ { "extends": "./tsconfig.json", + "exclude": ["packages/capnp-ts/**/*"], "include": ["packages/*/test/**/*"] }