pynect 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +478 -2
- package/SECURITY.md +34 -0
- package/binding.gyp +60 -0
- package/dist/cli/codegen.d.ts +3 -0
- package/dist/cli/codegen.d.ts.map +1 -0
- package/dist/cli/codegen.js +543 -0
- package/dist/cli/codegen.js.map +1 -0
- package/dist/cli/sync.d.ts +3 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +48 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/config/project.d.ts +57 -0
- package/dist/config/project.d.ts.map +1 -0
- package/dist/config/project.js +176 -0
- package/dist/config/project.js.map +1 -0
- package/dist/core/IsolatedWorker.d.ts +39 -0
- package/dist/core/IsolatedWorker.d.ts.map +1 -0
- package/dist/core/IsolatedWorker.js +178 -0
- package/dist/core/IsolatedWorker.js.map +1 -0
- package/dist/core/PyCallable.d.ts +67 -0
- package/dist/core/PyCallable.d.ts.map +1 -0
- package/dist/core/PyCallable.js +104 -0
- package/dist/core/PyCallable.js.map +1 -0
- package/dist/core/PyContext.d.ts +76 -0
- package/dist/core/PyContext.d.ts.map +1 -0
- package/dist/core/PyContext.js +239 -0
- package/dist/core/PyContext.js.map +1 -0
- package/dist/core/PyIterator.d.ts +84 -0
- package/dist/core/PyIterator.d.ts.map +1 -0
- package/dist/core/PyIterator.js +243 -0
- package/dist/core/PyIterator.js.map +1 -0
- package/dist/core/PyModule.d.ts +53 -0
- package/dist/core/PyModule.d.ts.map +1 -0
- package/dist/core/PyModule.js +162 -0
- package/dist/core/PyModule.js.map +1 -0
- package/dist/core/PyProxy.d.ts +75 -0
- package/dist/core/PyProxy.d.ts.map +1 -0
- package/dist/core/PyProxy.js +563 -0
- package/dist/core/PyProxy.js.map +1 -0
- package/dist/core/PyRuntime.d.ts +112 -0
- package/dist/core/PyRuntime.d.ts.map +1 -0
- package/dist/core/PyRuntime.js +546 -0
- package/dist/core/PyRuntime.js.map +1 -0
- package/dist/env/PackageInstaller.d.ts +232 -0
- package/dist/env/PackageInstaller.d.ts.map +1 -0
- package/dist/env/PackageInstaller.js +628 -0
- package/dist/env/PackageInstaller.js.map +1 -0
- package/dist/env/ProjectEnvironment.d.ts +63 -0
- package/dist/env/ProjectEnvironment.d.ts.map +1 -0
- package/dist/env/ProjectEnvironment.js +379 -0
- package/dist/env/ProjectEnvironment.js.map +1 -0
- package/dist/env/PyfigAdapter.d.ts +32 -0
- package/dist/env/PyfigAdapter.d.ts.map +1 -0
- package/dist/env/PyfigAdapter.js +10 -0
- package/dist/env/PyfigAdapter.js.map +1 -0
- package/dist/env/PythonDetector.d.ts +48 -0
- package/dist/env/PythonDetector.d.ts.map +1 -0
- package/dist/env/PythonDetector.js +182 -0
- package/dist/env/PythonDetector.js.map +1 -0
- package/dist/env/PythonProvisioner.d.ts +16 -0
- package/dist/env/PythonProvisioner.d.ts.map +1 -0
- package/dist/env/PythonProvisioner.js +42 -0
- package/dist/env/PythonProvisioner.js.map +1 -0
- package/dist/env/VenvManager.d.ts +55 -0
- package/dist/env/VenvManager.d.ts.map +1 -0
- package/dist/env/VenvManager.js +153 -0
- package/dist/env/VenvManager.js.map +1 -0
- package/dist/env/executables.d.ts +3 -0
- package/dist/env/executables.d.ts.map +1 -0
- package/dist/env/executables.js +14 -0
- package/dist/env/executables.js.map +1 -0
- package/dist/index.d.ts +182 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +393 -0
- package/dist/index.js.map +1 -0
- package/dist/native/NativeAddonLoader.d.ts +11 -0
- package/dist/native/NativeAddonLoader.d.ts.map +1 -0
- package/dist/native/NativeAddonLoader.js +75 -0
- package/dist/native/NativeAddonLoader.js.map +1 -0
- package/dist/plugins/Plugin.interface.d.ts +41 -0
- package/dist/plugins/Plugin.interface.d.ts.map +1 -0
- package/dist/plugins/Plugin.interface.js +12 -0
- package/dist/plugins/Plugin.interface.js.map +1 -0
- package/dist/plugins/PluginManager.d.ts +26 -0
- package/dist/plugins/PluginManager.d.ts.map +1 -0
- package/dist/plugins/PluginManager.js +174 -0
- package/dist/plugins/PluginManager.js.map +1 -0
- package/dist/plugins/builtin/NumpyPlugin.d.ts +17 -0
- package/dist/plugins/builtin/NumpyPlugin.d.ts.map +1 -0
- package/dist/plugins/builtin/NumpyPlugin.js +41 -0
- package/dist/plugins/builtin/NumpyPlugin.js.map +1 -0
- package/dist/plugins/builtin/PandasPlugin.d.ts +19 -0
- package/dist/plugins/builtin/PandasPlugin.d.ts.map +1 -0
- package/dist/plugins/builtin/PandasPlugin.js +57 -0
- package/dist/plugins/builtin/PandasPlugin.js.map +1 -0
- package/dist/plugins/builtin/TorchPlugin.d.ts +23 -0
- package/dist/plugins/builtin/TorchPlugin.d.ts.map +1 -0
- package/dist/plugins/builtin/TorchPlugin.js +50 -0
- package/dist/plugins/builtin/TorchPlugin.js.map +1 -0
- package/dist/plugins/index.d.ts +7 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +12 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/serialization/DataFrameBridge.d.ts +141 -0
- package/dist/serialization/DataFrameBridge.d.ts.map +1 -0
- package/dist/serialization/DataFrameBridge.js +355 -0
- package/dist/serialization/DataFrameBridge.js.map +1 -0
- package/dist/serialization/MsgPackSerializer.d.ts +45 -0
- package/dist/serialization/MsgPackSerializer.d.ts.map +1 -0
- package/dist/serialization/MsgPackSerializer.js +242 -0
- package/dist/serialization/MsgPackSerializer.js.map +1 -0
- package/dist/serialization/NumpyBridge.d.ts +96 -0
- package/dist/serialization/NumpyBridge.d.ts.map +1 -0
- package/dist/serialization/NumpyBridge.js +323 -0
- package/dist/serialization/NumpyBridge.js.map +1 -0
- package/dist/serialization/Serializer.d.ts +78 -0
- package/dist/serialization/Serializer.d.ts.map +1 -0
- package/dist/serialization/Serializer.js +281 -0
- package/dist/serialization/Serializer.js.map +1 -0
- package/dist/types/addon.d.ts +131 -0
- package/dist/types/addon.d.ts.map +1 -0
- package/dist/types/addon.js +32 -0
- package/dist/types/addon.js.map +1 -0
- package/dist/types/config.d.ts +233 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +60 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +12 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/python.d.ts +235 -0
- package/dist/types/python.d.ts.map +1 -0
- package/dist/types/python.js +7 -0
- package/dist/types/python.js.map +1 -0
- package/dist/utils/ErrorTranslator.d.ts +83 -0
- package/dist/utils/ErrorTranslator.d.ts.map +1 -0
- package/dist/utils/ErrorTranslator.js +210 -0
- package/dist/utils/ErrorTranslator.js.map +1 -0
- package/dist/utils/Locking.d.ts +3 -0
- package/dist/utils/Locking.d.ts.map +1 -0
- package/dist/utils/Locking.js +10 -0
- package/dist/utils/Locking.js.map +1 -0
- package/dist/utils/Logger.d.ts +27 -0
- package/dist/utils/Logger.d.ts.map +1 -0
- package/dist/utils/Logger.js +115 -0
- package/dist/utils/Logger.js.map +1 -0
- package/dist/utils/MemoryMonitor.d.ts +43 -0
- package/dist/utils/MemoryMonitor.d.ts.map +1 -0
- package/dist/utils/MemoryMonitor.js +143 -0
- package/dist/utils/MemoryMonitor.js.map +1 -0
- package/package.json +114 -4
- package/python/ast_inspector.py +248 -0
- package/python/error_handler.py +432 -0
- package/python/isolated_worker.py +94 -0
- package/python/pynect_dispatcher.py +382 -0
- package/python/pynect_runtime.py +574 -0
- package/python/serializer.py +373 -0
- package/python/type_inspector.py +315 -0
- package/scripts/build-native.js +50 -0
- package/scripts/cli.js +21 -0
- package/scripts/ensure-native.js +85 -0
- package/scripts/postinstall.js +40 -0
- package/scripts/pyfig.js +113 -0
- package/scripts/python-provisioner.js +23 -0
- package/scripts/smoke-python-boundary.js +103 -0
- package/src/native/NativeAddonLoader.ts +98 -0
- package/src/native/gil_guard.cpp +25 -0
- package/src/native/gil_guard.h +174 -0
- package/src/native/pynect_addon.cpp +942 -0
- package/src/native/python_bridge.cpp +904 -0
- package/src/native/python_bridge.h +263 -0
- package/src/native/thread_pool.cpp +375 -0
- package/src/native/thread_pool.h +185 -0
- package/src/native/type_converter.cpp +906 -0
- package/src/native/type_converter.h +271 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* pynect - MsgPackSerializer
|
|
4
|
+
* MessagePack encoder/decoder for high-performance binary serialization.
|
|
5
|
+
* Used for large arrays, complex objects, and bulk data transfer.
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.MsgPackSerializer = void 0;
|
|
42
|
+
const msgpack = __importStar(require("@msgpack/msgpack"));
|
|
43
|
+
const Logger_1 = require("../utils/Logger");
|
|
44
|
+
const logger = new Logger_1.Logger('MsgPackSerializer');
|
|
45
|
+
/**
|
|
46
|
+
* Extension type definitions for custom Python types.
|
|
47
|
+
* Extension type 1 = Python datetime
|
|
48
|
+
* Extension type 2 = Python complex number
|
|
49
|
+
* Extension type 3 = Python set
|
|
50
|
+
* Extension type 4 = Python tuple
|
|
51
|
+
* Extension type 5 = Python bytes
|
|
52
|
+
*/
|
|
53
|
+
var MsgPackExtType;
|
|
54
|
+
(function (MsgPackExtType) {
|
|
55
|
+
MsgPackExtType[MsgPackExtType["DATETIME"] = 1] = "DATETIME";
|
|
56
|
+
MsgPackExtType[MsgPackExtType["COMPLEX"] = 2] = "COMPLEX";
|
|
57
|
+
MsgPackExtType[MsgPackExtType["SET"] = 3] = "SET";
|
|
58
|
+
MsgPackExtType[MsgPackExtType["TUPLE"] = 4] = "TUPLE";
|
|
59
|
+
MsgPackExtType[MsgPackExtType["BYTES"] = 5] = "BYTES";
|
|
60
|
+
MsgPackExtType[MsgPackExtType["NUMPY_DTYPE"] = 10] = "NUMPY_DTYPE";
|
|
61
|
+
})(MsgPackExtType || (MsgPackExtType = {}));
|
|
62
|
+
/**
|
|
63
|
+
* MsgPackSerializer - encodes/decodes JavaScript <-> MessagePack binary.
|
|
64
|
+
*
|
|
65
|
+
* Handles Python-specific types via extension codecs:
|
|
66
|
+
* - Python datetime -> JS Date
|
|
67
|
+
* - Python set -> JS Set
|
|
68
|
+
* - Python tuple -> JS Array (immutable semantics lost, acceptable)
|
|
69
|
+
* - Python bytes -> JS Uint8Array
|
|
70
|
+
* - Python complex -> JS {real, imag}
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* const serializer = new MsgPackSerializer();
|
|
75
|
+
* const encoded = serializer.encode({ key: 'value', nums: [1, 2, 3] });
|
|
76
|
+
* const decoded = serializer.decode(encoded);
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
class MsgPackSerializer {
|
|
80
|
+
_encoderOptions;
|
|
81
|
+
_decoderOptions;
|
|
82
|
+
constructor() {
|
|
83
|
+
this._encoderOptions = {
|
|
84
|
+
extensionCodec: this._createExtensionCodec(),
|
|
85
|
+
forceIntegerToFloat: false,
|
|
86
|
+
forceFloat32: false,
|
|
87
|
+
sortKeys: false,
|
|
88
|
+
maxDepth: 64,
|
|
89
|
+
};
|
|
90
|
+
this._decoderOptions = {
|
|
91
|
+
extensionCodec: this._createExtensionCodec(),
|
|
92
|
+
// rawBinaryType: 'Uint8Array',
|
|
93
|
+
useBigInt64: false,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Encode a JavaScript value to MessagePack binary.
|
|
98
|
+
*/
|
|
99
|
+
encode(value) {
|
|
100
|
+
try {
|
|
101
|
+
return msgpack.encode(value, this._encoderOptions);
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
logger.error('MsgPack encoding failed', err);
|
|
105
|
+
// Fallback: try encoding as JSON string
|
|
106
|
+
try {
|
|
107
|
+
const json = JSON.stringify(value);
|
|
108
|
+
return msgpack.encode(json, this._encoderOptions);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
// Last resort: empty bytes
|
|
112
|
+
return new Uint8Array(0);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Decode a MessagePack binary to a JavaScript value.
|
|
118
|
+
*/
|
|
119
|
+
decode(data) {
|
|
120
|
+
if (!data || data.length === 0) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
return msgpack.decode(data, this._decoderOptions);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
logger.error('MsgPack decoding failed', err);
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Encode a stream of values (for streaming large datasets).
|
|
133
|
+
*/
|
|
134
|
+
encodeStream(values) {
|
|
135
|
+
const chunks = [];
|
|
136
|
+
let totalLength = 0;
|
|
137
|
+
for (const value of values) {
|
|
138
|
+
const encoded = this.encode(value);
|
|
139
|
+
chunks.push(encoded);
|
|
140
|
+
totalLength += encoded.length;
|
|
141
|
+
}
|
|
142
|
+
// Concatenate all chunks
|
|
143
|
+
const result = new Uint8Array(totalLength);
|
|
144
|
+
let offset = 0;
|
|
145
|
+
for (const chunk of chunks) {
|
|
146
|
+
result.set(chunk, offset);
|
|
147
|
+
offset += chunk.length;
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Decode a stream of values from MessagePack binary.
|
|
153
|
+
*/
|
|
154
|
+
*decodeStream(data) {
|
|
155
|
+
if (!data || data.length === 0) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
for (const item of msgpack.decodeMulti(data, this._decoderOptions)) {
|
|
160
|
+
yield item;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
logger.error('MsgPack stream decoding failed', err);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Extension Codec
|
|
168
|
+
_createExtensionCodec() {
|
|
169
|
+
const codec = new msgpack.ExtensionCodec();
|
|
170
|
+
// Python datetime -> JS Date
|
|
171
|
+
codec.register({
|
|
172
|
+
type: MsgPackExtType.DATETIME,
|
|
173
|
+
encode: (value) => {
|
|
174
|
+
if (value instanceof Date) {
|
|
175
|
+
const ms = value.getTime();
|
|
176
|
+
const buf = new ArrayBuffer(8);
|
|
177
|
+
new DataView(buf).setFloat64(0, ms, false);
|
|
178
|
+
return new Uint8Array(buf);
|
|
179
|
+
}
|
|
180
|
+
return null;
|
|
181
|
+
},
|
|
182
|
+
decode: (data) => {
|
|
183
|
+
const ms = new DataView(data.buffer, data.byteOffset, data.byteLength).getFloat64(0, false);
|
|
184
|
+
return new Date(ms);
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
// Python complex -> {real, imag}
|
|
188
|
+
codec.register({
|
|
189
|
+
type: MsgPackExtType.COMPLEX,
|
|
190
|
+
encode: (value) => {
|
|
191
|
+
if (value !== null &&
|
|
192
|
+
typeof value === 'object' &&
|
|
193
|
+
'real' in value &&
|
|
194
|
+
'imag' in value) {
|
|
195
|
+
const buf = new ArrayBuffer(16);
|
|
196
|
+
const dv = new DataView(buf);
|
|
197
|
+
dv.setFloat64(0, value.real, false);
|
|
198
|
+
dv.setFloat64(8, value.imag, false);
|
|
199
|
+
return new Uint8Array(buf);
|
|
200
|
+
}
|
|
201
|
+
return null;
|
|
202
|
+
},
|
|
203
|
+
decode: (data) => {
|
|
204
|
+
const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
205
|
+
return {
|
|
206
|
+
real: dv.getFloat64(0, false),
|
|
207
|
+
imag: dv.getFloat64(8, false),
|
|
208
|
+
};
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
// Python set -> JS Set
|
|
212
|
+
codec.register({
|
|
213
|
+
type: MsgPackExtType.SET,
|
|
214
|
+
encode: (value) => {
|
|
215
|
+
if (value instanceof Set) {
|
|
216
|
+
const arr = Array.from(value);
|
|
217
|
+
return this.encode(arr);
|
|
218
|
+
}
|
|
219
|
+
return null;
|
|
220
|
+
},
|
|
221
|
+
decode: (data) => {
|
|
222
|
+
const arr = this.decode(data);
|
|
223
|
+
return new Set(arr);
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
// Python tuple -> JS Array
|
|
227
|
+
codec.register({
|
|
228
|
+
type: MsgPackExtType.TUPLE,
|
|
229
|
+
encode: (_value) => {
|
|
230
|
+
// Tuples are encoded as arrays by Python side
|
|
231
|
+
return null;
|
|
232
|
+
},
|
|
233
|
+
decode: (data) => {
|
|
234
|
+
const decoded = this.decode(data);
|
|
235
|
+
return Array.isArray(decoded) ? decoded : [decoded];
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
return codec;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
exports.MsgPackSerializer = MsgPackSerializer;
|
|
242
|
+
//# sourceMappingURL=MsgPackSerializer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MsgPackSerializer.js","sourceRoot":"","sources":["../../src/serialization/MsgPackSerializer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pynect - NumpyBridge
|
|
3
|
+
* Converts NumPy arrays to/from JavaScript TypedArrays.
|
|
4
|
+
*
|
|
5
|
+
* Wire protocol (binary layout for NUMPY_ARRAY format):
|
|
6
|
+
* Bytes 0-3 : uint32 LE - ndim (number of dimensions)
|
|
7
|
+
* Bytes 4-7 : uint32 LE - dtype code (see NumpyDTypeCode)
|
|
8
|
+
* Bytes 8-11 : uint32 LE - itemsize in bytes
|
|
9
|
+
* Bytes 12-15 : uint32 LE - total element count
|
|
10
|
+
* Bytes 16.. : ndim x uint32 LE - shape dimensions
|
|
11
|
+
* After shape : raw element bytes (C-contiguous order)
|
|
12
|
+
*
|
|
13
|
+
* When SharedArrayBuffer is enabled the element bytes are placed in a
|
|
14
|
+
* SharedArrayBuffer so the data can be read from Node.js worker threads
|
|
15
|
+
* without copying.
|
|
16
|
+
*/
|
|
17
|
+
import type { SerializedValue, NumPyArrayResult } from '../types/python';
|
|
18
|
+
export declare enum NumpyDTypeCode {
|
|
19
|
+
BOOL = 0,
|
|
20
|
+
INT8 = 1,
|
|
21
|
+
INT16 = 2,
|
|
22
|
+
INT32 = 3,
|
|
23
|
+
INT64 = 4,
|
|
24
|
+
UINT8 = 5,
|
|
25
|
+
UINT16 = 6,
|
|
26
|
+
UINT32 = 7,
|
|
27
|
+
UINT64 = 8,
|
|
28
|
+
FLOAT32 = 9,
|
|
29
|
+
FLOAT64 = 10,
|
|
30
|
+
COMPLEX64 = 11,
|
|
31
|
+
COMPLEX128 = 12
|
|
32
|
+
}
|
|
33
|
+
export type NumpyDType = 'bool' | 'int8' | 'int16' | 'int32' | 'int64' | 'uint8' | 'uint16' | 'uint32' | 'uint64' | 'float32' | 'float64' | 'complex64' | 'complex128';
|
|
34
|
+
interface NumpyBridgeOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Use SharedArrayBuffer for large arrays.
|
|
37
|
+
* Requires `Cross-Origin-Opener-Policy: same-origin` and
|
|
38
|
+
* `Cross-Origin-Embedder-Policy: require-corp` response headers.
|
|
39
|
+
*/
|
|
40
|
+
useSharedArrayBuffer?: boolean;
|
|
41
|
+
/** Threshold in bytes above which SharedArrayBuffer is used. Default: 1 MB */
|
|
42
|
+
sharedArrayBufferThreshold?: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* NumpyBridge - converts NumPy arrays <-> TypedArrays.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const bridge = new NumpyBridge();
|
|
50
|
+
*
|
|
51
|
+
* // Serialize a Float32Array -> NumPy wire format
|
|
52
|
+
* const sv = bridge.serializeTypedArray(new Float32Array([1, 2, 3]), 'float32');
|
|
53
|
+
*
|
|
54
|
+
* // Deserialize NumPy wire format -> TypedArray
|
|
55
|
+
* const arr = bridge.deserialize(sv) as Float32Array;
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare class NumpyBridge {
|
|
59
|
+
private readonly _useShared;
|
|
60
|
+
private readonly _sharedThreshold;
|
|
61
|
+
constructor(options?: NumpyBridgeOptions);
|
|
62
|
+
/**
|
|
63
|
+
* Deserialize a NUMPY_ARRAY SerializedValue to a TypedArray.
|
|
64
|
+
*/
|
|
65
|
+
deserialize(sv: SerializedValue): NumPyArrayResult | null;
|
|
66
|
+
/**
|
|
67
|
+
* Serialize a TypedArray to a NUMPY_ARRAY SerializedValue.
|
|
68
|
+
*
|
|
69
|
+
* @param arr - the typed array
|
|
70
|
+
* @param dtype - NumPy dtype string
|
|
71
|
+
* @param shape - optional explicit shape; defaults to [arr.length]
|
|
72
|
+
*/
|
|
73
|
+
serializeTypedArray(arr: ArrayBufferView, dtype: NumpyDType | {
|
|
74
|
+
dtype: string;
|
|
75
|
+
itemsize: number;
|
|
76
|
+
}, shape?: number[]): SerializedValue;
|
|
77
|
+
/**
|
|
78
|
+
* Create an empty NumPy array SerializedValue (used for zero-size results).
|
|
79
|
+
*/
|
|
80
|
+
serializeEmpty(dtype?: NumpyDType): SerializedValue;
|
|
81
|
+
private _decodeBuffer;
|
|
82
|
+
private _buildTypedArray;
|
|
83
|
+
/**
|
|
84
|
+
* Detect dtype code from a TypedArray instance.
|
|
85
|
+
*/
|
|
86
|
+
static detectDType(arr: ArrayBufferView): {
|
|
87
|
+
dtype: NumpyDType;
|
|
88
|
+
itemsize: number;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Return the item size in bytes for a dtype string.
|
|
92
|
+
*/
|
|
93
|
+
static itemSizeOf(dtype: NumpyDType): number;
|
|
94
|
+
}
|
|
95
|
+
export {};
|
|
96
|
+
//# sourceMappingURL=NumpyBridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NumpyBridge.d.ts","sourceRoot":"","sources":["../../src/serialization/NumpyBridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAoB,gBAAgB,EAAmB,MAAM,iBAAiB,CAAC;AAO5G,oBAAY,cAAc;IACxB,IAAI,IAAQ;IACZ,IAAI,IAAQ;IACZ,KAAK,IAAO;IACZ,KAAK,IAAO;IACZ,KAAK,IAAO;IACZ,KAAK,IAAO;IACZ,MAAM,IAAM;IACZ,MAAM,IAAM;IACZ,MAAM,IAAM;IACZ,OAAO,IAAK;IACZ,OAAO,KAAK;IACZ,SAAS,KAAM;IACf,UAAU,KAAK;CAChB;AAED,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GACpC,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GACxC,SAAS,GAAG,SAAS,GACrB,WAAW,GAAG,YAAY,CAAC;AAE/B,UAAU,kBAAkB;IAC1B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,8EAA8E;IAC9E,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC;AAyCD;;;;;;;;;;;;;GAaG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;IACrC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,OAAO,GAAE,kBAAuB;IAO5C;;OAEG;IACH,WAAW,CAAC,EAAE,EAAE,eAAe,GAAG,gBAAgB,GAAG,IAAI;IAiCzD;;;;;;OAMG;IACH,mBAAmB,CACjB,GAAG,EAAE,eAAe,EACpB,KAAK,EAAE,UAAU,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EACvD,KAAK,CAAC,EAAE,MAAM,EAAE,GACf,eAAe;IA8ClB;;OAEG;IACH,cAAc,CAAC,KAAK,GAAE,UAAsB,GAAG,eAAe;IAM9D,OAAO,CAAC,aAAa;IA6BrB,OAAO,CAAC,gBAAgB;IAkDxB;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,eAAe,GAAG;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IAiBjF;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM;CAI7C"}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* pynect - NumpyBridge
|
|
4
|
+
* Converts NumPy arrays to/from JavaScript TypedArrays.
|
|
5
|
+
*
|
|
6
|
+
* Wire protocol (binary layout for NUMPY_ARRAY format):
|
|
7
|
+
* Bytes 0-3 : uint32 LE - ndim (number of dimensions)
|
|
8
|
+
* Bytes 4-7 : uint32 LE - dtype code (see NumpyDTypeCode)
|
|
9
|
+
* Bytes 8-11 : uint32 LE - itemsize in bytes
|
|
10
|
+
* Bytes 12-15 : uint32 LE - total element count
|
|
11
|
+
* Bytes 16.. : ndim x uint32 LE - shape dimensions
|
|
12
|
+
* After shape : raw element bytes (C-contiguous order)
|
|
13
|
+
*
|
|
14
|
+
* When SharedArrayBuffer is enabled the element bytes are placed in a
|
|
15
|
+
* SharedArrayBuffer so the data can be read from Node.js worker threads
|
|
16
|
+
* without copying.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.NumpyBridge = exports.NumpyDTypeCode = void 0;
|
|
20
|
+
const Logger_1 = require("../utils/Logger");
|
|
21
|
+
const logger = new Logger_1.Logger('NumpyBridge');
|
|
22
|
+
// NumPy dtype codes (must match Python side pynect_runtime.py)
|
|
23
|
+
var NumpyDTypeCode;
|
|
24
|
+
(function (NumpyDTypeCode) {
|
|
25
|
+
NumpyDTypeCode[NumpyDTypeCode["BOOL"] = 0] = "BOOL";
|
|
26
|
+
NumpyDTypeCode[NumpyDTypeCode["INT8"] = 1] = "INT8";
|
|
27
|
+
NumpyDTypeCode[NumpyDTypeCode["INT16"] = 2] = "INT16";
|
|
28
|
+
NumpyDTypeCode[NumpyDTypeCode["INT32"] = 3] = "INT32";
|
|
29
|
+
NumpyDTypeCode[NumpyDTypeCode["INT64"] = 4] = "INT64";
|
|
30
|
+
NumpyDTypeCode[NumpyDTypeCode["UINT8"] = 5] = "UINT8";
|
|
31
|
+
NumpyDTypeCode[NumpyDTypeCode["UINT16"] = 6] = "UINT16";
|
|
32
|
+
NumpyDTypeCode[NumpyDTypeCode["UINT32"] = 7] = "UINT32";
|
|
33
|
+
NumpyDTypeCode[NumpyDTypeCode["UINT64"] = 8] = "UINT64";
|
|
34
|
+
NumpyDTypeCode[NumpyDTypeCode["FLOAT32"] = 9] = "FLOAT32";
|
|
35
|
+
NumpyDTypeCode[NumpyDTypeCode["FLOAT64"] = 10] = "FLOAT64";
|
|
36
|
+
NumpyDTypeCode[NumpyDTypeCode["COMPLEX64"] = 11] = "COMPLEX64";
|
|
37
|
+
NumpyDTypeCode[NumpyDTypeCode["COMPLEX128"] = 12] = "COMPLEX128";
|
|
38
|
+
})(NumpyDTypeCode || (exports.NumpyDTypeCode = NumpyDTypeCode = {}));
|
|
39
|
+
/** Header size in bytes (see layout above) */
|
|
40
|
+
const HEADER_BYTES = 16;
|
|
41
|
+
// dtype string -> NumpyDTypeCode
|
|
42
|
+
const DTYPE_STRING_TO_CODE = {
|
|
43
|
+
bool: NumpyDTypeCode.BOOL,
|
|
44
|
+
int8: NumpyDTypeCode.INT8,
|
|
45
|
+
int16: NumpyDTypeCode.INT16,
|
|
46
|
+
int32: NumpyDTypeCode.INT32,
|
|
47
|
+
int64: NumpyDTypeCode.INT64,
|
|
48
|
+
uint8: NumpyDTypeCode.UINT8,
|
|
49
|
+
uint16: NumpyDTypeCode.UINT16,
|
|
50
|
+
uint32: NumpyDTypeCode.UINT32,
|
|
51
|
+
uint64: NumpyDTypeCode.UINT64,
|
|
52
|
+
float32: NumpyDTypeCode.FLOAT32,
|
|
53
|
+
float64: NumpyDTypeCode.FLOAT64,
|
|
54
|
+
complex64: NumpyDTypeCode.COMPLEX64,
|
|
55
|
+
complex128: NumpyDTypeCode.COMPLEX128,
|
|
56
|
+
};
|
|
57
|
+
// NumpyDTypeCode -> item size in bytes
|
|
58
|
+
const DTYPE_CODE_TO_ITEMSIZE = {
|
|
59
|
+
[NumpyDTypeCode.BOOL]: 1,
|
|
60
|
+
[NumpyDTypeCode.INT8]: 1,
|
|
61
|
+
[NumpyDTypeCode.INT16]: 2,
|
|
62
|
+
[NumpyDTypeCode.INT32]: 4,
|
|
63
|
+
[NumpyDTypeCode.INT64]: 8,
|
|
64
|
+
[NumpyDTypeCode.UINT8]: 1,
|
|
65
|
+
[NumpyDTypeCode.UINT16]: 2,
|
|
66
|
+
[NumpyDTypeCode.UINT32]: 4,
|
|
67
|
+
[NumpyDTypeCode.UINT64]: 8,
|
|
68
|
+
[NumpyDTypeCode.FLOAT32]: 4,
|
|
69
|
+
[NumpyDTypeCode.FLOAT64]: 8,
|
|
70
|
+
[NumpyDTypeCode.COMPLEX64]: 8,
|
|
71
|
+
[NumpyDTypeCode.COMPLEX128]: 16,
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* NumpyBridge - converts NumPy arrays <-> TypedArrays.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const bridge = new NumpyBridge();
|
|
79
|
+
*
|
|
80
|
+
* // Serialize a Float32Array -> NumPy wire format
|
|
81
|
+
* const sv = bridge.serializeTypedArray(new Float32Array([1, 2, 3]), 'float32');
|
|
82
|
+
*
|
|
83
|
+
* // Deserialize NumPy wire format -> TypedArray
|
|
84
|
+
* const arr = bridge.deserialize(sv) as Float32Array;
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
class NumpyBridge {
|
|
88
|
+
_useShared;
|
|
89
|
+
_sharedThreshold;
|
|
90
|
+
constructor(options = {}) {
|
|
91
|
+
this._useShared = options.useSharedArrayBuffer ?? false;
|
|
92
|
+
this._sharedThreshold = options.sharedArrayBufferThreshold ?? 1_048_576; // 1 MB
|
|
93
|
+
}
|
|
94
|
+
// Python wire format -> TypedArray
|
|
95
|
+
/**
|
|
96
|
+
* Deserialize a NUMPY_ARRAY SerializedValue to a TypedArray.
|
|
97
|
+
*/
|
|
98
|
+
deserialize(sv) {
|
|
99
|
+
if (sv.format !== 'numpy_array') {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const rawData = sv.data;
|
|
103
|
+
if (!rawData) {
|
|
104
|
+
logger.warn('NumpyBridge.deserialize: invalid data');
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
let u8;
|
|
109
|
+
if (typeof rawData === 'string') {
|
|
110
|
+
// base64-encoded binary
|
|
111
|
+
const buf = Buffer.from(rawData, 'base64');
|
|
112
|
+
u8 = new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
113
|
+
}
|
|
114
|
+
else if (rawData instanceof Uint8Array) {
|
|
115
|
+
u8 = rawData;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
logger.warn('NumpyBridge.deserialize: unsupported data type');
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
if (u8.length < HEADER_BYTES) {
|
|
122
|
+
logger.warn('NumpyBridge.deserialize: buffer too small');
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
return this._decodeBuffer(u8);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
logger.error('NumpyBridge.deserialize failed', err);
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// TypedArray -> Python wire format
|
|
133
|
+
/**
|
|
134
|
+
* Serialize a TypedArray to a NUMPY_ARRAY SerializedValue.
|
|
135
|
+
*
|
|
136
|
+
* @param arr - the typed array
|
|
137
|
+
* @param dtype - NumPy dtype string
|
|
138
|
+
* @param shape - optional explicit shape; defaults to [arr.length]
|
|
139
|
+
*/
|
|
140
|
+
serializeTypedArray(arr, dtype, shape) {
|
|
141
|
+
const dtypeStr = (typeof dtype === 'string' ? dtype : dtype.dtype);
|
|
142
|
+
const dtypeCode = DTYPE_STRING_TO_CODE[dtypeStr] ?? NumpyDTypeCode.FLOAT64;
|
|
143
|
+
const itemSize = DTYPE_CODE_TO_ITEMSIZE[dtypeCode];
|
|
144
|
+
const dims = shape ?? [arr.byteLength / itemSize];
|
|
145
|
+
const ndim = dims.length;
|
|
146
|
+
const count = dims.reduce((a, b) => a * b, 1);
|
|
147
|
+
const dataBytes = count * itemSize;
|
|
148
|
+
const totalBytes = HEADER_BYTES + ndim * 4 + dataBytes;
|
|
149
|
+
const buffer = new ArrayBuffer(totalBytes);
|
|
150
|
+
const dv = new DataView(buffer);
|
|
151
|
+
const u8 = new Uint8Array(buffer);
|
|
152
|
+
// Write header
|
|
153
|
+
dv.setUint32(0, ndim, true);
|
|
154
|
+
dv.setUint32(4, dtypeCode, true);
|
|
155
|
+
dv.setUint32(8, itemSize, true);
|
|
156
|
+
dv.setUint32(12, count, true);
|
|
157
|
+
// Write shape
|
|
158
|
+
for (let i = 0; i < ndim; i++) {
|
|
159
|
+
dv.setUint32(HEADER_BYTES + i * 4, dims[i], true);
|
|
160
|
+
}
|
|
161
|
+
// Write data
|
|
162
|
+
const srcU8 = new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
163
|
+
u8.set(srcU8, HEADER_BYTES + ndim * 4);
|
|
164
|
+
return {
|
|
165
|
+
format: 'numpy_array',
|
|
166
|
+
data: u8,
|
|
167
|
+
metadata: {
|
|
168
|
+
dtype: dtypeStr,
|
|
169
|
+
shape: dims,
|
|
170
|
+
itemSize,
|
|
171
|
+
size: dataBytes,
|
|
172
|
+
length: count,
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Create an empty NumPy array SerializedValue (used for zero-size results).
|
|
178
|
+
*/
|
|
179
|
+
serializeEmpty(dtype = 'float64') {
|
|
180
|
+
return this.serializeTypedArray(new Float64Array(0), dtype, [0]);
|
|
181
|
+
}
|
|
182
|
+
// Helpers
|
|
183
|
+
_decodeBuffer(u8) {
|
|
184
|
+
const dv = new DataView(u8.buffer, u8.byteOffset, u8.byteLength);
|
|
185
|
+
const ndim = dv.getUint32(0, true);
|
|
186
|
+
const dtypeCode = dv.getUint32(4, true);
|
|
187
|
+
const itemSize = dv.getUint32(8, true);
|
|
188
|
+
const count = dv.getUint32(12, true);
|
|
189
|
+
// Read shape
|
|
190
|
+
const shape = [];
|
|
191
|
+
for (let i = 0; i < ndim; i++) {
|
|
192
|
+
shape.push(dv.getUint32(HEADER_BYTES + i * 4, true));
|
|
193
|
+
}
|
|
194
|
+
const dataOffset = HEADER_BYTES + ndim * 4;
|
|
195
|
+
const dataLength = count * itemSize;
|
|
196
|
+
if (u8.length < dataOffset + dataLength) {
|
|
197
|
+
throw new Error(`NumpyBridge: buffer too small. ` +
|
|
198
|
+
`Expected ${dataOffset + dataLength} bytes, got ${u8.length}`);
|
|
199
|
+
}
|
|
200
|
+
const srcBuffer = u8.buffer;
|
|
201
|
+
const srcByteOffset = u8.byteOffset + dataOffset;
|
|
202
|
+
return this._buildTypedArray(dtypeCode, srcBuffer, srcByteOffset, count, shape, ndim);
|
|
203
|
+
}
|
|
204
|
+
_buildTypedArray(code, srcBuffer, byteOffset, count, shape = [], ndim = 1) {
|
|
205
|
+
const useShared = this._useShared &&
|
|
206
|
+
typeof SharedArrayBuffer !== 'undefined' &&
|
|
207
|
+
count * DTYPE_CODE_TO_ITEMSIZE[code] >= this._sharedThreshold;
|
|
208
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
209
|
+
const targetBuffer = (useShared
|
|
210
|
+
? new SharedArrayBuffer(count * DTYPE_CODE_TO_ITEMSIZE[code])
|
|
211
|
+
: new ArrayBuffer(count * DTYPE_CODE_TO_ITEMSIZE[code]));
|
|
212
|
+
// Copy data
|
|
213
|
+
const src = new Uint8Array(srcBuffer, byteOffset, count * DTYPE_CODE_TO_ITEMSIZE[code]);
|
|
214
|
+
const dest = new Uint8Array(targetBuffer);
|
|
215
|
+
dest.set(src);
|
|
216
|
+
let data;
|
|
217
|
+
let dtypeStr;
|
|
218
|
+
switch (code) {
|
|
219
|
+
case NumpyDTypeCode.BOOL:
|
|
220
|
+
case NumpyDTypeCode.UINT8:
|
|
221
|
+
data = new Uint8Array(targetBuffer);
|
|
222
|
+
dtypeStr = code === NumpyDTypeCode.BOOL ? 'bool' : 'uint8';
|
|
223
|
+
break;
|
|
224
|
+
case NumpyDTypeCode.INT8:
|
|
225
|
+
data = new Int8Array(targetBuffer);
|
|
226
|
+
dtypeStr = 'int8';
|
|
227
|
+
break;
|
|
228
|
+
case NumpyDTypeCode.INT16:
|
|
229
|
+
data = new Int16Array(targetBuffer);
|
|
230
|
+
dtypeStr = 'int16';
|
|
231
|
+
break;
|
|
232
|
+
case NumpyDTypeCode.INT32:
|
|
233
|
+
data = new Int32Array(targetBuffer);
|
|
234
|
+
dtypeStr = 'int32';
|
|
235
|
+
break;
|
|
236
|
+
case NumpyDTypeCode.INT64:
|
|
237
|
+
data = new BigInt64Array(targetBuffer);
|
|
238
|
+
dtypeStr = 'int64';
|
|
239
|
+
break;
|
|
240
|
+
case NumpyDTypeCode.UINT16:
|
|
241
|
+
data = new Uint16Array(targetBuffer);
|
|
242
|
+
dtypeStr = 'uint16';
|
|
243
|
+
break;
|
|
244
|
+
case NumpyDTypeCode.UINT32:
|
|
245
|
+
data = new Uint32Array(targetBuffer);
|
|
246
|
+
dtypeStr = 'uint32';
|
|
247
|
+
break;
|
|
248
|
+
case NumpyDTypeCode.UINT64:
|
|
249
|
+
data = new BigUint64Array(targetBuffer);
|
|
250
|
+
dtypeStr = 'uint64';
|
|
251
|
+
break;
|
|
252
|
+
case NumpyDTypeCode.FLOAT32:
|
|
253
|
+
data = new Float32Array(targetBuffer);
|
|
254
|
+
dtypeStr = 'float32';
|
|
255
|
+
break;
|
|
256
|
+
case NumpyDTypeCode.COMPLEX64:
|
|
257
|
+
data = new Float32Array(targetBuffer);
|
|
258
|
+
dtypeStr = 'complex64';
|
|
259
|
+
break;
|
|
260
|
+
case NumpyDTypeCode.COMPLEX128:
|
|
261
|
+
data = new Float64Array(targetBuffer);
|
|
262
|
+
dtypeStr = 'complex128';
|
|
263
|
+
break;
|
|
264
|
+
case NumpyDTypeCode.FLOAT64:
|
|
265
|
+
default:
|
|
266
|
+
data = new Float64Array(targetBuffer);
|
|
267
|
+
dtypeStr = 'float64';
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
return { data, dtype: dtypeStr, shape, ndim };
|
|
271
|
+
}
|
|
272
|
+
// Static helpers
|
|
273
|
+
/**
|
|
274
|
+
* Detect dtype code from a TypedArray instance.
|
|
275
|
+
*/
|
|
276
|
+
static detectDType(arr) {
|
|
277
|
+
let dtype;
|
|
278
|
+
if (arr instanceof Float32Array) {
|
|
279
|
+
dtype = 'float32';
|
|
280
|
+
}
|
|
281
|
+
else if (arr instanceof Float64Array) {
|
|
282
|
+
dtype = 'float64';
|
|
283
|
+
}
|
|
284
|
+
else if (arr instanceof Int8Array) {
|
|
285
|
+
dtype = 'int8';
|
|
286
|
+
}
|
|
287
|
+
else if (arr instanceof Int16Array) {
|
|
288
|
+
dtype = 'int16';
|
|
289
|
+
}
|
|
290
|
+
else if (arr instanceof Int32Array) {
|
|
291
|
+
dtype = 'int32';
|
|
292
|
+
}
|
|
293
|
+
else if (arr instanceof BigInt64Array) {
|
|
294
|
+
dtype = 'int64';
|
|
295
|
+
}
|
|
296
|
+
else if (arr instanceof Uint8Array) {
|
|
297
|
+
dtype = 'uint8';
|
|
298
|
+
}
|
|
299
|
+
else if (arr instanceof Uint16Array) {
|
|
300
|
+
dtype = 'uint16';
|
|
301
|
+
}
|
|
302
|
+
else if (arr instanceof Uint32Array) {
|
|
303
|
+
dtype = 'uint32';
|
|
304
|
+
}
|
|
305
|
+
else if (arr instanceof BigUint64Array) {
|
|
306
|
+
dtype = 'uint64';
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
dtype = 'float64';
|
|
310
|
+
}
|
|
311
|
+
const code = DTYPE_STRING_TO_CODE[dtype] ?? NumpyDTypeCode.FLOAT64;
|
|
312
|
+
return { dtype, itemsize: DTYPE_CODE_TO_ITEMSIZE[code] };
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Return the item size in bytes for a dtype string.
|
|
316
|
+
*/
|
|
317
|
+
static itemSizeOf(dtype) {
|
|
318
|
+
const code = DTYPE_STRING_TO_CODE[dtype] ?? NumpyDTypeCode.FLOAT64;
|
|
319
|
+
return DTYPE_CODE_TO_ITEMSIZE[code];
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
exports.NumpyBridge = NumpyBridge;
|
|
323
|
+
//# sourceMappingURL=NumpyBridge.js.map
|