koffi 2.4.1 → 2.4.2

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 (31) hide show
  1. package/CHANGELOG.md +12 -2
  2. package/build/2.4.2/koffi_darwin_arm64/koffi.node +0 -0
  3. package/build/{2.4.1 → 2.4.2}/koffi_darwin_x64/koffi.node +0 -0
  4. package/build/{2.4.1 → 2.4.2}/koffi_freebsd_arm64/koffi.node +0 -0
  5. package/build/2.4.2/koffi_freebsd_ia32/koffi.node +0 -0
  6. package/build/{2.4.1 → 2.4.2}/koffi_freebsd_x64/koffi.node +0 -0
  7. package/build/{2.4.1 → 2.4.2}/koffi_linux_arm32hf/koffi.node +0 -0
  8. package/build/{2.4.1 → 2.4.2}/koffi_linux_arm64/koffi.node +0 -0
  9. package/build/{2.4.1 → 2.4.2}/koffi_linux_ia32/koffi.node +0 -0
  10. package/build/{2.4.1 → 2.4.2}/koffi_linux_riscv64hf64/koffi.node +0 -0
  11. package/build/{2.4.1 → 2.4.2}/koffi_linux_x64/koffi.node +0 -0
  12. package/build/2.4.2/koffi_openbsd_ia32/koffi.node +0 -0
  13. package/build/{2.4.1 → 2.4.2}/koffi_openbsd_x64/koffi.node +0 -0
  14. package/build/2.4.2/koffi_win32_arm64/koffi.node +0 -0
  15. package/build/{2.4.1 → 2.4.2}/koffi_win32_ia32/koffi.node +0 -0
  16. package/build/{2.4.1 → 2.4.2}/koffi_win32_x64/koffi.node +0 -0
  17. package/doc/functions.md +73 -4
  18. package/package.json +2 -2
  19. package/src/koffi/src/ffi.cc +4 -9
  20. package/src/koffi/src/parser.cc +1 -1
  21. package/src/koffi/src/util.cc +4 -0
  22. package/build/2.4.1/koffi_darwin_arm64/koffi.node +0 -0
  23. package/build/2.4.1/koffi_freebsd_ia32/koffi.node +0 -0
  24. package/build/2.4.1/koffi_openbsd_ia32/koffi.node +0 -0
  25. package/build/2.4.1/koffi_win32_arm64/koffi.node +0 -0
  26. /package/build/{2.4.1 → 2.4.2}/koffi_win32_arm64/koffi.exp +0 -0
  27. /package/build/{2.4.1 → 2.4.2}/koffi_win32_arm64/koffi.lib +0 -0
  28. /package/build/{2.4.1 → 2.4.2}/koffi_win32_ia32/koffi.exp +0 -0
  29. /package/build/{2.4.1 → 2.4.2}/koffi_win32_ia32/koffi.lib +0 -0
  30. /package/build/{2.4.1 → 2.4.2}/koffi_win32_x64/koffi.exp +0 -0
  31. /package/build/{2.4.1 → 2.4.2}/koffi_win32_x64/koffi.lib +0 -0
package/CHANGELOG.md CHANGED
@@ -4,12 +4,22 @@
4
4
 
5
5
  ### Koffi 2.4
6
6
 
7
+ #### Koffi 2.4.2
8
+
9
+ **Main changes:**
10
+
11
+ - Support calling variadic function pointers
12
+
13
+ **Other changes:**
14
+
15
+ - Add documentation for function pointers
16
+
7
17
  #### Koffi 2.4.1
8
18
 
9
19
  **Main changes:**
10
20
 
