@lakutata/ffi 0.0.0-stage → 3.1.5

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.
Files changed (129) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +163 -2
  3. package/README.zh-CN.md +140 -0
  4. package/dist/cjs/components/NativeLibrary.d.ts +229 -0
  5. package/dist/cjs/components/NativeLibrary.js +346 -0
  6. package/dist/cjs/decorators/Library.d.ts +61 -0
  7. package/dist/cjs/decorators/Library.js +44 -0
  8. package/dist/cjs/decorators/Native.d.ts +69 -0
  9. package/dist/cjs/decorators/Native.js +90 -0
  10. package/dist/cjs/exceptions/NativeDeclarationException.d.ts +12 -0
  11. package/dist/cjs/exceptions/NativeDeclarationException.js +19 -0
  12. package/dist/cjs/exceptions/NativeLibraryClosedException.d.ts +12 -0
  13. package/dist/cjs/exceptions/NativeLibraryClosedException.js +19 -0
  14. package/dist/cjs/exceptions/NativeLibraryNotFoundException.d.ts +11 -0
  15. package/dist/cjs/exceptions/NativeLibraryNotFoundException.js +18 -0
  16. package/dist/cjs/exceptions/NativeMemoryException.d.ts +11 -0
  17. package/dist/cjs/exceptions/NativeMemoryException.js +18 -0
  18. package/dist/cjs/exports/FFI.d.ts +12 -0
  19. package/dist/cjs/exports/FFI.js +40 -0
  20. package/dist/cjs/exports/Generator.d.ts +2 -0
  21. package/dist/cjs/exports/Generator.js +10 -0
  22. package/dist/cjs/lib/Memory.d.ts +188 -0
  23. package/dist/cjs/lib/Memory.js +227 -0
  24. package/dist/cjs/lib/Runtime.d.ts +98 -0
  25. package/dist/cjs/lib/Runtime.js +209 -0
  26. package/dist/cjs/lib/backend/Functions.d.ts +65 -0
  27. package/dist/cjs/lib/backend/Functions.js +214 -0
  28. package/dist/cjs/lib/backend/KoffiTypes.d.ts +53 -0
  29. package/dist/cjs/lib/backend/KoffiTypes.js +426 -0
  30. package/dist/cjs/lib/declarations/Builtins.d.ts +33 -0
  31. package/dist/cjs/lib/declarations/Builtins.js +179 -0
  32. package/dist/cjs/lib/declarations/Layout.d.ts +41 -0
  33. package/dist/cjs/lib/declarations/Layout.js +180 -0
  34. package/dist/cjs/lib/declarations/Lexer.d.ts +40 -0
  35. package/dist/cjs/lib/declarations/Lexer.js +325 -0
  36. package/dist/cjs/lib/declarations/Parser.d.ts +90 -0
  37. package/dist/cjs/lib/declarations/Parser.js +1425 -0
  38. package/dist/cjs/lib/declarations/Platform.d.ts +50 -0
  39. package/dist/cjs/lib/declarations/Platform.js +27 -0
  40. package/dist/cjs/lib/declarations/Types.d.ts +173 -0
  41. package/dist/cjs/lib/declarations/Types.js +179 -0
  42. package/dist/cjs/lib/generator/CText.d.ts +14 -0
  43. package/dist/cjs/lib/generator/CText.js +133 -0
  44. package/dist/cjs/lib/generator/Generator.d.ts +136 -0
  45. package/dist/cjs/lib/generator/Generator.js +395 -0
  46. package/dist/cjs/lib/generator/Preprocessor.d.ts +60 -0
  47. package/dist/cjs/lib/generator/Preprocessor.js +94 -0
  48. package/dist/cjs/lib/generator/TypeScriptTypes.d.ts +35 -0
  49. package/dist/cjs/lib/generator/TypeScriptTypes.js +153 -0
  50. package/dist/cjs/lib/library/NativeCallback.d.ts +44 -0
  51. package/dist/cjs/lib/library/NativeCallback.js +66 -0
  52. package/dist/cjs/lib/library/NativeLibraryHandle.d.ts +268 -0
  53. package/dist/cjs/lib/library/NativeLibraryHandle.js +540 -0
  54. package/dist/cjs/lib/library/Resolve.d.ts +49 -0
  55. package/dist/cjs/lib/library/Resolve.js +130 -0
  56. package/dist/cjs/lib/thread/NativeThreads.d.ts +80 -0
  57. package/dist/cjs/lib/thread/NativeThreads.js +384 -0
  58. package/dist/cjs/lib/thread/NativeWorker.d.ts +6 -0
  59. package/dist/cjs/lib/thread/NativeWorker.js +96 -0
  60. package/dist/cjs/lib/thread/NativeWorkerCode.d.ts +5 -0
  61. package/dist/cjs/lib/thread/NativeWorkerCode.js +4 -0
  62. package/dist/cjs/lib/thread/PackageRequire.d.ts +6 -0
  63. package/dist/cjs/lib/thread/PackageRequire.js +4 -0
  64. package/dist/cjs/lib/thread/ThreadProtocol.d.ts +77 -0
  65. package/dist/cjs/lib/thread/ThreadProtocol.js +2 -0
  66. package/dist/cjs/package.json +1 -0
  67. package/dist/esm/components/NativeLibrary.js +338 -0
  68. package/dist/esm/decorators/Library.js +40 -0
  69. package/dist/esm/decorators/Native.js +85 -0
  70. package/dist/esm/exceptions/NativeDeclarationException.js +15 -0
  71. package/dist/esm/exceptions/NativeLibraryClosedException.js +15 -0
  72. package/dist/esm/exceptions/NativeLibraryNotFoundException.js +14 -0
  73. package/dist/esm/exceptions/NativeMemoryException.js +14 -0
  74. package/dist/esm/exports/FFI.js +10 -0
  75. package/dist/esm/exports/Generator.js +2 -0
  76. package/dist/esm/lib/Memory.js +210 -0
  77. package/dist/esm/lib/Runtime.js +192 -0
  78. package/dist/esm/lib/backend/Functions.js +206 -0
  79. package/dist/esm/lib/backend/KoffiTypes.js +418 -0
  80. package/dist/esm/lib/declarations/Builtins.js +174 -0
  81. package/dist/esm/lib/declarations/Layout.js +175 -0
  82. package/dist/esm/lib/declarations/Lexer.js +321 -0
  83. package/dist/esm/lib/declarations/Parser.js +1421 -0
  84. package/dist/esm/lib/declarations/Platform.js +23 -0
  85. package/dist/esm/lib/declarations/Types.js +170 -0
  86. package/dist/esm/lib/generator/CText.js +129 -0
  87. package/dist/esm/lib/generator/Generator.js +388 -0
  88. package/dist/esm/lib/generator/Preprocessor.js +87 -0
  89. package/dist/esm/lib/generator/TypeScriptTypes.js +149 -0
  90. package/dist/esm/lib/library/NativeCallback.js +59 -0
  91. package/dist/esm/lib/library/NativeLibraryHandle.js +532 -0
  92. package/dist/esm/lib/library/Resolve.js +122 -0
  93. package/dist/esm/lib/thread/NativeThreads.js +377 -0
  94. package/dist/esm/lib/thread/NativeWorker.js +93 -0
  95. package/dist/esm/lib/thread/NativeWorkerCode.js +1 -0
  96. package/dist/esm/lib/thread/PackageRequire.js +2 -0
  97. package/dist/esm/lib/thread/ThreadProtocol.js +1 -0
  98. package/dist/types/components/NativeLibrary.d.ts +229 -0
  99. package/dist/types/decorators/Library.d.ts +61 -0
  100. package/dist/types/decorators/Native.d.ts +69 -0
  101. package/dist/types/exceptions/NativeDeclarationException.d.ts +12 -0
  102. package/dist/types/exceptions/NativeLibraryClosedException.d.ts +12 -0
  103. package/dist/types/exceptions/NativeLibraryNotFoundException.d.ts +11 -0
  104. package/dist/types/exceptions/NativeMemoryException.d.ts +11 -0
  105. package/dist/types/exports/FFI.d.ts +12 -0
  106. package/dist/types/exports/Generator.d.ts +2 -0
  107. package/dist/types/lib/Memory.d.ts +188 -0
  108. package/dist/types/lib/Runtime.d.ts +98 -0
  109. package/dist/types/lib/backend/Functions.d.ts +65 -0
  110. package/dist/types/lib/backend/KoffiTypes.d.ts +53 -0
  111. package/dist/types/lib/declarations/Builtins.d.ts +33 -0
  112. package/dist/types/lib/declarations/Layout.d.ts +41 -0
  113. package/dist/types/lib/declarations/Lexer.d.ts +40 -0
  114. package/dist/types/lib/declarations/Parser.d.ts +90 -0
  115. package/dist/types/lib/declarations/Platform.d.ts +50 -0
  116. package/dist/types/lib/declarations/Types.d.ts +173 -0
  117. package/dist/types/lib/generator/CText.d.ts +14 -0
  118. package/dist/types/lib/generator/Generator.d.ts +136 -0
  119. package/dist/types/lib/generator/Preprocessor.d.ts +60 -0
  120. package/dist/types/lib/generator/TypeScriptTypes.d.ts +35 -0
  121. package/dist/types/lib/library/NativeCallback.d.ts +44 -0
  122. package/dist/types/lib/library/NativeLibraryHandle.d.ts +268 -0
  123. package/dist/types/lib/library/Resolve.d.ts +49 -0
  124. package/dist/types/lib/thread/NativeThreads.d.ts +80 -0
  125. package/dist/types/lib/thread/NativeWorker.d.ts +6 -0
  126. package/dist/types/lib/thread/NativeWorkerCode.d.ts +5 -0
  127. package/dist/types/lib/thread/PackageRequire.d.ts +6 -0
  128. package/dist/types/lib/thread/ThreadProtocol.d.ts +77 -0
  129. package/package.json +85 -4
