sabcom 0.0.25 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.cjs +10 -12
- package/build/index.cjs.map +1 -1
- package/build/index.d.ts +6 -6
- package/build/index.js +10 -12
- package/build/index.js.map +1 -1
- package/package.json +2 -4
- package/src/index.ts +23 -73
package/build/index.cjs
CHANGED
|
@@ -46,7 +46,6 @@ _export(exports, {
|
|
|
46
46
|
return writeSync;
|
|
47
47
|
}
|
|
48
48
|
});
|
|
49
|
-
const _nodev8 = require("node:v8");
|
|
50
49
|
const SEMAPHORE = 0;
|
|
51
50
|
var Semaphore = /*#__PURE__*/ function(Semaphore) {
|
|
52
51
|
Semaphore[Semaphore["READY"] = 0] = "READY";
|
|
@@ -68,9 +67,8 @@ var Header = /*#__PURE__*/ function(Header) {
|
|
|
68
67
|
const HEADER_VALUES = 1 + Math.max(Object.values(Handshake).length, Object.values(Header).length) / 2;
|
|
69
68
|
const HEADER_SIZE = Uint32Array.BYTES_PER_ELEMENT * HEADER_VALUES;
|
|
70
69
|
function* writeGenerator(data, buffer, { timeout = 5000 } = {}) {
|
|
71
|
-
const serialized = (0, _nodev8.serialize)(data);
|
|
72
70
|
const chunkSize = buffer.byteLength - HEADER_SIZE;
|
|
73
|
-
const totalSize =
|
|
71
|
+
const totalSize = data.length;
|
|
74
72
|
const totalChunks = Math.ceil(totalSize / chunkSize);
|
|
75
73
|
const header = new Int32Array(buffer);
|
|
76
74
|
header[1] = totalSize;
|
|
@@ -84,15 +82,15 @@ function* writeGenerator(data, buffer, { timeout = 5000 } = {}) {
|
|
|
84
82
|
value: 1,
|
|
85
83
|
timeout
|
|
86
84
|
};
|
|
87
|
-
if (handshakeResult ===
|
|
88
|
-
throw new Error(
|
|
85
|
+
if (handshakeResult === 'timed-out') {
|
|
86
|
+
throw new Error('Reader handshake timeout');
|
|
89
87
|
}
|
|
90
88
|
const payload = new Uint8Array(buffer, HEADER_SIZE);
|
|
91
89
|
for(let i = 0; i < totalChunks; i++){
|
|
92
90
|
const start = i * chunkSize;
|
|
93
91
|
const end = Math.min(start + chunkSize, totalSize);
|
|
94
92
|
const size = end - start;
|
|
95
|
-
payload.set(
|
|
93
|
+
payload.set(data.subarray(start, end), 0);
|
|
96
94
|
header[1] = i;
|
|
97
95
|
header[2] = start;
|
|
98
96
|
header[3] = size;
|
|
@@ -104,7 +102,7 @@ function* writeGenerator(data, buffer, { timeout = 5000 } = {}) {
|
|
|
104
102
|
value: 2,
|
|
105
103
|
timeout
|
|
106
104
|
};
|
|
107
|
-
if (chunkResult ===
|
|
105
|
+
if (chunkResult === 'timed-out') {
|
|
108
106
|
throw new Error(`Reader timeout on chunk ${i}/${totalChunks - 1}`);
|
|
109
107
|
}
|
|
110
108
|
}
|
|
@@ -120,11 +118,11 @@ function* readGenerator(buffer, { timeout = 5000 } = {}) {
|
|
|
120
118
|
value: 0,
|
|
121
119
|
timeout
|
|
122
120
|
};
|
|
123
|
-
if (handshakeResult ===
|
|
124
|
-
throw new Error(
|
|
121
|
+
if (handshakeResult === 'timed-out') {
|
|
122
|
+
throw new Error('Handshake timeout');
|
|
125
123
|
}
|
|
126
124
|
if (header[SEMAPHORE] !== 1) {
|
|
127
|
-
throw new Error(
|
|
125
|
+
throw new Error('Invalid handshake state');
|
|
128
126
|
}
|
|
129
127
|
const totalSize = header[1];
|
|
130
128
|
const totalChunks = header[2];
|
|
@@ -139,7 +137,7 @@ function* readGenerator(buffer, { timeout = 5000 } = {}) {
|
|
|
139
137
|
value: 0,
|
|
140
138
|
timeout
|
|
141
139
|
};
|
|
142
|
-
if (chunkResult ===
|
|
140
|
+
if (chunkResult === 'timed-out') {
|
|
143
141
|
throw new Error(`Writer timeout waiting for chunk ${i}`);
|
|
144
142
|
}
|
|
145
143
|
if (header[SEMAPHORE] !== 2) {
|
|
@@ -155,7 +153,7 @@ function* readGenerator(buffer, { timeout = 5000 } = {}) {
|
|
|
155
153
|
Atomics.store(header, SEMAPHORE, 0);
|
|
156
154
|
Atomics.notify(header, SEMAPHORE);
|
|
157
155
|
}
|
|
158
|
-
return
|
|
156
|
+
return data;
|
|
159
157
|
}
|
|
160
158
|
const writeSync = (data, buffer, options)=>{
|
|
161
159
|
const gen = writeGenerator(data, buffer, options);
|
package/build/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { serialize, deserialize } from \"node:v8\";\n\nexport const SEMAPHORE = 0;\n\nexport enum Semaphore {\n READY,\n HANDSHAKE,\n PAYLOAD,\n}\n\nexport enum Handshake {\n TOTAL_SIZE = 1,\n TOTAL_CHUNKS,\n}\n\nexport enum Header {\n CHUNK_INDEX = 1,\n CHUNK_OFFSET,\n CHUNK_SIZE,\n}\n\nexport const HEADER_VALUES =\n 1 +\n Math.max(Object.values(Handshake).length, Object.values(Header).length) / 2;\nexport const HEADER_SIZE = Uint32Array.BYTES_PER_ELEMENT * HEADER_VALUES;\n\nexport interface Options {\n timeout?: number;\n}\n\nexport interface WaitRequest {\n target: Int32Array;\n index: number;\n value: number;\n timeout?: number;\n}\n\nexport type WaitResponse = ReturnType<typeof Atomics.wait>;\n\nexport function* writeGenerator(\n data: unknown,\n buffer: SharedArrayBuffer,\n { timeout = 5000 }: Options = {},\n): Generator<WaitRequest, void, WaitResponse> {\n const serialized = serialize(data);\n const chunkSize = buffer.byteLength - HEADER_SIZE;\n const totalSize = serialized.length;\n const totalChunks = Math.ceil(totalSize / chunkSize);\n const header = new Int32Array(buffer);\n\n header[Handshake.TOTAL_SIZE] = totalSize;\n header[Handshake.TOTAL_CHUNKS] = totalChunks;\n Atomics.store(header, SEMAPHORE, Semaphore.HANDSHAKE);\n Atomics.notify(header, SEMAPHORE);\n\n try {\n const handshakeResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.HANDSHAKE,\n timeout,\n };\n if (handshakeResult === \"timed-out\") {\n throw new Error(\"Reader handshake timeout\");\n }\n\n const payload = new Uint8Array(buffer, HEADER_SIZE);\n for (let i = 0; i < totalChunks; i++) {\n const start = i * chunkSize;\n const end = Math.min(start + chunkSize, totalSize);\n const size = end - start;\n payload.set(serialized.subarray(start, end), 0);\n header[Header.CHUNK_INDEX] = i;\n header[Header.CHUNK_OFFSET] = start;\n header[Header.CHUNK_SIZE] = size;\n Atomics.store(header, SEMAPHORE, Semaphore.PAYLOAD);\n Atomics.notify(header, SEMAPHORE);\n\n const chunkResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.PAYLOAD,\n timeout,\n };\n if (chunkResult === \"timed-out\") {\n throw new Error(`Reader timeout on chunk ${i}/${totalChunks - 1}`);\n }\n }\n } finally {\n Atomics.store(header, SEMAPHORE, Semaphore.READY);\n }\n}\n\nexport function* readGenerator(\n buffer: SharedArrayBuffer,\n { timeout = 5000 }: Options = {},\n): Generator<WaitRequest, unknown, WaitResponse> {\n const header = new Int32Array(buffer);\n\n const handshakeResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.READY,\n timeout,\n };\n if (handshakeResult === \"timed-out\") {\n throw new Error(\"Handshake timeout\");\n }\n if (header[SEMAPHORE] !== Semaphore.HANDSHAKE) {\n throw new Error(\"Invalid handshake state\");\n }\n\n const totalSize = header[Handshake.TOTAL_SIZE];\n const totalChunks = header[Handshake.TOTAL_CHUNKS];\n const data = new Uint8Array(totalSize);\n\n Atomics.store(header, SEMAPHORE, Semaphore.READY);\n Atomics.notify(header, SEMAPHORE);\n\n const payload = new Uint8Array(buffer, HEADER_SIZE);\n for (let i = 0; i < totalChunks; i++) {\n const chunkResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.READY,\n timeout,\n };\n if (chunkResult === \"timed-out\") {\n throw new Error(`Writer timeout waiting for chunk ${i}`);\n }\n // @ts-expect-error does not infer number\n if (header[SEMAPHORE] !== Semaphore.PAYLOAD) {\n throw new Error(\n `Expected payload header, received ${Semaphore[header[SEMAPHORE]]}`,\n );\n }\n const chunkIndex = header[Header.CHUNK_INDEX];\n if (i !== chunkIndex) {\n throw new Error(\n `Reader integrity failure for chunk ${chunkIndex} expected ${i}`,\n );\n }\n const offset = header[Header.CHUNK_OFFSET];\n const size = header[Header.CHUNK_SIZE];\n data.set(payload.subarray(0, size), offset);\n Atomics.store(header, SEMAPHORE, Semaphore.READY);\n Atomics.notify(header, SEMAPHORE);\n }\n return deserialize(data) as unknown;\n}\n\nexport const writeSync = (\n data: unknown,\n buffer: SharedArrayBuffer,\n options?: Options,\n) => {\n const gen = writeGenerator(data, buffer, options);\n let result = gen.next();\n while (!result.done) {\n const waitResult = Atomics.wait(\n result.value.target,\n result.value.index,\n result.value.value,\n result.value.timeout,\n );\n result = gen.next(waitResult);\n }\n};\n\nexport const write = async (\n data: unknown,\n buffer: SharedArrayBuffer,\n options?: Options,\n) => {\n const gen = writeGenerator(data, buffer, options);\n let result = gen.next();\n while (!result.done) {\n const request = result.value;\n const waitResult = await Atomics.waitAsync(\n request.target,\n request.index,\n request.value,\n request.timeout,\n ).value;\n result = gen.next(waitResult);\n }\n};\n\nexport const readSync = (\n buffer: SharedArrayBuffer,\n options?: Options,\n): unknown => {\n const gen = readGenerator(buffer, options);\n let result = gen.next();\n while (!result.done) {\n const waitResult = Atomics.wait(\n result.value.target,\n result.value.index,\n result.value.value,\n result.value.timeout,\n );\n result = gen.next(waitResult);\n }\n return result.value;\n};\n\nexport const read = async (\n buffer: SharedArrayBuffer,\n options?: Options,\n): Promise<unknown> => {\n const gen = readGenerator(buffer, options);\n let result = gen.next();\n while (!result.done) {\n const request = result.value;\n const waitResult = await Atomics.waitAsync(\n request.target,\n request.index,\n request.value,\n request.timeout,\n ).value;\n result = gen.next(waitResult);\n }\n return result.value;\n};\n"],"names":["HEADER_SIZE","HEADER_VALUES","Handshake","Header","SEMAPHORE","Semaphore","read","readGenerator","readSync","write","writeGenerator","writeSync","Math","max","Object","values","length","Uint32Array","BYTES_PER_ELEMENT","data","buffer","timeout","serialized","serialize","chunkSize","byteLength","totalSize","totalChunks","ceil","header","Int32Array","Atomics","store","notify","handshakeResult","target","index","value","Error","payload","Uint8Array","i","start","end","min","size","set","subarray","chunkResult","chunkIndex","offset","deserialize","options","gen","result","next","done","waitResult","wait","request","waitAsync"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export const SEMAPHORE = 0;\n\nexport enum Semaphore {\n READY,\n HANDSHAKE,\n PAYLOAD,\n}\n\nexport enum Handshake {\n TOTAL_SIZE = 1,\n TOTAL_CHUNKS,\n}\n\nexport enum Header {\n CHUNK_INDEX = 1,\n CHUNK_OFFSET,\n CHUNK_SIZE,\n}\n\nexport const HEADER_VALUES = 1 + Math.max(Object.values(Handshake).length, Object.values(Header).length) / 2;\nexport const HEADER_SIZE = Uint32Array.BYTES_PER_ELEMENT * HEADER_VALUES;\n\nexport interface Options {\n timeout?: number;\n}\n\nexport interface WaitRequest {\n target: Int32Array;\n index: number;\n value: number;\n timeout?: number;\n}\n\nexport type WaitResponse = ReturnType<typeof Atomics.wait>;\n\nexport function* writeGenerator(data: Uint8Array, buffer: SharedArrayBuffer, { timeout = 5000 }: Options = {}): Generator<WaitRequest, void, WaitResponse> {\n const chunkSize = buffer.byteLength - HEADER_SIZE;\n const totalSize = data.length;\n const totalChunks = Math.ceil(totalSize / chunkSize);\n const header = new Int32Array(buffer);\n\n header[Handshake.TOTAL_SIZE] = totalSize;\n header[Handshake.TOTAL_CHUNKS] = totalChunks;\n Atomics.store(header, SEMAPHORE, Semaphore.HANDSHAKE);\n Atomics.notify(header, SEMAPHORE);\n\n try {\n const handshakeResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.HANDSHAKE,\n timeout,\n };\n if (handshakeResult === 'timed-out') {\n throw new Error('Reader handshake timeout');\n }\n\n const payload = new Uint8Array(buffer, HEADER_SIZE);\n for (let i = 0; i < totalChunks; i++) {\n const start = i * chunkSize;\n const end = Math.min(start + chunkSize, totalSize);\n const size = end - start;\n payload.set(data.subarray(start, end), 0);\n header[Header.CHUNK_INDEX] = i;\n header[Header.CHUNK_OFFSET] = start;\n header[Header.CHUNK_SIZE] = size;\n Atomics.store(header, SEMAPHORE, Semaphore.PAYLOAD);\n Atomics.notify(header, SEMAPHORE);\n\n const chunkResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.PAYLOAD,\n timeout,\n };\n if (chunkResult === 'timed-out') {\n throw new Error(`Reader timeout on chunk ${i}/${totalChunks - 1}`);\n }\n }\n } finally {\n Atomics.store(header, SEMAPHORE, Semaphore.READY);\n }\n}\n\nexport function* readGenerator(buffer: SharedArrayBuffer, { timeout = 5000 }: Options = {}): Generator<WaitRequest, Uint8Array, WaitResponse> {\n const header = new Int32Array(buffer);\n\n const handshakeResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.READY,\n timeout,\n };\n if (handshakeResult === 'timed-out') {\n throw new Error('Handshake timeout');\n }\n if (header[SEMAPHORE] !== Semaphore.HANDSHAKE) {\n throw new Error('Invalid handshake state');\n }\n\n const totalSize = header[Handshake.TOTAL_SIZE];\n const totalChunks = header[Handshake.TOTAL_CHUNKS];\n const data = new Uint8Array(totalSize);\n\n Atomics.store(header, SEMAPHORE, Semaphore.READY);\n Atomics.notify(header, SEMAPHORE);\n\n const payload = new Uint8Array(buffer, HEADER_SIZE);\n for (let i = 0; i < totalChunks; i++) {\n const chunkResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.READY,\n timeout,\n };\n if (chunkResult === 'timed-out') {\n throw new Error(`Writer timeout waiting for chunk ${i}`);\n }\n // @ts-expect-error does not infer number\n if (header[SEMAPHORE] !== Semaphore.PAYLOAD) {\n throw new Error(`Expected payload header, received ${Semaphore[header[SEMAPHORE]]}`);\n }\n const chunkIndex = header[Header.CHUNK_INDEX];\n if (i !== chunkIndex) {\n throw new Error(`Reader integrity failure for chunk ${chunkIndex} expected ${i}`);\n }\n const offset = header[Header.CHUNK_OFFSET];\n const size = header[Header.CHUNK_SIZE];\n data.set(payload.subarray(0, size), offset);\n Atomics.store(header, SEMAPHORE, Semaphore.READY);\n Atomics.notify(header, SEMAPHORE);\n }\n return data;\n}\n\nexport const writeSync = (data: Uint8Array, buffer: SharedArrayBuffer, options?: Options) => {\n const gen = writeGenerator(data, buffer, options);\n let result = gen.next();\n while (!result.done) {\n const waitResult = Atomics.wait(result.value.target, result.value.index, result.value.value, result.value.timeout);\n result = gen.next(waitResult);\n }\n};\n\nexport const write = async (data: Uint8Array, buffer: SharedArrayBuffer, options?: Options) => {\n const gen = writeGenerator(data, buffer, options);\n let result = gen.next();\n while (!result.done) {\n const request = result.value;\n const waitResult = await Atomics.waitAsync(request.target, request.index, request.value, request.timeout).value;\n result = gen.next(waitResult);\n }\n};\n\nexport const readSync = (buffer: SharedArrayBuffer, options?: Options): Uint8Array => {\n const gen = readGenerator(buffer, options);\n let result = gen.next();\n while (!result.done) {\n const waitResult = Atomics.wait(result.value.target, result.value.index, result.value.value, result.value.timeout);\n result = gen.next(waitResult);\n }\n return result.value;\n};\n\nexport const read = async (buffer: SharedArrayBuffer, options?: Options): Promise<Uint8Array> => {\n const gen = readGenerator(buffer, options);\n let result = gen.next();\n while (!result.done) {\n const request = result.value;\n const waitResult = await Atomics.waitAsync(request.target, request.index, request.value, request.timeout).value;\n result = gen.next(waitResult);\n }\n return result.value;\n};\n"],"names":["HEADER_SIZE","HEADER_VALUES","Handshake","Header","SEMAPHORE","Semaphore","read","readGenerator","readSync","write","writeGenerator","writeSync","Math","max","Object","values","length","Uint32Array","BYTES_PER_ELEMENT","data","buffer","timeout","chunkSize","byteLength","totalSize","totalChunks","ceil","header","Int32Array","Atomics","store","notify","handshakeResult","target","index","value","Error","payload","Uint8Array","i","start","end","min","size","set","subarray","chunkResult","chunkIndex","offset","options","gen","result","next","done","waitResult","wait","request","waitAsync"],"mappings":";;;;;;;;;;;QAoBaA;eAAAA;;QADAC;eAAAA;;QAXDC;eAAAA;;QAKAC;eAAAA;;QAbCC;eAAAA;;QAEDC;eAAAA;;QAkKCC;eAAAA;;QAhFIC;eAAAA;;QAsEJC;eAAAA;;QAVAC;eAAAA;;QA7GIC;eAAAA;;QAoGJC;eAAAA;;;AAvIN,MAAMP,YAAY;AAElB,IAAA,AAAKC,mCAAAA;;;;WAAAA;;AAML,IAAA,AAAKH,mCAAAA;;;WAAAA;;AAKL,IAAA,AAAKC,gCAAAA;;;;WAAAA;;AAML,MAAMF,gBAAgB,IAAIW,KAAKC,GAAG,CAACC,OAAOC,MAAM,CAACb,WAAWc,MAAM,EAAEF,OAAOC,MAAM,CAACZ,QAAQa,MAAM,IAAI;AACpG,MAAMhB,cAAciB,YAAYC,iBAAiB,GAAGjB;AAepD,UAAUS,eAAeS,IAAgB,EAAEC,MAAyB,EAAE,EAAEC,UAAU,IAAI,EAAW,GAAG,CAAC,CAAC;IAC3G,MAAMC,YAAYF,OAAOG,UAAU,GAAGvB;IACtC,MAAMwB,YAAYL,KAAKH,MAAM;IAC7B,MAAMS,cAAcb,KAAKc,IAAI,CAACF,YAAYF;IAC1C,MAAMK,SAAS,IAAIC,WAAWR;IAE9BO,MAAM,GAAsB,GAAGH;IAC/BG,MAAM,GAAwB,GAAGF;IACjCI,QAAQC,KAAK,CAACH,QAAQvB;IACtByB,QAAQE,MAAM,CAACJ,QAAQvB;IAEvB,IAAI;QACF,MAAM4B,kBAAgC,MAAM;YAC1CC,QAAQN;YACRO,OAAO9B;YACP+B,KAAK;YACLd;QACF;QACA,IAAIW,oBAAoB,aAAa;YACnC,MAAM,IAAII,MAAM;QAClB;QAEA,MAAMC,UAAU,IAAIC,WAAWlB,QAAQpB;QACvC,IAAK,IAAIuC,IAAI,GAAGA,IAAId,aAAac,IAAK;YACpC,MAAMC,QAAQD,IAAIjB;YAClB,MAAMmB,MAAM7B,KAAK8B,GAAG,CAACF,QAAQlB,WAAWE;YACxC,MAAMmB,OAAOF,MAAMD;YACnBH,QAAQO,GAAG,CAACzB,KAAK0B,QAAQ,CAACL,OAAOC,MAAM;YACvCd,MAAM,GAAoB,GAAGY;YAC7BZ,MAAM,GAAqB,GAAGa;YAC9Bb,MAAM,GAAmB,GAAGgB;YAC5Bd,QAAQC,KAAK,CAACH,QAAQvB;YACtByB,QAAQE,MAAM,CAACJ,QAAQvB;YAEvB,MAAM0C,cAA4B,MAAM;gBACtCb,QAAQN;gBACRO,OAAO9B;gBACP+B,KAAK;gBACLd;YACF;YACA,IAAIyB,gBAAgB,aAAa;gBAC/B,MAAM,IAAIV,MAAM,CAAC,wBAAwB,EAAEG,EAAE,CAAC,EAAEd,cAAc,GAAG;YACnE;QACF;IACF,SAAU;QACRI,QAAQC,KAAK,CAACH,QAAQvB;IACxB;AACF;AAEO,UAAUG,cAAca,MAAyB,EAAE,EAAEC,UAAU,IAAI,EAAW,GAAG,CAAC,CAAC;IACxF,MAAMM,SAAS,IAAIC,WAAWR;IAE9B,MAAMY,kBAAgC,MAAM;QAC1CC,QAAQN;QACRO,OAAO9B;QACP+B,KAAK;QACLd;IACF;IACA,IAAIW,oBAAoB,aAAa;QACnC,MAAM,IAAII,MAAM;IAClB;IACA,IAAIT,MAAM,CAACvB,UAAU,QAA0B;QAC7C,MAAM,IAAIgC,MAAM;IAClB;IAEA,MAAMZ,YAAYG,MAAM,GAAsB;IAC9C,MAAMF,cAAcE,MAAM,GAAwB;IAClD,MAAMR,OAAO,IAAImB,WAAWd;IAE5BK,QAAQC,KAAK,CAACH,QAAQvB;IACtByB,QAAQE,MAAM,CAACJ,QAAQvB;IAEvB,MAAMiC,UAAU,IAAIC,WAAWlB,QAAQpB;IACvC,IAAK,IAAIuC,IAAI,GAAGA,IAAId,aAAac,IAAK;QACpC,MAAMO,cAA4B,MAAM;YACtCb,QAAQN;YACRO,OAAO9B;YACP+B,KAAK;YACLd;QACF;QACA,IAAIyB,gBAAgB,aAAa;YAC/B,MAAM,IAAIV,MAAM,CAAC,iCAAiC,EAAEG,GAAG;QACzD;QAEA,IAAIZ,MAAM,CAACvB,UAAU,QAAwB;YAC3C,MAAM,IAAIgC,MAAM,CAAC,kCAAkC,EAAE/B,SAAS,CAACsB,MAAM,CAACvB,UAAU,CAAC,EAAE;QACrF;QACA,MAAM2C,aAAapB,MAAM,GAAoB;QAC7C,IAAIY,MAAMQ,YAAY;YACpB,MAAM,IAAIX,MAAM,CAAC,mCAAmC,EAAEW,WAAW,UAAU,EAAER,GAAG;QAClF;QACA,MAAMS,SAASrB,MAAM,GAAqB;QAC1C,MAAMgB,OAAOhB,MAAM,GAAmB;QACtCR,KAAKyB,GAAG,CAACP,QAAQQ,QAAQ,CAAC,GAAGF,OAAOK;QACpCnB,QAAQC,KAAK,CAACH,QAAQvB;QACtByB,QAAQE,MAAM,CAACJ,QAAQvB;IACzB;IACA,OAAOe;AACT;AAEO,MAAMR,YAAY,CAACQ,MAAkBC,QAA2B6B;IACrE,MAAMC,MAAMxC,eAAeS,MAAMC,QAAQ6B;IACzC,IAAIE,SAASD,IAAIE,IAAI;IACrB,MAAO,CAACD,OAAOE,IAAI,CAAE;QACnB,MAAMC,aAAazB,QAAQ0B,IAAI,CAACJ,OAAOhB,KAAK,CAACF,MAAM,EAAEkB,OAAOhB,KAAK,CAACD,KAAK,EAAEiB,OAAOhB,KAAK,CAACA,KAAK,EAAEgB,OAAOhB,KAAK,CAACd,OAAO;QACjH8B,SAASD,IAAIE,IAAI,CAACE;IACpB;AACF;AAEO,MAAM7C,QAAQ,OAAOU,MAAkBC,QAA2B6B;IACvE,MAAMC,MAAMxC,eAAeS,MAAMC,QAAQ6B;IACzC,IAAIE,SAASD,IAAIE,IAAI;IACrB,MAAO,CAACD,OAAOE,IAAI,CAAE;QACnB,MAAMG,UAAUL,OAAOhB,KAAK;QAC5B,MAAMmB,aAAa,MAAMzB,QAAQ4B,SAAS,CAACD,QAAQvB,MAAM,EAAEuB,QAAQtB,KAAK,EAAEsB,QAAQrB,KAAK,EAAEqB,QAAQnC,OAAO,EAAEc,KAAK;QAC/GgB,SAASD,IAAIE,IAAI,CAACE;IACpB;AACF;AAEO,MAAM9C,WAAW,CAACY,QAA2B6B;IAClD,MAAMC,MAAM3C,cAAca,QAAQ6B;IAClC,IAAIE,SAASD,IAAIE,IAAI;IACrB,MAAO,CAACD,OAAOE,IAAI,CAAE;QACnB,MAAMC,aAAazB,QAAQ0B,IAAI,CAACJ,OAAOhB,KAAK,CAACF,MAAM,EAAEkB,OAAOhB,KAAK,CAACD,KAAK,EAAEiB,OAAOhB,KAAK,CAACA,KAAK,EAAEgB,OAAOhB,KAAK,CAACd,OAAO;QACjH8B,SAASD,IAAIE,IAAI,CAACE;IACpB;IACA,OAAOH,OAAOhB,KAAK;AACrB;AAEO,MAAM7B,OAAO,OAAOc,QAA2B6B;IACpD,MAAMC,MAAM3C,cAAca,QAAQ6B;IAClC,IAAIE,SAASD,IAAIE,IAAI;IACrB,MAAO,CAACD,OAAOE,IAAI,CAAE;QACnB,MAAMG,UAAUL,OAAOhB,KAAK;QAC5B,MAAMmB,aAAa,MAAMzB,QAAQ4B,SAAS,CAACD,QAAQvB,MAAM,EAAEuB,QAAQtB,KAAK,EAAEsB,QAAQrB,KAAK,EAAEqB,QAAQnC,OAAO,EAAEc,KAAK;QAC/GgB,SAASD,IAAIE,IAAI,CAACE;IACpB;IACA,OAAOH,OAAOhB,KAAK;AACrB"}
|
package/build/index.d.ts
CHANGED
|
@@ -25,9 +25,9 @@ export interface WaitRequest {
|
|
|
25
25
|
timeout?: number;
|
|
26
26
|
}
|
|
27
27
|
export type WaitResponse = ReturnType<typeof Atomics.wait>;
|
|
28
|
-
export declare function writeGenerator(data:
|
|
29
|
-
export declare function readGenerator(buffer: SharedArrayBuffer, { timeout }?: Options): Generator<WaitRequest,
|
|
30
|
-
export declare const writeSync: (data:
|
|
31
|
-
export declare const write: (data:
|
|
32
|
-
export declare const readSync: (buffer: SharedArrayBuffer, options?: Options) =>
|
|
33
|
-
export declare const read: (buffer: SharedArrayBuffer, options?: Options) => Promise<
|
|
28
|
+
export declare function writeGenerator(data: Uint8Array, buffer: SharedArrayBuffer, { timeout }?: Options): Generator<WaitRequest, void, WaitResponse>;
|
|
29
|
+
export declare function readGenerator(buffer: SharedArrayBuffer, { timeout }?: Options): Generator<WaitRequest, Uint8Array, WaitResponse>;
|
|
30
|
+
export declare const writeSync: (data: Uint8Array, buffer: SharedArrayBuffer, options?: Options) => void;
|
|
31
|
+
export declare const write: (data: Uint8Array, buffer: SharedArrayBuffer, options?: Options) => Promise<void>;
|
|
32
|
+
export declare const readSync: (buffer: SharedArrayBuffer, options?: Options) => Uint8Array;
|
|
33
|
+
export declare const read: (buffer: SharedArrayBuffer, options?: Options) => Promise<Uint8Array>;
|
package/build/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { serialize, deserialize } from "node:v8";
|
|
2
1
|
export const SEMAPHORE = 0;
|
|
3
2
|
export var Semaphore = /*#__PURE__*/ function(Semaphore) {
|
|
4
3
|
Semaphore[Semaphore["READY"] = 0] = "READY";
|
|
@@ -20,9 +19,8 @@ export var Header = /*#__PURE__*/ function(Header) {
|
|
|
20
19
|
export const HEADER_VALUES = 1 + Math.max(Object.values(Handshake).length, Object.values(Header).length) / 2;
|
|
21
20
|
export const HEADER_SIZE = Uint32Array.BYTES_PER_ELEMENT * HEADER_VALUES;
|
|
22
21
|
export function* writeGenerator(data, buffer, { timeout = 5000 } = {}) {
|
|
23
|
-
const serialized = serialize(data);
|
|
24
22
|
const chunkSize = buffer.byteLength - HEADER_SIZE;
|
|
25
|
-
const totalSize =
|
|
23
|
+
const totalSize = data.length;
|
|
26
24
|
const totalChunks = Math.ceil(totalSize / chunkSize);
|
|
27
25
|
const header = new Int32Array(buffer);
|
|
28
26
|
header[1] = totalSize;
|
|
@@ -36,15 +34,15 @@ export function* writeGenerator(data, buffer, { timeout = 5000 } = {}) {
|
|
|
36
34
|
value: 1,
|
|
37
35
|
timeout
|
|
38
36
|
};
|
|
39
|
-
if (handshakeResult ===
|
|
40
|
-
throw new Error(
|
|
37
|
+
if (handshakeResult === 'timed-out') {
|
|
38
|
+
throw new Error('Reader handshake timeout');
|
|
41
39
|
}
|
|
42
40
|
const payload = new Uint8Array(buffer, HEADER_SIZE);
|
|
43
41
|
for(let i = 0; i < totalChunks; i++){
|
|
44
42
|
const start = i * chunkSize;
|
|
45
43
|
const end = Math.min(start + chunkSize, totalSize);
|
|
46
44
|
const size = end - start;
|
|
47
|
-
payload.set(
|
|
45
|
+
payload.set(data.subarray(start, end), 0);
|
|
48
46
|
header[1] = i;
|
|
49
47
|
header[2] = start;
|
|
50
48
|
header[3] = size;
|
|
@@ -56,7 +54,7 @@ export function* writeGenerator(data, buffer, { timeout = 5000 } = {}) {
|
|
|
56
54
|
value: 2,
|
|
57
55
|
timeout
|
|
58
56
|
};
|
|
59
|
-
if (chunkResult ===
|
|
57
|
+
if (chunkResult === 'timed-out') {
|
|
60
58
|
throw new Error(`Reader timeout on chunk ${i}/${totalChunks - 1}`);
|
|
61
59
|
}
|
|
62
60
|
}
|
|
@@ -72,11 +70,11 @@ export function* readGenerator(buffer, { timeout = 5000 } = {}) {
|
|
|
72
70
|
value: 0,
|
|
73
71
|
timeout
|
|
74
72
|
};
|
|
75
|
-
if (handshakeResult ===
|
|
76
|
-
throw new Error(
|
|
73
|
+
if (handshakeResult === 'timed-out') {
|
|
74
|
+
throw new Error('Handshake timeout');
|
|
77
75
|
}
|
|
78
76
|
if (header[SEMAPHORE] !== 1) {
|
|
79
|
-
throw new Error(
|
|
77
|
+
throw new Error('Invalid handshake state');
|
|
80
78
|
}
|
|
81
79
|
const totalSize = header[1];
|
|
82
80
|
const totalChunks = header[2];
|
|
@@ -91,7 +89,7 @@ export function* readGenerator(buffer, { timeout = 5000 } = {}) {
|
|
|
91
89
|
value: 0,
|
|
92
90
|
timeout
|
|
93
91
|
};
|
|
94
|
-
if (chunkResult ===
|
|
92
|
+
if (chunkResult === 'timed-out') {
|
|
95
93
|
throw new Error(`Writer timeout waiting for chunk ${i}`);
|
|
96
94
|
}
|
|
97
95
|
if (header[SEMAPHORE] !== 2) {
|
|
@@ -107,7 +105,7 @@ export function* readGenerator(buffer, { timeout = 5000 } = {}) {
|
|
|
107
105
|
Atomics.store(header, SEMAPHORE, 0);
|
|
108
106
|
Atomics.notify(header, SEMAPHORE);
|
|
109
107
|
}
|
|
110
|
-
return
|
|
108
|
+
return data;
|
|
111
109
|
}
|
|
112
110
|
export const writeSync = (data, buffer, options)=>{
|
|
113
111
|
const gen = writeGenerator(data, buffer, options);
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { serialize, deserialize } from \"node:v8\";\n\nexport const SEMAPHORE = 0;\n\nexport enum Semaphore {\n READY,\n HANDSHAKE,\n PAYLOAD,\n}\n\nexport enum Handshake {\n TOTAL_SIZE = 1,\n TOTAL_CHUNKS,\n}\n\nexport enum Header {\n CHUNK_INDEX = 1,\n CHUNK_OFFSET,\n CHUNK_SIZE,\n}\n\nexport const HEADER_VALUES =\n 1 +\n Math.max(Object.values(Handshake).length, Object.values(Header).length) / 2;\nexport const HEADER_SIZE = Uint32Array.BYTES_PER_ELEMENT * HEADER_VALUES;\n\nexport interface Options {\n timeout?: number;\n}\n\nexport interface WaitRequest {\n target: Int32Array;\n index: number;\n value: number;\n timeout?: number;\n}\n\nexport type WaitResponse = ReturnType<typeof Atomics.wait>;\n\nexport function* writeGenerator(\n data: unknown,\n buffer: SharedArrayBuffer,\n { timeout = 5000 }: Options = {},\n): Generator<WaitRequest, void, WaitResponse> {\n const serialized = serialize(data);\n const chunkSize = buffer.byteLength - HEADER_SIZE;\n const totalSize = serialized.length;\n const totalChunks = Math.ceil(totalSize / chunkSize);\n const header = new Int32Array(buffer);\n\n header[Handshake.TOTAL_SIZE] = totalSize;\n header[Handshake.TOTAL_CHUNKS] = totalChunks;\n Atomics.store(header, SEMAPHORE, Semaphore.HANDSHAKE);\n Atomics.notify(header, SEMAPHORE);\n\n try {\n const handshakeResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.HANDSHAKE,\n timeout,\n };\n if (handshakeResult === \"timed-out\") {\n throw new Error(\"Reader handshake timeout\");\n }\n\n const payload = new Uint8Array(buffer, HEADER_SIZE);\n for (let i = 0; i < totalChunks; i++) {\n const start = i * chunkSize;\n const end = Math.min(start + chunkSize, totalSize);\n const size = end - start;\n payload.set(serialized.subarray(start, end), 0);\n header[Header.CHUNK_INDEX] = i;\n header[Header.CHUNK_OFFSET] = start;\n header[Header.CHUNK_SIZE] = size;\n Atomics.store(header, SEMAPHORE, Semaphore.PAYLOAD);\n Atomics.notify(header, SEMAPHORE);\n\n const chunkResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.PAYLOAD,\n timeout,\n };\n if (chunkResult === \"timed-out\") {\n throw new Error(`Reader timeout on chunk ${i}/${totalChunks - 1}`);\n }\n }\n } finally {\n Atomics.store(header, SEMAPHORE, Semaphore.READY);\n }\n}\n\nexport function* readGenerator(\n buffer: SharedArrayBuffer,\n { timeout = 5000 }: Options = {},\n): Generator<WaitRequest, unknown, WaitResponse> {\n const header = new Int32Array(buffer);\n\n const handshakeResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.READY,\n timeout,\n };\n if (handshakeResult === \"timed-out\") {\n throw new Error(\"Handshake timeout\");\n }\n if (header[SEMAPHORE] !== Semaphore.HANDSHAKE) {\n throw new Error(\"Invalid handshake state\");\n }\n\n const totalSize = header[Handshake.TOTAL_SIZE];\n const totalChunks = header[Handshake.TOTAL_CHUNKS];\n const data = new Uint8Array(totalSize);\n\n Atomics.store(header, SEMAPHORE, Semaphore.READY);\n Atomics.notify(header, SEMAPHORE);\n\n const payload = new Uint8Array(buffer, HEADER_SIZE);\n for (let i = 0; i < totalChunks; i++) {\n const chunkResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.READY,\n timeout,\n };\n if (chunkResult === \"timed-out\") {\n throw new Error(`Writer timeout waiting for chunk ${i}`);\n }\n // @ts-expect-error does not infer number\n if (header[SEMAPHORE] !== Semaphore.PAYLOAD) {\n throw new Error(\n `Expected payload header, received ${Semaphore[header[SEMAPHORE]]}`,\n );\n }\n const chunkIndex = header[Header.CHUNK_INDEX];\n if (i !== chunkIndex) {\n throw new Error(\n `Reader integrity failure for chunk ${chunkIndex} expected ${i}`,\n );\n }\n const offset = header[Header.CHUNK_OFFSET];\n const size = header[Header.CHUNK_SIZE];\n data.set(payload.subarray(0, size), offset);\n Atomics.store(header, SEMAPHORE, Semaphore.READY);\n Atomics.notify(header, SEMAPHORE);\n }\n return deserialize(data) as unknown;\n}\n\nexport const writeSync = (\n data: unknown,\n buffer: SharedArrayBuffer,\n options?: Options,\n) => {\n const gen = writeGenerator(data, buffer, options);\n let result = gen.next();\n while (!result.done) {\n const waitResult = Atomics.wait(\n result.value.target,\n result.value.index,\n result.value.value,\n result.value.timeout,\n );\n result = gen.next(waitResult);\n }\n};\n\nexport const write = async (\n data: unknown,\n buffer: SharedArrayBuffer,\n options?: Options,\n) => {\n const gen = writeGenerator(data, buffer, options);\n let result = gen.next();\n while (!result.done) {\n const request = result.value;\n const waitResult = await Atomics.waitAsync(\n request.target,\n request.index,\n request.value,\n request.timeout,\n ).value;\n result = gen.next(waitResult);\n }\n};\n\nexport const readSync = (\n buffer: SharedArrayBuffer,\n options?: Options,\n): unknown => {\n const gen = readGenerator(buffer, options);\n let result = gen.next();\n while (!result.done) {\n const waitResult = Atomics.wait(\n result.value.target,\n result.value.index,\n result.value.value,\n result.value.timeout,\n );\n result = gen.next(waitResult);\n }\n return result.value;\n};\n\nexport const read = async (\n buffer: SharedArrayBuffer,\n options?: Options,\n): Promise<unknown> => {\n const gen = readGenerator(buffer, options);\n let result = gen.next();\n while (!result.done) {\n const request = result.value;\n const waitResult = await Atomics.waitAsync(\n request.target,\n request.index,\n request.value,\n request.timeout,\n ).value;\n result = gen.next(waitResult);\n }\n return result.value;\n};\n"],"names":["serialize","deserialize","SEMAPHORE","Semaphore","Handshake","Header","HEADER_VALUES","Math","max","Object","values","length","HEADER_SIZE","Uint32Array","BYTES_PER_ELEMENT","writeGenerator","data","buffer","timeout","serialized","chunkSize","byteLength","totalSize","totalChunks","ceil","header","Int32Array","Atomics","store","notify","handshakeResult","target","index","value","Error","payload","Uint8Array","i","start","end","min","size","set","subarray","chunkResult","readGenerator","chunkIndex","offset","writeSync","options","gen","result","next","done","waitResult","wait","write","request","waitAsync","readSync","read"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export const SEMAPHORE = 0;\n\nexport enum Semaphore {\n READY,\n HANDSHAKE,\n PAYLOAD,\n}\n\nexport enum Handshake {\n TOTAL_SIZE = 1,\n TOTAL_CHUNKS,\n}\n\nexport enum Header {\n CHUNK_INDEX = 1,\n CHUNK_OFFSET,\n CHUNK_SIZE,\n}\n\nexport const HEADER_VALUES = 1 + Math.max(Object.values(Handshake).length, Object.values(Header).length) / 2;\nexport const HEADER_SIZE = Uint32Array.BYTES_PER_ELEMENT * HEADER_VALUES;\n\nexport interface Options {\n timeout?: number;\n}\n\nexport interface WaitRequest {\n target: Int32Array;\n index: number;\n value: number;\n timeout?: number;\n}\n\nexport type WaitResponse = ReturnType<typeof Atomics.wait>;\n\nexport function* writeGenerator(data: Uint8Array, buffer: SharedArrayBuffer, { timeout = 5000 }: Options = {}): Generator<WaitRequest, void, WaitResponse> {\n const chunkSize = buffer.byteLength - HEADER_SIZE;\n const totalSize = data.length;\n const totalChunks = Math.ceil(totalSize / chunkSize);\n const header = new Int32Array(buffer);\n\n header[Handshake.TOTAL_SIZE] = totalSize;\n header[Handshake.TOTAL_CHUNKS] = totalChunks;\n Atomics.store(header, SEMAPHORE, Semaphore.HANDSHAKE);\n Atomics.notify(header, SEMAPHORE);\n\n try {\n const handshakeResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.HANDSHAKE,\n timeout,\n };\n if (handshakeResult === 'timed-out') {\n throw new Error('Reader handshake timeout');\n }\n\n const payload = new Uint8Array(buffer, HEADER_SIZE);\n for (let i = 0; i < totalChunks; i++) {\n const start = i * chunkSize;\n const end = Math.min(start + chunkSize, totalSize);\n const size = end - start;\n payload.set(data.subarray(start, end), 0);\n header[Header.CHUNK_INDEX] = i;\n header[Header.CHUNK_OFFSET] = start;\n header[Header.CHUNK_SIZE] = size;\n Atomics.store(header, SEMAPHORE, Semaphore.PAYLOAD);\n Atomics.notify(header, SEMAPHORE);\n\n const chunkResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.PAYLOAD,\n timeout,\n };\n if (chunkResult === 'timed-out') {\n throw new Error(`Reader timeout on chunk ${i}/${totalChunks - 1}`);\n }\n }\n } finally {\n Atomics.store(header, SEMAPHORE, Semaphore.READY);\n }\n}\n\nexport function* readGenerator(buffer: SharedArrayBuffer, { timeout = 5000 }: Options = {}): Generator<WaitRequest, Uint8Array, WaitResponse> {\n const header = new Int32Array(buffer);\n\n const handshakeResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.READY,\n timeout,\n };\n if (handshakeResult === 'timed-out') {\n throw new Error('Handshake timeout');\n }\n if (header[SEMAPHORE] !== Semaphore.HANDSHAKE) {\n throw new Error('Invalid handshake state');\n }\n\n const totalSize = header[Handshake.TOTAL_SIZE];\n const totalChunks = header[Handshake.TOTAL_CHUNKS];\n const data = new Uint8Array(totalSize);\n\n Atomics.store(header, SEMAPHORE, Semaphore.READY);\n Atomics.notify(header, SEMAPHORE);\n\n const payload = new Uint8Array(buffer, HEADER_SIZE);\n for (let i = 0; i < totalChunks; i++) {\n const chunkResult: WaitResponse = yield {\n target: header,\n index: SEMAPHORE,\n value: Semaphore.READY,\n timeout,\n };\n if (chunkResult === 'timed-out') {\n throw new Error(`Writer timeout waiting for chunk ${i}`);\n }\n // @ts-expect-error does not infer number\n if (header[SEMAPHORE] !== Semaphore.PAYLOAD) {\n throw new Error(`Expected payload header, received ${Semaphore[header[SEMAPHORE]]}`);\n }\n const chunkIndex = header[Header.CHUNK_INDEX];\n if (i !== chunkIndex) {\n throw new Error(`Reader integrity failure for chunk ${chunkIndex} expected ${i}`);\n }\n const offset = header[Header.CHUNK_OFFSET];\n const size = header[Header.CHUNK_SIZE];\n data.set(payload.subarray(0, size), offset);\n Atomics.store(header, SEMAPHORE, Semaphore.READY);\n Atomics.notify(header, SEMAPHORE);\n }\n return data;\n}\n\nexport const writeSync = (data: Uint8Array, buffer: SharedArrayBuffer, options?: Options) => {\n const gen = writeGenerator(data, buffer, options);\n let result = gen.next();\n while (!result.done) {\n const waitResult = Atomics.wait(result.value.target, result.value.index, result.value.value, result.value.timeout);\n result = gen.next(waitResult);\n }\n};\n\nexport const write = async (data: Uint8Array, buffer: SharedArrayBuffer, options?: Options) => {\n const gen = writeGenerator(data, buffer, options);\n let result = gen.next();\n while (!result.done) {\n const request = result.value;\n const waitResult = await Atomics.waitAsync(request.target, request.index, request.value, request.timeout).value;\n result = gen.next(waitResult);\n }\n};\n\nexport const readSync = (buffer: SharedArrayBuffer, options?: Options): Uint8Array => {\n const gen = readGenerator(buffer, options);\n let result = gen.next();\n while (!result.done) {\n const waitResult = Atomics.wait(result.value.target, result.value.index, result.value.value, result.value.timeout);\n result = gen.next(waitResult);\n }\n return result.value;\n};\n\nexport const read = async (buffer: SharedArrayBuffer, options?: Options): Promise<Uint8Array> => {\n const gen = readGenerator(buffer, options);\n let result = gen.next();\n while (!result.done) {\n const request = result.value;\n const waitResult = await Atomics.waitAsync(request.target, request.index, request.value, request.timeout).value;\n result = gen.next(waitResult);\n }\n return result.value;\n};\n"],"names":["SEMAPHORE","Semaphore","Handshake","Header","HEADER_VALUES","Math","max","Object","values","length","HEADER_SIZE","Uint32Array","BYTES_PER_ELEMENT","writeGenerator","data","buffer","timeout","chunkSize","byteLength","totalSize","totalChunks","ceil","header","Int32Array","Atomics","store","notify","handshakeResult","target","index","value","Error","payload","Uint8Array","i","start","end","min","size","set","subarray","chunkResult","readGenerator","chunkIndex","offset","writeSync","options","gen","result","next","done","waitResult","wait","write","request","waitAsync","readSync","read"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sabcom",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "A TypeScript/Node.js library for inter-thread communication using SharedArrayBuffer with atomic operations
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A TypeScript/Node.js library for inter-thread communication using SharedArrayBuffer with atomic operations for raw buffer data transfer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
7
7
|
"main": "build/index.cjs",
|
|
@@ -31,8 +31,6 @@
|
|
|
31
31
|
"multithreading",
|
|
32
32
|
"ipc",
|
|
33
33
|
"inter-process",
|
|
34
|
-
"v8",
|
|
35
|
-
"serialization",
|
|
36
34
|
"synchronization",
|
|
37
35
|
"memory"
|
|
38
36
|
],
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { serialize, deserialize } from "node:v8";
|
|
2
|
-
|
|
3
1
|
export const SEMAPHORE = 0;
|
|
4
2
|
|
|
5
3
|
export enum Semaphore {
|
|
@@ -19,9 +17,7 @@ export enum Header {
|
|
|
19
17
|
CHUNK_SIZE,
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
export const HEADER_VALUES =
|
|
23
|
-
1 +
|
|
24
|
-
Math.max(Object.values(Handshake).length, Object.values(Header).length) / 2;
|
|
20
|
+
export const HEADER_VALUES = 1 + Math.max(Object.values(Handshake).length, Object.values(Header).length) / 2;
|
|
25
21
|
export const HEADER_SIZE = Uint32Array.BYTES_PER_ELEMENT * HEADER_VALUES;
|
|
26
22
|
|
|
27
23
|
export interface Options {
|
|
@@ -37,14 +33,9 @@ export interface WaitRequest {
|
|
|
37
33
|
|
|
38
34
|
export type WaitResponse = ReturnType<typeof Atomics.wait>;
|
|
39
35
|
|
|
40
|
-
export function* writeGenerator(
|
|
41
|
-
data: unknown,
|
|
42
|
-
buffer: SharedArrayBuffer,
|
|
43
|
-
{ timeout = 5000 }: Options = {},
|
|
44
|
-
): Generator<WaitRequest, void, WaitResponse> {
|
|
45
|
-
const serialized = serialize(data);
|
|
36
|
+
export function* writeGenerator(data: Uint8Array, buffer: SharedArrayBuffer, { timeout = 5000 }: Options = {}): Generator<WaitRequest, void, WaitResponse> {
|
|
46
37
|
const chunkSize = buffer.byteLength - HEADER_SIZE;
|
|
47
|
-
const totalSize =
|
|
38
|
+
const totalSize = data.length;
|
|
48
39
|
const totalChunks = Math.ceil(totalSize / chunkSize);
|
|
49
40
|
const header = new Int32Array(buffer);
|
|
50
41
|
|
|
@@ -60,8 +51,8 @@ export function* writeGenerator(
|
|
|
60
51
|
value: Semaphore.HANDSHAKE,
|
|
61
52
|
timeout,
|
|
62
53
|
};
|
|
63
|
-
if (handshakeResult ===
|
|
64
|
-
throw new Error(
|
|
54
|
+
if (handshakeResult === 'timed-out') {
|
|
55
|
+
throw new Error('Reader handshake timeout');
|
|
65
56
|
}
|
|
66
57
|
|
|
67
58
|
const payload = new Uint8Array(buffer, HEADER_SIZE);
|
|
@@ -69,7 +60,7 @@ export function* writeGenerator(
|
|
|
69
60
|
const start = i * chunkSize;
|
|
70
61
|
const end = Math.min(start + chunkSize, totalSize);
|
|
71
62
|
const size = end - start;
|
|
72
|
-
payload.set(
|
|
63
|
+
payload.set(data.subarray(start, end), 0);
|
|
73
64
|
header[Header.CHUNK_INDEX] = i;
|
|
74
65
|
header[Header.CHUNK_OFFSET] = start;
|
|
75
66
|
header[Header.CHUNK_SIZE] = size;
|
|
@@ -82,7 +73,7 @@ export function* writeGenerator(
|
|
|
82
73
|
value: Semaphore.PAYLOAD,
|
|
83
74
|
timeout,
|
|
84
75
|
};
|
|
85
|
-
if (chunkResult ===
|
|
76
|
+
if (chunkResult === 'timed-out') {
|
|
86
77
|
throw new Error(`Reader timeout on chunk ${i}/${totalChunks - 1}`);
|
|
87
78
|
}
|
|
88
79
|
}
|
|
@@ -91,10 +82,7 @@ export function* writeGenerator(
|
|
|
91
82
|
}
|
|
92
83
|
}
|
|
93
84
|
|
|
94
|
-
export function* readGenerator(
|
|
95
|
-
buffer: SharedArrayBuffer,
|
|
96
|
-
{ timeout = 5000 }: Options = {},
|
|
97
|
-
): Generator<WaitRequest, unknown, WaitResponse> {
|
|
85
|
+
export function* readGenerator(buffer: SharedArrayBuffer, { timeout = 5000 }: Options = {}): Generator<WaitRequest, Uint8Array, WaitResponse> {
|
|
98
86
|
const header = new Int32Array(buffer);
|
|
99
87
|
|
|
100
88
|
const handshakeResult: WaitResponse = yield {
|
|
@@ -103,11 +91,11 @@ export function* readGenerator(
|
|
|
103
91
|
value: Semaphore.READY,
|
|
104
92
|
timeout,
|
|
105
93
|
};
|
|
106
|
-
if (handshakeResult ===
|
|
107
|
-
throw new Error(
|
|
94
|
+
if (handshakeResult === 'timed-out') {
|
|
95
|
+
throw new Error('Handshake timeout');
|
|
108
96
|
}
|
|
109
97
|
if (header[SEMAPHORE] !== Semaphore.HANDSHAKE) {
|
|
110
|
-
throw new Error(
|
|
98
|
+
throw new Error('Invalid handshake state');
|
|
111
99
|
}
|
|
112
100
|
|
|
113
101
|
const totalSize = header[Handshake.TOTAL_SIZE];
|
|
@@ -125,20 +113,16 @@ export function* readGenerator(
|
|
|
125
113
|
value: Semaphore.READY,
|
|
126
114
|
timeout,
|
|
127
115
|
};
|
|
128
|
-
if (chunkResult ===
|
|
116
|
+
if (chunkResult === 'timed-out') {
|
|
129
117
|
throw new Error(`Writer timeout waiting for chunk ${i}`);
|
|
130
118
|
}
|
|
131
119
|
// @ts-expect-error does not infer number
|
|
132
120
|
if (header[SEMAPHORE] !== Semaphore.PAYLOAD) {
|
|
133
|
-
throw new Error(
|
|
134
|
-
`Expected payload header, received ${Semaphore[header[SEMAPHORE]]}`,
|
|
135
|
-
);
|
|
121
|
+
throw new Error(`Expected payload header, received ${Semaphore[header[SEMAPHORE]]}`);
|
|
136
122
|
}
|
|
137
123
|
const chunkIndex = header[Header.CHUNK_INDEX];
|
|
138
124
|
if (i !== chunkIndex) {
|
|
139
|
-
throw new Error(
|
|
140
|
-
`Reader integrity failure for chunk ${chunkIndex} expected ${i}`,
|
|
141
|
-
);
|
|
125
|
+
throw new Error(`Reader integrity failure for chunk ${chunkIndex} expected ${i}`);
|
|
142
126
|
}
|
|
143
127
|
const offset = header[Header.CHUNK_OFFSET];
|
|
144
128
|
const size = header[Header.CHUNK_SIZE];
|
|
@@ -146,78 +130,44 @@ export function* readGenerator(
|
|
|
146
130
|
Atomics.store(header, SEMAPHORE, Semaphore.READY);
|
|
147
131
|
Atomics.notify(header, SEMAPHORE);
|
|
148
132
|
}
|
|
149
|
-
return
|
|
133
|
+
return data;
|
|
150
134
|
}
|
|
151
135
|
|
|
152
|
-
export const writeSync = (
|
|
153
|
-
data: unknown,
|
|
154
|
-
buffer: SharedArrayBuffer,
|
|
155
|
-
options?: Options,
|
|
156
|
-
) => {
|
|
136
|
+
export const writeSync = (data: Uint8Array, buffer: SharedArrayBuffer, options?: Options) => {
|
|
157
137
|
const gen = writeGenerator(data, buffer, options);
|
|
158
138
|
let result = gen.next();
|
|
159
139
|
while (!result.done) {
|
|
160
|
-
const waitResult = Atomics.wait(
|
|
161
|
-
result.value.target,
|
|
162
|
-
result.value.index,
|
|
163
|
-
result.value.value,
|
|
164
|
-
result.value.timeout,
|
|
165
|
-
);
|
|
140
|
+
const waitResult = Atomics.wait(result.value.target, result.value.index, result.value.value, result.value.timeout);
|
|
166
141
|
result = gen.next(waitResult);
|
|
167
142
|
}
|
|
168
143
|
};
|
|
169
144
|
|
|
170
|
-
export const write = async (
|
|
171
|
-
data: unknown,
|
|
172
|
-
buffer: SharedArrayBuffer,
|
|
173
|
-
options?: Options,
|
|
174
|
-
) => {
|
|
145
|
+
export const write = async (data: Uint8Array, buffer: SharedArrayBuffer, options?: Options) => {
|
|
175
146
|
const gen = writeGenerator(data, buffer, options);
|
|
176
147
|
let result = gen.next();
|
|
177
148
|
while (!result.done) {
|
|
178
149
|
const request = result.value;
|
|
179
|
-
const waitResult = await Atomics.waitAsync(
|
|
180
|
-
request.target,
|
|
181
|
-
request.index,
|
|
182
|
-
request.value,
|
|
183
|
-
request.timeout,
|
|
184
|
-
).value;
|
|
150
|
+
const waitResult = await Atomics.waitAsync(request.target, request.index, request.value, request.timeout).value;
|
|
185
151
|
result = gen.next(waitResult);
|
|
186
152
|
}
|
|
187
153
|
};
|
|
188
154
|
|
|
189
|
-
export const readSync = (
|
|
190
|
-
buffer: SharedArrayBuffer,
|
|
191
|
-
options?: Options,
|
|
192
|
-
): unknown => {
|
|
155
|
+
export const readSync = (buffer: SharedArrayBuffer, options?: Options): Uint8Array => {
|
|
193
156
|
const gen = readGenerator(buffer, options);
|
|
194
157
|
let result = gen.next();
|
|
195
158
|
while (!result.done) {
|
|
196
|
-
const waitResult = Atomics.wait(
|
|
197
|
-
result.value.target,
|
|
198
|
-
result.value.index,
|
|
199
|
-
result.value.value,
|
|
200
|
-
result.value.timeout,
|
|
201
|
-
);
|
|
159
|
+
const waitResult = Atomics.wait(result.value.target, result.value.index, result.value.value, result.value.timeout);
|
|
202
160
|
result = gen.next(waitResult);
|
|
203
161
|
}
|
|
204
162
|
return result.value;
|
|
205
163
|
};
|
|
206
164
|
|
|
207
|
-
export const read = async (
|
|
208
|
-
buffer: SharedArrayBuffer,
|
|
209
|
-
options?: Options,
|
|
210
|
-
): Promise<unknown> => {
|
|
165
|
+
export const read = async (buffer: SharedArrayBuffer, options?: Options): Promise<Uint8Array> => {
|
|
211
166
|
const gen = readGenerator(buffer, options);
|
|
212
167
|
let result = gen.next();
|
|
213
168
|
while (!result.done) {
|
|
214
169
|
const request = result.value;
|
|
215
|
-
const waitResult = await Atomics.waitAsync(
|
|
216
|
-
request.target,
|
|
217
|
-
request.index,
|
|
218
|
-
request.value,
|
|
219
|
-
request.timeout,
|
|
220
|
-
).value;
|
|
170
|
+
const waitResult = await Atomics.waitAsync(request.target, request.index, request.value, request.timeout).value;
|
|
221
171
|
result = gen.next(waitResult);
|
|
222
172
|
}
|
|
223
173
|
return result.value;
|