11
- - Support decoding pointers to callable functions
12
- - Support calling function pointers with [koffi.call()]
21
+ - Support [decoding function pointers](functions.md#decode-pointer-to-function) to callable functions
22
+ - Support calling function pointers with [koffi.call()](functions.md#call-pointer-directly)
13
23
  - Deprecate `koffi.callback` in favor of `koffi.proto`
14
24
 
15
25
  **Other changes:**
package/doc/functions.md CHANGED
@@ -1,4 +1,4 @@
1
- # Native functions
1
+ # Function calls
2
2
 
3
3
  ## Loading libraries
4
4
 
@@ -89,7 +89,7 @@ const MessageBoxA_1 = lib.stdcall('MessageBoxA', 'int', ['void *', 'str', 'str',
89
89
  const MessageBoxA_2 = lib.func('int __stdcall MessageBoxA(void *hwnd, str text, str caption, uint type)');
90
90
  ```
91
91
 
92
- ## Function calls
92
+ ## Call types
93
93
 
94
94
  ### Synchronous calls
95
95
 
@@ -137,8 +137,77 @@ You can easily convert this callback-style async function to a promise-based ver
137
137
 
138
138
  Variadic functions cannot be called asynchronously.
139
139
 
140
- ## Thread safety
141
-
140
+ ```{note}
142
141
  Asynchronous functions run on worker threads. You need to deal with thread safety issues if you share data between threads.
143
142
 
144
143
  Callbacks must be called from the main thread, or more precisely from the same thread as the V8 intepreter. Calling a callback from another thread is undefined behavior, and will likely lead to a crash or a big mess. You've been warned!
144
+ ```
145
+
146
+ ## Function pointers
147
+
148
+ *New in Koffi 2.4*
149
+
150
+ You can call a function pointer in two ways:
151
+
152
+ - Directly call the function pointer with `koffi.call(ptr, type, ...)`
153
+ - Decode the function pointer to an actual function with `koffi.decode(ptr, type)`
154
+
155
+ The example below shows how to call an `int (*)(int, int)` C function pointer both ways, based on the following native C library:
156
+
157
+ ```c
158
+ typedef int BinaryIntFunc(int a, int b);
159
+
160
+ static int AddInt(int a, int b) { return a + b; }
161
+ static int SubstractInt(int a, int b) { return a - b; }
162
+
163
+ BinaryIntFunc *GetBinaryIntFunction(const char *type)
164
+ {
165
+ if (!strcmp(type, "add")) {
166
+ return AddInt;
167
+ } else if (!strcmp(type, "substract")) {
168
+ return SubstractInt;
169
+ } else {
170
+ return NULL;
171
+ }
172
+ }
173
+ ```
174
+
175
+ ### Call pointer directly
176
+
177
+ Use `koffi.call(ptr, type, ...)` to call a function pointer. The first two arguments are the pointer itself and the type of the function you are trying to call (declared with `koffi.proto()` as shown below), and the remaining arguments are used for the call.
178
+
179
+ ```js
180
+ // Declare function type
181
+ const BinaryIntFunc = koffi.proto('int BinaryIntFunc(int a, int b)');
182
+
183
+ const GetBinaryIntFunction = lib.func('BinaryIntFunc *GetBinaryIntFunction(const char *name)');
184
+
185
+ const add_ptr = GetBinaryIntFunction('add');
186
+ const substract_ptr = GetBinaryIntFunction('substract');
187
+
188
+ let sum = koffi.call(add_ptr, BinaryIntFunc, 4, 5);
189
+ let delta = koffi.call(substract_ptr, BinaryIntFunc, 100, 58);
190
+
191
+ console.log(sum, delta); // Prints 9 and 42
192
+ ```
193
+
194
+ ### Decode pointer to function
195
+
196
+ Use `koffi.decode(ptr, type)` to get back a JS function, which you can then use like any other Koffi function.
197
+
198
+ This method also allows you to perform an [asynchronous call](#asynchronous-calls) with the async member of the decoded function.
199
+
200
+ ```js
201
+ // Declare function type
202
+ const BinaryIntFunc = koffi.proto('int BinaryIntFunc(int a, int b)');
203
+
204
+ const GetBinaryIntFunction = lib.func('BinaryIntFunc *GetBinaryIntFunction(const char *name)');
205
+
206
+ const add = koffi.decode(GetBinaryIntFunction('add'), BinaryIntFunc);
207
+ const substract = koffi.decode(GetBinaryIntFunction('substract'), BinaryIntFunc);
208
+
209
+ let sum = add(4, 5);
210
+ let delta = substract(100, 58);
211
+
212
+ console.log(sum, delta); // Prints 9 and 42
213
+ ```
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.4.1",
4
- "stable": "2.4.1",
3
+ "version": "2.4.2",
4
+ "stable": "2.4.2",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
7
7
  "foreign",
@@ -895,7 +895,7 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
895
895
  if (!param.type)
896
896
  return false;
897
897
  if (!CanPassType(param.type, param.directions)) {
898
- ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
898
+ ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
899
899
  return false;
900
900
  }
901
901
  if (func->parameters.len >= MaxParameters) {
@@ -942,11 +942,6 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
942
942
  return env.Null();
943
943
  }
944
944
 
945
- if (func->variadic) {
946
- LogError("Variadic callbacks are not supported");
947
- return env.Null();
948
- }
949
-
950
945
  if (!AnalyseFunction(env, instance, func))
951
946
  return env.Null();
952
947
 
@@ -1310,7 +1305,7 @@ static Napi::Value TranslateVariadicCall(const FunctionInfo *func, void *native,
1310
1305
  if (RG_UNLIKELY(!param.type))
1311
1306
  return env.Null();
1312
1307
  if (RG_UNLIKELY(!CanPassType(param.type, param.directions))) {
1313
- ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
1308
+ ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
1314
1309
  return env.Null();
1315
1310
  }
1316
1311
  if (RG_UNLIKELY(copy.parameters.len >= MaxParameters)) {
@@ -2084,9 +2079,9 @@ static Napi::Value CallPointerSync(const Napi::CallbackInfo &info)
2084
2079
  }
2085
2080
 
2086
2081
  const FunctionInfo *proto = type->ref.proto;
2087
- RG_ASSERT(!proto->variadic);
2088
2082
 
2089
- return TranslateNormalCall(proto, ptr, info);
2083
+ return proto->variadic ? TranslateVariadicCall(proto, ptr, info)
2084
+ : TranslateNormalCall(proto, ptr, info);
2090
2085
  }
2091
2086
 
2092
2087
  extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
@@ -75,7 +75,7 @@ bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
75
75
  param.type = ParseType();
76
76
 
77
77
  if (!CanPassType(param.type, param.directions)) {
78
- MarkError("Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
78
+ MarkError("Type %1 cannot be used as a parameter", param.type->name);
79
79
  return false;
80
80
  }
81
81
  if (out_func->parameters.len >= MaxParameters) {
@@ -371,6 +371,8 @@ bool CanPassType(const TypeInfo *type, int directions)
371
371
  return false;
372
372
  if (type->primitive == PrimitiveKind::Prototype)
373
373
  return false;
374
+ if (type->primitive == PrimitiveKind::Callback && type->ref.proto->variadic)
375
+ return false;
374
376
 
375
377
  return true;
376
378
  }
@@ -394,6 +396,8 @@ bool CanStoreType(const TypeInfo *type)
394
396
  return false;
395
397
  if (type->primitive == PrimitiveKind::Prototype)
396
398
  return false;
399
+ if (type->primitive == PrimitiveKind::Callback && type->ref.proto->variadic)
400
+ return false;
397
401
 
398
402
  return true;
399
403
  }