@@ -0,0 +1,346 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.NativeLibrary = void 0;
16
+ exports.buildNativeLibraryOptions = buildNativeLibraryOptions;
17
+ const node_path_1 = __importDefault(require("node:path"));
18
+ const core_1 = require("@lakutata/core");
19
+ const di_1 = require("@lakutata/core/decorator/di");
20
+ const Library_js_1 = require("../decorators/Library.js");
21
+ const Native_js_1 = require("../decorators/Native.js");
22
+ const NativeDeclarationException_js_1 = require("../exceptions/NativeDeclarationException.js");
23
+ const NativeLibraryClosedException_js_1 = require("../exceptions/NativeLibraryClosedException.js");
24
+ const NativeLibraryHandle_js_1 = require("../lib/library/NativeLibraryHandle.js");
25
+ /**
26
+ * A native library: a component holding a library loaded with its C declarations (`@Library`), its functions on its
27
+ * properties (`@Native`), its variables (`@NativeVariable`). Write one subclass for each library and register it in the
28
+ * components of the application; it is loaded when it is created, and destroyed with the application: the asynchronous
29
+ * calls running are awaited, its callbacks released, the library unloaded.
30
+ *
31
+ * In a packaged application, the library is also looked for in the directory `native` of the resources (put it there
32
+ * with `lakutata.resources` of the package.json). The exceptions thrown by its persistent callbacks are its `error`
33
+ * events (written to the log of the application when nothing listens to them).
34
+ * @example
35
+ * ```typescript
36
+ * import {Application} from 'lakutata'
37
+ * import {buildNativeLibraryOptions, Library, Native, NativeLibrary, type Out, type Pointer} from '@lakutata/ffi'
38
+ *
39
+ * @Library({
40
+ * names: {darwin: 'libsqlite3.dylib', linux: 'libsqlite3.so.0', win32: 'winsqlite3.dll'},
41
+ * declarations: `
42
+ * typedef struct sqlite3 sqlite3;
43
+ * #define SQLITE_OK 0
44
+ * `
45
+ * })
46
+ * export class SQLite extends NativeLibrary {
47
+ * @Native('const char *sqlite3_libversion(void)')
48
+ * public readonly libversion: () => string
49
+ *
50
+ * @Native('int sqlite3_open(const char *filename, _Out_ sqlite3 **db)')
51
+ * public readonly open: (filename: string, db: Out<Pointer>) => number
52
+ *
53
+ * @Native('int sqlite3_close(sqlite3 *db)')
54
+ * public readonly close: (db: Pointer) => number
55
+ * }
56
+ *
57
+ * Application
58
+ * .run(() => ({
59
+ * id: 'store.app',
60
+ * name: 'Store',
61
+ * components: {
62
+ * sqlite: buildNativeLibraryOptions(SQLite)
63
+ * }
64
+ * }))
65
+ * .onLaunched(async (app: Application): Promise<void> => {
66
+ * const sqlite: SQLite = await app.getObject('sqlite')
67
+ * console.log(sqlite.libversion())
68
+ * })
69
+ * ```
70
+ */
71
+ class NativeLibrary extends core_1.Component {
72
+ #handle;
73
+ /**
74
+ * Load the library and bind its functions and variables to their properties.
75
+ * @protected
76
+ */
77
+ async init() {
78
+ const library = (0, Library_js_1.libraryOptionsOf)(this.constructor);
79
+ if (!library)
80
+ throw new NativeDeclarationException_js_1.NativeDeclarationException(`${this.constructor.name} has no @Library: give the names of its library and its declarations`);
81
+ const resources = (0, core_1.isPackaged)() ? (0, core_1.resourcesPath)() : undefined;
82
+ this.#handle = new NativeLibraryHandle_js_1.NativeLibraryHandle(library.names, library.declarations ?? '', {
83
+ path: this.path,
84
+ search: [...this.search ?? [], ...library.search ?? []],
85
+ packaged: resources ? node_path_1.default.join(resources, 'native') : undefined,
86
+ keepLoaded: this.keepLoaded,
87
+ crt: library.crt,
88
+ threads: this.threads ?? library.threads ?? 0,
89
+ onCallbackError: (error) => this.#callbackError(error)
90
+ });
91
+ //The threads have loaded the library (a thread that could not fails the creation)
92
+ try {
93
+ await this.#handle.ready;
94
+ }
95
+ catch (error) {
96
+ await this.#handle.close(0);
97
+ this.#handle = undefined;
98
+ throw error;
99
+ }
100
+ for (const [key, member] of (0, Native_js_1.nativeMembersOf)(Object.getPrototypeOf(this)))
101
+ this.#bindMember(key, member);
102
+ }
103
+ /**
104
+ * Close the library: the asynchronous calls running awaited, the callbacks released, the library unloaded (kept,
105
+ * with its callbacks and its memory, when calls still run after `drainTimeout`); its properties throw from then on.
106
+ * @protected
107
+ */
108
+ async destroy() {
109
+ const handle = this.#handle;
110
+ if (!handle)
111
+ return;
112
+ for (const [key, member] of (0, Native_js_1.nativeMembersOf)(Object.getPrototypeOf(this)))
113
+ this.#closeMember(key, member, handle.file);
114
+ await handle.close(this.drainTimeout ?? 10000);
115
+ }
116
+ /**
117
+ * The file the library was loaded from.
118
+ */
119
+ get file() {
120
+ return this.#library().file;
121
+ }
122
+ /**
123
+ * The asynchronous calls running.
124
+ */
125
+ get pending() {
126
+ return this.#library().pending;
127
+ }
128
+ /**
129
+ * The worker threads of the library (0: its asynchronous calls run in the thread pool of the runtime).
130
+ */
131
+ get threadCount() {
132
+ return this.#library().threads;
133
+ }
134
+ /**
135
+ * The constants of the declarations: the values of the enumerations, of the static constants and of the macros
136
+ * whose value is an integer.
137
+ */
138
+ get constants() {
139
+ return this.#library().constants;
140
+ }
141
+ /**
142
+ * A function of the library bound from its prototype, besides the ones of the properties.
143
+ * @param prototype Its C prototype, with the types of the declarations.
144
+ * @param options Whether it is asynchronous, how its strings are freed, how its 64-bit integers are given.
145
+ * @returns The function.
146
+ */
147
+ func(prototype, options = {}) {
148
+ return this.#library().func(prototype, options);
149
+ }
150
+ /**
151
+ * A variable the library exports, besides the ones of the properties.
152
+ * @param declaration Its name in the declarations, or its declaration.
153
+ * @returns Its address, and the functions reading and writing its value.
154
+ */
155
+ variable(declaration) {
156
+ return this.#library().variable(declaration);
157
+ }
158
+ /**
159
+ * A persistent callback: a JS function the library can call at any time, released by `release()` or when the
160
+ * component is destroyed. Its exceptions are `error` events of the component.
161
+ * @param type The name of a pointer-to-function type of the declarations, or its prototype.
162
+ * @param callback The JS function.
163
+ * @returns The callback, whose `pointer` is given to the library.
164
+ */
165
+ callback(type, callback) {
166
+ return this.#library().callback(type, callback);
167
+ }
168
+ /**
169
+ * Read native memory as a type of the declarations: a value, or an array of values.
170
+ * @param pointer The address.
171
+ * @param type The type: `int`, `struct timeval`, `char *` (a string).
172
+ * @param count The number of values, for an array.
173
+ * @returns The value, or the array.
174
+ */
175
+ read(pointer, type, count) {
176
+ return this.#library().read(pointer, type, count);
177
+ }
178
+ /**
179
+ * Write a value to native memory as a type of the declarations.
180
+ * @param pointer The address.
181
+ * @param type The type.
182
+ * @param value The value.
183
+ */
184
+ write(pointer, type, value) {
185
+ this.#library().write(pointer, type, value);
186
+ }
187
+ /**
188
+ * The size of a type of the declarations, in bytes.
189
+ * @param type The type.
190
+ */
191
+ sizeOf(type) {
192
+ return this.#library().sizeOf(type);
193
+ }
194
+ /**
195
+ * The offset of a member of a struct of the declarations, in bytes.
196
+ * @param type The struct.
197
+ * @param member The member.
198
+ */
199
+ offsetOf(type, member) {
200
+ return this.#library().offsetOf(type, member);
201
+ }
202
+ /**
203
+ * Allocate native memory for values of a type of the declarations, which the library can keep; freed by `free()`,
204
+ * or when the component is destroyed.
205
+ * @param type The type.
206
+ * @param count The number of values.
207
+ * @returns Its address.
208
+ */
209
+ alloc(type, count = 1) {
210
+ return this.#library().alloc(type, count);
211
+ }
212
+ /**
213
+ * Free memory allocated by `alloc()`.
214
+ * @param pointer Its address.
215
+ */
216
+ free(pointer) {
217
+ this.#library().free(pointer);
218
+ }
219
+ /**
220
+ * The errno of the last call of this thread (on Windows, the one of the C library of `@Library`, ucrtbase.dll by
221
+ * default); with threads, the one of the thread of the last asynchronous call completed.
222
+ */
223
+ errno() {
224
+ return this.#library().errno();
225
+ }
226
+ /**
227
+ * The last error of the Windows API after the last call of this thread; with threads, the one of the thread of the
228
+ * last asynchronous call completed; undefined on the other systems.
229
+ */
230
+ windowsError() {
231
+ return this.#library().windowsError();
232
+ }
233
+ /**
234
+ * The library, once loaded
235
+ */
236
+ #library() {
237
+ if (!this.#handle)
238
+ throw new NativeLibraryClosedException_js_1.NativeLibraryClosedException(`The library of ${this.constructor.name} is not loaded`);
239
+ return this.#handle;
240
+ }
241
+ /**
242
+ * A function or a variable bound to its property
243
+ * @param key
244
+ * @param member
245
+ */
246
+ #bindMember(key, member) {
247
+ const handle = this.#handle;
248
+ const declaration = member.declaration ?? key;
249
+ const named = /^[A-Za-z_]\w*$/.test(declaration);
250
+ if (member.kind === 'function') {
251
+ const bound = named ? handle.function(declaration, member.options) : handle.func(declaration, member.options);
252
+ Object.defineProperty(this, key, { value: bound, writable: false, enumerable: true, configurable: true });
253
+ return;
254
+ }
255
+ const variable = handle.variable(declaration);
256
+ Object.defineProperty(this, key, {
257
+ get: () => variable.get(),
258
+ set: (value) => variable.set(value),
259
+ enumerable: true,
260
+ configurable: true
261
+ });
262
+ }
263
+ /**
264
+ * A property of a closed library: throwing (an asynchronous function rejecting)
265
+ * @param key
266
+ * @param member
267
+ * @param file
268
+ */
269
+ #closeMember(key, member, file) {
270
+ const closed = () => new NativeLibraryClosedException_js_1.NativeLibraryClosedException(`The library ${file} is closed: ${this.constructor.name}.${key} cannot be used`);
271
+ if (member.kind === 'function') {
272
+ const value = member.options.async ? () => Promise.reject(closed()) : () => {
273
+ throw closed();
274
+ };
275
+ Object.defineProperty(this, key, { value: value, writable: false, enumerable: true, configurable: true });
276
+ return;
277
+ }
278
+ const fail = () => {
279
+ throw closed();
280
+ };
281
+ Object.defineProperty(this, key, { get: fail, set: fail, enumerable: true, configurable: true });
282
+ }
283
+ /**
284
+ * An exception of a persistent callback: an error event, or the log of the application when nothing listens
285
+ * @param error
286
+ */
287
+ #callbackError(error) {
288
+ if (this.listenerCount('error')) {
289
+ this.emit('error', error);
290
+ return;
291
+ }
292
+ const message = `A callback of the native library ${this.#handle?.file ?? this.constructor.name} threw`;
293
+ this.getModule().getObject('log').then((log) => log.error(error, message), () => console.error(`${message}:`, error));
294
+ }
295
+ }
296
+ exports.NativeLibrary = NativeLibrary;
297
+ __decorate([
298
+ (0, di_1.Configurable)(core_1.DTO.String().optional()),
299
+ __metadata("design:type", String)
300
+ ], NativeLibrary.prototype, "path", void 0);
301
+ __decorate([
302
+ (0, di_1.Configurable)(core_1.DTO.Array().items(core_1.DTO.String()).optional()),
303
+ __metadata("design:type", Array)
304
+ ], NativeLibrary.prototype, "search", void 0);
305
+ __decorate([
306
+ (0, di_1.Configurable)(core_1.DTO.Boolean().optional()),
307
+ __metadata("design:type", Boolean)
308
+ ], NativeLibrary.prototype, "keepLoaded", void 0);
309
+ __decorate([
310
+ (0, di_1.Configurable)(core_1.DTO.Number().min(0).optional()),
311
+ __metadata("design:type", Number)
312
+ ], NativeLibrary.prototype, "drainTimeout", void 0);
313
+ __decorate([
314
+ (0, di_1.Configurable)(core_1.DTO.Number().integer().min(0).optional()),
315
+ __metadata("design:type", Number)
316
+ ], NativeLibrary.prototype, "threads", void 0);
317
+ /**
318
+ * Build the declaration of a library component, for the `components` of an application.
319
+ * @param library The `NativeLibrary` subclass of the library.
320
+ * @param options Where it is found (a file, directories searched first), whether it stays loaded, how long its
321
+ * destruction waits for its asynchronous calls.
322
+ * @returns The component declaration.
323
+ * @example
324
+ * ```typescript
325
+ * import {Application} from 'lakutata'
326
+ * import {buildNativeLibraryOptions, Library, Native, NativeLibrary} from '@lakutata/ffi'
327
+ *
328
+ * @Library({names: 'vendor'})
329
+ * class Vendor extends NativeLibrary {
330
+ * @Native('int vendor_version(void)')
331
+ * public readonly version: () => number
332
+ * }
333
+ *
334
+ * Application.run(() => ({
335
+ * id: 'devices.app',
336
+ * name: 'Devices',
337
+ * components: {
338
+ * //The library shipped with the application: an alias, or a path relative to the working directory
339
+ * vendor: buildNativeLibraryOptions(Vendor, {search: ['@data/native']})
340
+ * }
341
+ * }))
342
+ * ```
343
+ */
344
+ function buildNativeLibraryOptions(library, options = {}) {
345
+ return { class: library, ...options };
346
+ }
@@ -0,0 +1,61 @@
1
+ import type { LibraryNames } from '../lib/library/Resolve.js';
2
+ /**
3
+ * What a library is: its file names, where it is looked for, its C declarations
4
+ */
5
+ export interface LibraryOptions {
6
+ /**
7
+ * Its file names: one (`sqlite3`, completed as each platform names libraries: `libsqlite3.dylib`, `libsqlite3.so`,
8
+ * `sqlite3.dll`), or one by platform (`{darwin: 'libsqlite3.dylib', linux: 'libsqlite3.so.0', win32:
9
+ * 'winsqlite3.dll'}`, `default` for the others); `c` for the C library, `m` for its mathematical functions.
10
+ */
11
+ names: LibraryNames;
12
+ /**
13
+ * The directories it is looked for in before the ones of the system, in their order (aliases of the application
14
+ * allowed). The ones of the configuration come first.
15
+ */
16
+ search?: string[];
17
+ /**
18
+ * Its C declarations, as its headers write them: the types its functions use, its functions, its variables, its
19
+ * constants (enumerations, #define of integers).
20
+ */
21
+ declarations?: string;
22
+ /**
23
+ * On Windows, the C library its functions use, whose errno `errno()` reads.
24
+ * @default 'ucrtbase.dll'
25
+ */
26
+ crt?: string;
27
+ /**
28
+ * The worker threads that run its asynchronous functions (the configuration can give another number): 0 for the
29
+ * thread pool of the runtime; 1 runs them one after the other, for a library that is not thread-safe.
30
+ * @default 0
31
+ */
32
+ threads?: number;
33
+ }
34
+ /**
35
+ * Declare a native library on a `NativeLibrary` subclass: its file names, the directories it is looked for in, its C
36
+ * declarations. Its functions are declared on its properties by `@Native`, its variables by `@NativeVariable`.
37
+ * @param options Its names, its search directories, its declarations.
38
+ * @returns The class decorator.
39
+ * @example
40
+ * ```typescript
41
+ * import {Library, Native, NativeLibrary} from '@lakutata/ffi'
42
+ *
43
+ * @Library({
44
+ * names: {darwin: 'libz.dylib', linux: 'libz.so.1', win32: 'zlib1.dll'},
45
+ * declarations: 'typedef unsigned long uLong;'
46
+ * })
47
+ * export class Zlib extends NativeLibrary {
48
+ * @Native('const char *zlibVersion(void)')
49
+ * public readonly zlibVersion: () => string
50
+ *
51
+ * @Native('uLong crc32(uLong crc, const unsigned char *buffer, unsigned int length)')
52
+ * public readonly crc32: (crc: bigint | number, buffer: Buffer, length: number) => bigint
53
+ * }
54
+ * ```
55
+ */
56
+ export declare function Library(options: LibraryOptions): (target: Function) => void;
57
+ /**
58
+ * The library declared on a class or on the nearest of its parent classes
59
+ * @param target
60
+ */
61
+ export declare function libraryOptionsOf(target: Function): LibraryOptions | undefined;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Library = Library;
4
+ exports.libraryOptionsOf = libraryOptionsOf;
5
+ const libraries = new WeakMap();
6
+ /**
7
+ * Declare a native library on a `NativeLibrary` subclass: its file names, the directories it is looked for in, its C
8
+ * declarations. Its functions are declared on its properties by `@Native`, its variables by `@NativeVariable`.
9
+ * @param options Its names, its search directories, its declarations.
10
+ * @returns The class decorator.
11
+ * @example
12
+ * ```typescript
13
+ * import {Library, Native, NativeLibrary} from '@lakutata/ffi'
14
+ *
15
+ * @Library({
16
+ * names: {darwin: 'libz.dylib', linux: 'libz.so.1', win32: 'zlib1.dll'},
17
+ * declarations: 'typedef unsigned long uLong;'
18
+ * })
19
+ * export class Zlib extends NativeLibrary {
20
+ * @Native('const char *zlibVersion(void)')
21
+ * public readonly zlibVersion: () => string
22
+ *
23
+ * @Native('uLong crc32(uLong crc, const unsigned char *buffer, unsigned int length)')
24
+ * public readonly crc32: (crc: bigint | number, buffer: Buffer, length: number) => bigint
25
+ * }
26
+ * ```
27
+ */
28
+ function Library(options) {
29
+ return (target) => {
30
+ libraries.set(target, options);
31
+ };
32
+ }
33
+ /**
34
+ * The library declared on a class or on the nearest of its parent classes
35
+ * @param target
36
+ */
37
+ function libraryOptionsOf(target) {
38
+ for (let current = target; current && current !== Function.prototype; current = Object.getPrototypeOf(current)) {
39
+ const options = libraries.get(current);
40
+ if (options)
41
+ return options;
42
+ }
43
+ return undefined;
44
+ }
@@ -0,0 +1,69 @@
1
+ import type { NativeFunctionOptions } from '../lib/library/NativeLibraryHandle.js';
2
+ /**
3
+ * A member of a library class: a function, or a variable
4
+ */
5
+ export type NativeMember = {
6
+ readonly kind: 'function';
7
+ readonly declaration?: string;
8
+ readonly options: NativeFunctionOptions;
9
+ } | {
10
+ readonly kind: 'variable';
11
+ readonly declaration?: string;
12
+ };
13
+ /**
14
+ * Declare a function of the library on a property of a `NativeLibrary` subclass: the property gets the function once
15
+ * the component is created (the function of koffi itself when nothing is converted), and a function throwing once it
16
+ * is destroyed. The TypeScript type of the property is the one of the function.
17
+ * @param declaration Its C prototype (`int sqlite3_open(const char *filename, _Out_ sqlite3 **db)`), or the name of a
18
+ * function of the declarations of the library; by default the function of the declarations named as the property.
19
+ * @param options Whether it runs in a thread of the pool (returning a promise), the function freeing the strings it
20
+ * gives, its 64-bit integers as numbers.
21
+ * @returns The property decorator.
22
+ * @example
23
+ * ```typescript
24
+ * import {Library, Native, NativeLibrary, type Out, type Pointer} from '@lakutata/ffi'
25
+ *
26
+ * @Library({
27
+ * names: {darwin: 'libsqlite3.dylib', linux: 'libsqlite3.so.0', win32: 'winsqlite3.dll'},
28
+ * declarations: `
29
+ * typedef struct sqlite3 sqlite3;
30
+ * int sqlite3_close(sqlite3 *db);
31
+ * `
32
+ * })
33
+ * export class SQLite extends NativeLibrary {
34
+ * @Native('int sqlite3_open(const char *filename, _Out_ sqlite3 **db)')
35
+ * public readonly open: (filename: string, db: Out<Pointer>) => number
36
+ *
37
+ * //The function of the declarations named as the property
38
+ * @Native()
39
+ * public readonly sqlite3_close: (db: Pointer) => number
40
+ *
41
+ * @Native('int sqlite3_exec(sqlite3 *db, const char *sql, void *callback, void *context, _Out_ char **error)', {async: true, free: 'sqlite3_free'})
42
+ * public readonly exec: (db: Pointer, sql: string, callback: null, context: null, error: Out<string>) => Promise<number>
43
+ * }
44
+ * ```
45
+ */
46
+ export declare function Native(declaration?: string, options?: NativeFunctionOptions): (target: object, key: string | symbol) => void;
47
+ /**
48
+ * Declare a variable the library exports on a property of a `NativeLibrary` subclass: reading the property reads the
49
+ * variable, writing it writes the variable (refused for a const one).
50
+ * @param declaration Its declaration (`extern const char sqlite3_version[]`), or the name of a variable of the
51
+ * declarations of the library; by default the variable of the declarations named as the property.
52
+ * @returns The property decorator.
53
+ * @example
54
+ * ```typescript
55
+ * import {Library, NativeLibrary, NativeVariable} from '@lakutata/ffi'
56
+ *
57
+ * @Library({names: {darwin: 'libsqlite3.dylib', linux: 'libsqlite3.so.0', win32: 'winsqlite3.dll'}})
58
+ * export class SQLiteVersion extends NativeLibrary {
59
+ * @NativeVariable('extern const char sqlite3_version[]')
60
+ * public readonly version: string
61
+ * }
62
+ * ```
63
+ */
64
+ export declare function NativeVariable(declaration?: string): (target: object, key: string | symbol) => void;
65
+ /**
66
+ * The native members of a class and of its parent classes (a subclass replacing a member of its parent)
67
+ * @param prototype
68
+ */
69
+ export declare function nativeMembersOf(prototype: object): Map<string, NativeMember>;
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Native = Native;
4
+ exports.NativeVariable = NativeVariable;
5
+ exports.nativeMembersOf = nativeMembersOf;
6
+ const members = new WeakMap();
7
+ /**
8
+ * Record a member on the prototype of a class
9
+ * @param target
10
+ * @param key
11
+ * @param member
12
+ */
13
+ function record(target, key, member) {
14
+ if (typeof key !== 'string')
15
+ throw new TypeError('A native function or variable is declared on a property with a string name');
16
+ let own = members.get(target);
17
+ if (!own)
18
+ members.set(target, own = new Map());
19
+ own.set(key, member);
20
+ }
21
+ /**
22
+ * Declare a function of the library on a property of a `NativeLibrary` subclass: the property gets the function once
23
+ * the component is created (the function of koffi itself when nothing is converted), and a function throwing once it
24
+ * is destroyed. The TypeScript type of the property is the one of the function.
25
+ * @param declaration Its C prototype (`int sqlite3_open(const char *filename, _Out_ sqlite3 **db)`), or the name of a
26
+ * function of the declarations of the library; by default the function of the declarations named as the property.
27
+ * @param options Whether it runs in a thread of the pool (returning a promise), the function freeing the strings it
28
+ * gives, its 64-bit integers as numbers.
29
+ * @returns The property decorator.
30
+ * @example
31
+ * ```typescript
32
+ * import {Library, Native, NativeLibrary, type Out, type Pointer} from '@lakutata/ffi'
33
+ *
34
+ * @Library({
35
+ * names: {darwin: 'libsqlite3.dylib', linux: 'libsqlite3.so.0', win32: 'winsqlite3.dll'},
36
+ * declarations: `
37
+ * typedef struct sqlite3 sqlite3;
38
+ * int sqlite3_close(sqlite3 *db);
39
+ * `
40
+ * })
41
+ * export class SQLite extends NativeLibrary {
42
+ * @Native('int sqlite3_open(const char *filename, _Out_ sqlite3 **db)')
43
+ * public readonly open: (filename: string, db: Out<Pointer>) => number
44
+ *
45
+ * //The function of the declarations named as the property
46
+ * @Native()
47
+ * public readonly sqlite3_close: (db: Pointer) => number
48
+ *
49
+ * @Native('int sqlite3_exec(sqlite3 *db, const char *sql, void *callback, void *context, _Out_ char **error)', {async: true, free: 'sqlite3_free'})
50
+ * public readonly exec: (db: Pointer, sql: string, callback: null, context: null, error: Out<string>) => Promise<number>
51
+ * }
52
+ * ```
53
+ */
54
+ function Native(declaration, options = {}) {
55
+ return (target, key) => record(target, key, { kind: 'function', declaration: declaration, options: options });
56
+ }
57
+ /**
58
+ * Declare a variable the library exports on a property of a `NativeLibrary` subclass: reading the property reads the
59
+ * variable, writing it writes the variable (refused for a const one).
60
+ * @param declaration Its declaration (`extern const char sqlite3_version[]`), or the name of a variable of the
61
+ * declarations of the library; by default the variable of the declarations named as the property.
62
+ * @returns The property decorator.
63
+ * @example
64
+ * ```typescript
65
+ * import {Library, NativeLibrary, NativeVariable} from '@lakutata/ffi'
66
+ *
67
+ * @Library({names: {darwin: 'libsqlite3.dylib', linux: 'libsqlite3.so.0', win32: 'winsqlite3.dll'}})
68
+ * export class SQLiteVersion extends NativeLibrary {
69
+ * @NativeVariable('extern const char sqlite3_version[]')
70
+ * public readonly version: string
71
+ * }
72
+ * ```
73
+ */
74
+ function NativeVariable(declaration) {
75
+ return (target, key) => record(target, key, { kind: 'variable', declaration: declaration });
76
+ }
77
+ /**
78
+ * The native members of a class and of its parent classes (a subclass replacing a member of its parent)
79
+ * @param prototype
80
+ */
81
+ function nativeMembersOf(prototype) {
82
+ const chain = [];
83
+ for (let current = prototype; current && current !== Object.prototype; current = Object.getPrototypeOf(current))
84
+ chain.unshift(current);
85
+ const all = new Map();
86
+ for (const current of chain)
87
+ for (const [key, member] of members.get(current) ?? [])
88
+ all.set(key, member);
89
+ return all;
90
+ }
@@ -0,0 +1,12 @@
1
+ import { Exception } from '@lakutata/core';
2
+ /**
3
+ * Thrown when C declarations or a function prototype cannot be read: its message gives the line and the column, what
4
+ * was found and what was expected (a type not declared, a construct not supported such as a macro or `long double`).
5
+ * Its `errno` is `'E_NATIVE_DECLARATION'`.
6
+ */
7
+ export declare class NativeDeclarationException extends Exception {
8
+ /**
9
+ * `'E_NATIVE_DECLARATION'`.
10
+ */
11
+ errno: string | number;
12
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NativeDeclarationException = void 0;
4
+ const core_1 = require("@lakutata/core");
5
+ /**
6
+ * Thrown when C declarations or a function prototype cannot be read: its message gives the line and the column, what
7
+ * was found and what was expected (a type not declared, a construct not supported such as a macro or `long double`).
8
+ * Its `errno` is `'E_NATIVE_DECLARATION'`.
9
+ */
10
+ class NativeDeclarationException extends core_1.Exception {
11
+ constructor() {
12
+ super(...arguments);
13
+ /**
14
+ * `'E_NATIVE_DECLARATION'`.
15
+ */
16
+ this.errno = 'E_NATIVE_DECLARATION';
17
+ }
18
+ }
19
+ exports.NativeDeclarationException = NativeDeclarationException;
@@ -0,0 +1,12 @@
1
+ import { Exception } from '@lakutata/core';
2
+ /**
3
+ * Thrown when a function, a variable or a callback of a library is used once the library is closed (its component
4
+ * destroyed, or `close()` called): calling a function of an unloaded library would end the process. Its `errno` is
5
+ * `'E_NATIVE_LIBRARY_CLOSED'`.
6
+ */
7
+ export declare class NativeLibraryClosedException extends Exception {
8
+ /**
9
+ * `'E_NATIVE_LIBRARY_CLOSED'`.
10
+ */
11
+ errno: string | number;
12
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NativeLibraryClosedException = void 0;
4
+ const core_1 = require("@lakutata/core");
5
+ /**
6
+ * Thrown when a function, a variable or a callback of a library is used once the library is closed (its component
7
+ * destroyed, or `close()` called): calling a function of an unloaded library would end the process. Its `errno` is
8
+ * `'E_NATIVE_LIBRARY_CLOSED'`.
9
+ */
10
+ class NativeLibraryClosedException extends core_1.Exception {
11
+ constructor() {
12
+ super(...arguments);
13
+ /**
14
+ * `'E_NATIVE_LIBRARY_CLOSED'`.
15
+ */
16
+ this.errno = 'E_NATIVE_LIBRARY_CLOSED';
17
+ }
18
+ }
19
+ exports.NativeLibraryClosedException = NativeLibraryClosedException;