koffi 1.3.12 → 2.1.0-beta.1

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 (104) hide show
  1. package/CMakeLists.txt +8 -10
  2. package/ChangeLog.md +48 -16
  3. package/README.md +6 -0
  4. package/benchmark/atoi_koffi.js +12 -8
  5. package/benchmark/atoi_napi.js +12 -8
  6. package/benchmark/atoi_node_ffi.js +11 -10
  7. package/benchmark/raylib_cc.cc +12 -9
  8. package/benchmark/raylib_koffi.js +15 -13
  9. package/benchmark/raylib_node_ffi.js +15 -13
  10. package/benchmark/raylib_node_raylib.js +14 -11
  11. package/build/qemu/2.1.0-beta.1/koffi_darwin_arm64.tar.gz +0 -0
  12. package/build/qemu/2.1.0-beta.1/koffi_darwin_x64.tar.gz +0 -0
  13. package/build/qemu/2.1.0-beta.1/koffi_freebsd_arm64.tar.gz +0 -0
  14. package/build/qemu/2.1.0-beta.1/koffi_freebsd_ia32.tar.gz +0 -0
  15. package/build/qemu/2.1.0-beta.1/koffi_freebsd_x64.tar.gz +0 -0
  16. package/build/qemu/2.1.0-beta.1/koffi_linux_arm32hf.tar.gz +0 -0
  17. package/build/qemu/2.1.0-beta.1/koffi_linux_arm64.tar.gz +0 -0
  18. package/build/qemu/2.1.0-beta.1/koffi_linux_ia32.tar.gz +0 -0
  19. package/build/qemu/2.1.0-beta.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  20. package/build/qemu/2.1.0-beta.1/koffi_linux_x64.tar.gz +0 -0
  21. package/build/qemu/2.1.0-beta.1/koffi_openbsd_ia32.tar.gz +0 -0
  22. package/build/qemu/2.1.0-beta.1/koffi_openbsd_x64.tar.gz +0 -0
  23. package/build/qemu/2.1.0-beta.1/koffi_win32_arm64.tar.gz +0 -0
  24. package/build/qemu/2.1.0-beta.1/koffi_win32_ia32.tar.gz +0 -0
  25. package/build/qemu/2.1.0-beta.1/koffi_win32_x64.tar.gz +0 -0
  26. package/doc/changes.md +160 -1
  27. package/doc/conf.py +14 -1
  28. package/doc/contribute.md +0 -1
  29. package/doc/dist/doctrees/benchmarks.doctree +0 -0
  30. package/doc/dist/doctrees/changes.doctree +0 -0
  31. package/doc/dist/doctrees/environment.pickle +0 -0
  32. package/doc/dist/doctrees/functions.doctree +0 -0
  33. package/doc/dist/doctrees/index.doctree +0 -0
  34. package/doc/dist/doctrees/types.doctree +0 -0
  35. package/doc/dist/html/.buildinfo +1 -1
  36. package/doc/dist/html/_sources/benchmarks.md.txt +2 -2
  37. package/doc/dist/html/_sources/changes.md.txt +160 -1
  38. package/doc/dist/html/_sources/functions.md.txt +17 -13
  39. package/doc/dist/html/_sources/types.md.txt +87 -35
  40. package/doc/dist/html/benchmarks.html +7 -3
  41. package/doc/dist/html/changes.html +241 -14
  42. package/doc/dist/html/contribute.html +5 -1
  43. package/doc/dist/html/functions.html +30 -23
  44. package/doc/dist/html/genindex.html +5 -1
  45. package/doc/dist/html/index.html +13 -19
  46. package/doc/dist/html/memory.html +7 -3
  47. package/doc/dist/html/objects.inv +0 -0
  48. package/doc/dist/html/platforms.html +6 -2
  49. package/doc/dist/html/search.html +5 -1
  50. package/doc/dist/html/searchindex.js +1 -1
  51. package/doc/dist/html/start.html +5 -1
  52. package/doc/dist/html/types.html +104 -43
  53. package/doc/functions.md +139 -15
  54. package/doc/templates/badges.html +5 -0
  55. package/doc/types.md +108 -40
  56. package/package.json +2 -2
  57. package/qemu/qemu.js +1 -1
  58. package/qemu/registry/machines.json +5 -5
  59. package/qemu/registry/sha256sum.txt +16 -16
  60. package/src/abi_arm32.cc +91 -19
  61. package/src/abi_arm32_fwd.S +121 -57
  62. package/src/abi_arm64.cc +91 -19
  63. package/src/abi_arm64_fwd.S +96 -0
  64. package/src/abi_arm64_fwd.asm +128 -0
  65. package/src/abi_riscv64.cc +89 -19
  66. package/src/abi_riscv64_fwd.S +96 -0
  67. package/src/abi_x64_sysv.cc +94 -22
  68. package/src/abi_x64_sysv_fwd.S +96 -0
  69. package/src/abi_x64_win.cc +89 -19
  70. package/src/abi_x64_win_fwd.asm +128 -0
  71. package/src/abi_x86.cc +94 -19
  72. package/src/abi_x86_fwd.S +96 -0
  73. package/src/abi_x86_fwd.asm +128 -0
  74. package/src/call.cc +128 -78
  75. package/src/call.hh +17 -4
  76. package/src/ffi.cc +514 -145
  77. package/src/ffi.hh +30 -9
  78. package/src/index.js +4 -2
  79. package/src/parser.cc +19 -44
  80. package/src/util.cc +160 -27
  81. package/src/util.hh +7 -2
  82. package/test/async.js +1 -2
  83. package/test/callbacks.js +56 -11
  84. package/test/misc.c +50 -15
  85. package/test/raylib.js +2 -2
  86. package/test/sqlite.js +27 -19
  87. package/test/sync.js +71 -35
  88. package/vendor/libcc/libcc.cc +18 -5
  89. package/vendor/libcc/libcc.hh +70 -23
  90. package/build/qemu/1.3.12/koffi_darwin_arm64.tar.gz +0 -0
  91. package/build/qemu/1.3.12/koffi_darwin_x64.tar.gz +0 -0
  92. package/build/qemu/1.3.12/koffi_freebsd_arm64.tar.gz +0 -0
  93. package/build/qemu/1.3.12/koffi_freebsd_ia32.tar.gz +0 -0
  94. package/build/qemu/1.3.12/koffi_freebsd_x64.tar.gz +0 -0
  95. package/build/qemu/1.3.12/koffi_linux_arm32hf.tar.gz +0 -0
  96. package/build/qemu/1.3.12/koffi_linux_arm64.tar.gz +0 -0
  97. package/build/qemu/1.3.12/koffi_linux_ia32.tar.gz +0 -0
  98. package/build/qemu/1.3.12/koffi_linux_riscv64hf64.tar.gz +0 -0
  99. package/build/qemu/1.3.12/koffi_linux_x64.tar.gz +0 -0
  100. package/build/qemu/1.3.12/koffi_openbsd_ia32.tar.gz +0 -0
  101. package/build/qemu/1.3.12/koffi_openbsd_x64.tar.gz +0 -0
  102. package/build/qemu/1.3.12/koffi_win32_arm64.tar.gz +0 -0
  103. package/build/qemu/1.3.12/koffi_win32_ia32.tar.gz +0 -0
  104. package/build/qemu/1.3.12/koffi_win32_x64.tar.gz +0 -0
package/src/ffi.cc CHANGED
@@ -42,6 +42,7 @@ namespace RG {
42
42
 
43
43
  // Value does not matter, the tag system uses memory addresses
44
44
  const int TypeInfoMarker = 0xDEADBEEF;
45
+ const int CastMarker = 0xDEADBEEF;
45
46
 
46
47
  static bool ChangeMemorySize(const char *name, Napi::Value value, Size *out_size)
47
48
  {
@@ -199,8 +200,6 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
199
200
 
200
201
  type->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
201
202
 
202
- type->defn.Reset(obj, 1);
203
-
204
203
  type->primitive = PrimitiveKind::Record;
205
204
  type->align = 1;
206
205
 
@@ -211,20 +210,44 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
211
210
 
212
211
  std::string key = ((Napi::Value)keys[i]).As<Napi::String>();
213
212
  Napi::Value value = obj[key];
213
+ int16_t align = 0;
214
214
 
215
215
  member.name = DuplicateString(key.c_str(), &instance->str_alloc).ptr;
216
- member.type = ResolveType(instance, value);
216
+
217
+ if (value.IsArray()) {
218
+ Napi::Array array = value.As<Napi::Array>();
219
+
220
+ if (array.Length() != 2 || !((Napi::Value)array[0u]).IsNumber()) {
221
+ ThrowError<Napi::Error>(env, "Member specifier array must contain alignement value and type");
222
+ return env.Null();
223
+ }
224
+
225
+ int64_t align64 = ((Napi::Value)array[0u]).As<Napi::Number>().Int64Value();
226
+
227
+ if (align64 < 1 || align64 > 64) {
228
+ ThrowError<Napi::Error>(env, "Alignment value must be between 1 and 64");
229
+ return env.Null();
230
+ }
231
+
232
+ value = array[1u];
233
+ align = (int16_t)align64;
234
+ }
235
+
236
+ member.type = ResolveType(value);
217
237
  if (!member.type)
218
238
  return env.Null();
219
- if (member.type->primitive == PrimitiveKind::Void) {
220
- ThrowError<Napi::TypeError>(env, "Type Void cannot be used as a member");
239
+ if (!CanStoreType(member.type)) {
240
+ ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a member (maybe try %1 *)", member.type->name);
221
241
  return env.Null();
222
242
  }
223
243
 
224
- member.align = pad ? member.type->align : 1;
244
+ if (!align) {
245
+ align = pad ? member.type->align : 1;
246
+ }
247
+ member.offset = (int16_t)AlignLen(type->size, align);
225
248
 
226
- type->size = (int16_t)(AlignLen(type->size, member.align) + member.type->size);
227
- type->align = std::max(type->align, member.align);
249
+ type->size = (int16_t)(member.offset + member.type->size);
250
+ type->align = std::max(type->align, align);
228
251
 
229
252
  if (!members.TrySet(member.name).second) {
230
253
  ThrowError<Napi::Error>(env, "Duplicate member '%1' in struct '%2'", member.name, type->name);
@@ -242,7 +265,7 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
242
265
  type->size = (int16_t)AlignLen(type->size, type->align);
243
266
 
244
267
  // If the insert succeeds, we cannot fail anymore
245
- if (named && !instance->types_map.TrySet(type).second) {
268
+ if (named && !instance->types_map.TrySet(type->name, type).second) {
246
269
  ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
247
270
  return env.Null();
248
271
  }
@@ -264,45 +287,31 @@ static Napi::Value CreatePackedStructType(const Napi::CallbackInfo &info)
264
287
  return CreateStructType(info, false);
265
288
  }
266
289
 
267
- static Napi::Value CreateHandleType(const Napi::CallbackInfo &info)
290
+ static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
268
291
  {
269
292
  Napi::Env env = info.Env();
270
293
  InstanceData *instance = env.GetInstanceData<InstanceData>();
271
294
 
272
- if (info.Length() < 1) {
273
- ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
274
- return env.Null();
275
- }
276
- if (!info[0].IsString()) {
295
+ bool named = (info.Length() >= 1);
296
+
297
+ if (named && !info[0].IsString()) {
277
298
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
278
299
  return env.Null();
279
300
  }
280
301
 
302
+ std::string name = named ? info[0].As<Napi::String>() : std::string("<anonymous>");
303
+
281
304
  TypeInfo *type = instance->types.AppendDefault();
282
305
  RG_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
283
306
 
284
- std::string name = info[0].As<Napi::String>();
285
-
286
307
  type->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
287
308
 
288
- type->primitive = PrimitiveKind::Record;
289
- type->align = alignof(void *);
290
- type->size = RG_SIZE(void *);
291
-
292
- // Add single handle member
293
- {
294
- RecordMember member = {};
295
-
296
- member.name = "value";
297
- member.type = instance->types_map.FindValue("void *", nullptr);
298
- RG_ASSERT(member.type);
299
- member.align = type->align;
300
-
301
- type->members.Append(member);
302
- }
309
+ type->primitive = PrimitiveKind::Void;
310
+ type->size = 0;
311
+ type->align = 0;
303
312
 
304
313
  // If the insert succeeds, we cannot fail anymore
305
- if (!instance->types_map.TrySet(type).second) {
314
+ if (named && !instance->types_map.TrySet(type->name, type).second) {
306
315
  ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
307
316
  return env.Null();
308
317
  }
@@ -320,18 +329,65 @@ static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
320
329
  InstanceData *instance = env.GetInstanceData<InstanceData>();
321
330
 
322
331
  if (info.Length() < 1) {
323
- ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
332
+ ThrowError<Napi::TypeError>(env, "Expected 1 to 3 arguments, got %1", info.Length());
324
333
  return env.Null();
325
334
  }
326
335
 
327
- const TypeInfo *ref = ResolveType(instance, info[0]);
328
- if (!ref)
336
+ bool named = (info.Length() >= 2 && !info[1].IsNumber());
337
+
338
+ if (named && !info[0].IsString()) {
339
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
329
340
  return env.Null();
341
+ }
342
+
343
+ std::string name = named ? info[0].As<Napi::String>() : std::string();
344
+
345
+ const TypeInfo *type = ResolveType(info[named]);
346
+ if (!type)
347
+ return env.Null();
348
+ if (type->dispose) {
349
+ ThrowError<Napi::TypeError>(env, "Cannot create pointer to disposable type '%1'", type->name);
350
+ return env.Null();
351
+ }
352
+
353
+ int count = 0;
354
+ if (info.Length() >= 2u + named) {
355
+ if (!info[1 + named].IsNumber()) {
356
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for count, expected number", GetValueType(instance, info[1 + named]));
357
+ return env.Null();
358
+ }
359
+
360
+ count = info[1 + named].As<Napi::Number>();
361
+
362
+ if (count < 1 || count > 4) {
363
+ ThrowError<Napi::TypeError>(env, "Value of count must be between 1 and 4");
364
+ return env.Null();
365
+ }
366
+ } else {
367
+ count = 1;
368
+ }
330
369
 
331
- TypeInfo *type = (TypeInfo *)GetPointerType(instance, ref);
370
+ type = MakePointerType(instance, type, count);
332
371
  RG_ASSERT(type);
333
372
 
334
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
373
+ if (named) {
374
+ TypeInfo *copy = instance->types.AppendDefault();
375
+ RG_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
376
+
377
+ memcpy((void *)copy, type, RG_SIZE(*type));
378
+ copy->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
379
+
380
+ // If the insert succeeds, we cannot fail anymore
381
+ if (!instance->types_map.TrySet(copy->name, copy).second) {
382
+ ThrowError<Napi::Error>(env, "Duplicate type name '%1'", copy->name);
383
+ return env.Null();
384
+ }
385
+ err_guard.Disable();
386
+
387
+ type = copy;
388
+ }
389
+
390
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
335
391
  SetValueTag(instance, external, &TypeInfoMarker);
336
392
 
337
393
  return external;
@@ -349,7 +405,7 @@ static Napi::Value EncodePointerDirection(const Napi::CallbackInfo &info, int di
349
405
  return env.Null();
350
406
  }
351
407
 
352
- const TypeInfo *type = ResolveType(instance, info[0]);
408
+ const TypeInfo *type = ResolveType(info[0]);
353
409
  if (!type)
354
410
  return env.Null();
355
411
 
@@ -382,6 +438,112 @@ static Napi::Value MarkInOut(const Napi::CallbackInfo &info)
382
438
  return EncodePointerDirection(info, 3);
383
439
  }
384
440
 
441
+ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
442
+ {
443
+ Napi::Env env = info.Env();
444
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
445
+
446
+ if (info.Length() < 1) {
447
+ ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
448
+ return env.Null();
449
+ }
450
+
451
+ bool named = (info.Length() >= 2 && !info[1].IsFunction());
452
+
453
+ if (named && !info[0].IsString()) {
454
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
455
+ return env.Null();
456
+ }
457
+
458
+ std::string name = named ? info[0].As<Napi::String>() : std::string("<anonymous>");
459
+
460
+ const TypeInfo *src = ResolveType(info[named]);
461
+ if (!src)
462
+ return env.Null();
463
+ if (src->primitive != PrimitiveKind::String &&
464
+ src->primitive != PrimitiveKind::String16 &&
465
+ src->primitive != PrimitiveKind::Pointer) {
466
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected pointer or string type", PrimitiveKindNames[(int)src->primitive]);
467
+ return env.Null();
468
+ }
469
+ if (src->dispose) {
470
+ ThrowError<Napi::TypeError>(env, "Cannot use disposable type '%1' to create new disposable", src->name);
471
+ return env.Null();
472
+ }
473
+
474
+ DisposeFunc *dispose;
475
+ Napi::Function dispose_func;
476
+ if (info.Length() >= 2u + named && !IsNullOrUndefined(info[1 + named])) {
477
+ Napi::Function func = info[1 + named].As<Napi::Function>();
478
+
479
+ if (!func.IsFunction()) {
480
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for func, expected function", GetValueType(instance, func));
481
+ return env.Null();
482
+ }
483
+
484
+ dispose = [](Napi::Env env, const TypeInfo *type, const void *ptr) {
485
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
486
+ const Napi::FunctionReference &ref = type->dispose_ref;
487
+
488
+ Napi::External<void> external = Napi::External<void>::New(env, (void *)ptr);
489
+ SetValueTag(instance, external, type->ref.marker);
490
+
491
+ Napi::Value self = env.Null();
492
+ napi_value args[] = {
493
+ external
494
+ };
495
+
496
+ ref.Call(self, RG_LEN(args), args);
497
+ };
498
+ dispose_func = func;
499
+ } else {
500
+ dispose = [](Napi::Env, const TypeInfo *, const void *ptr) { free((void *)ptr); };
501
+ }
502
+
503
+ TypeInfo *type = instance->types.AppendDefault();
504
+ RG_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
505
+
506
+ memcpy((void *)type, (const void *)src, RG_SIZE(*src));
507
+ type->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
508
+ type->members.allocator = GetNullAllocator();
509
+ type->dispose = dispose;
510
+ type->dispose_ref = Napi::Persistent(dispose_func);
511
+
512
+ // If the insert succeeds, we cannot fail anymore
513
+ if (named && !instance->types_map.TrySet(type->name, type).second) {
514
+ ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
515
+ return env.Null();
516
+ }
517
+ err_guard.Disable();
518
+
519
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
520
+ SetValueTag(instance, external, &TypeInfoMarker);
521
+
522
+ return external;
523
+ }
524
+
525
+ static Napi::Value CallFree(const Napi::CallbackInfo &info)
526
+ {
527
+ Napi::Env env = info.Env();
528
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
529
+
530
+ if (info.Length() < 1) {
531
+ ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
532
+ return env.Null();
533
+ }
534
+ if (!info[0].IsExternal() || CheckValueTag(instance, info[0], &TypeInfoMarker)) {
535
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected external", GetValueType(instance, info[0]));
536
+ return env.Null();
537
+ }
538
+
539
+ Napi::External<void> external = info[0].As<Napi::External<void>>();
540
+ void *ptr = external.Data();
541
+
542
+ free(ptr);
543
+
544
+ return env.Undefined();
545
+ }
546
+
385
547
  static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
386
548
  {
387
549
  Napi::Env env = info.Env();
@@ -396,7 +558,7 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
396
558
  return env.Null();
397
559
  }
398
560
 
399
- const TypeInfo *ref = ResolveType(instance, info[0]);
561
+ const TypeInfo *ref = ResolveType(info[0]);
400
562
  int64_t len = (uint16_t)info[1].As<Napi::Number>().Int64Value();
401
563
 
402
564
  if (!ref)
@@ -448,7 +610,7 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
448
610
  type->primitive = PrimitiveKind::Array;
449
611
  type->align = ref->align;
450
612
  type->size = (int16_t)(len * ref->size);
451
- type->ref = ref;
613
+ type->ref.type = ref;
452
614
  type->hint = hint;
453
615
 
454
616
  Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
@@ -476,11 +638,11 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
476
638
 
477
639
  func->name = DuplicateString(name.ToString().Utf8Value().c_str(), &instance->str_alloc).ptr;
478
640
 
479
- func->ret.type = ResolveType(instance, ret);
641
+ func->ret.type = ResolveType(ret);
480
642
  if (!func->ret.type)
481
643
  return false;
482
- if (func->ret.type->primitive == PrimitiveKind::Array) {
483
- ThrowError<Napi::Error>(env, "You are not allowed to directly return fixed-size arrays");
644
+ if (!CanReturnType(func->ret.type)) {
645
+ ThrowError<Napi::TypeError>(env, "You are not allowed to directly return %1 values (maybe try %1 *)", func->ret.type->name);
484
646
  return false;
485
647
  }
486
648
 
@@ -503,12 +665,11 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
503
665
  for (uint32_t j = 0; j < parameters_len; j++) {
504
666
  ParameterInfo param = {};
505
667
 
506
- param.type = ResolveType(instance, parameters[j], &param.directions);
668
+ param.type = ResolveType(parameters[j], &param.directions);
507
669
  if (!param.type)
508
670
  return false;
509
- if (param.type->primitive == PrimitiveKind::Void ||
510
- param.type->primitive == PrimitiveKind::Array) {
511
- ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
671
+ if (!CanPassType(param.type)) {
672
+ ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
512
673
  return false;
513
674
  }
514
675
 
@@ -573,12 +734,12 @@ static Napi::Value CreateCallbackType(const Napi::CallbackInfo &info)
573
734
 
574
735
  type->name = func->name;
575
736
 
576
- type->primitive = PrimitiveKind::Callback;
737
+ type->primitive = PrimitiveKind::Prototype;
577
738
  type->align = alignof(void *);
578
739
  type->size = RG_SIZE(void *);
579
- type->proto = func;
740
+ type->ref.proto = func;
580
741
 
581
- instance->types_map.Set(type);
742
+ instance->types_map.Set(type->name, type);
582
743
 
583
744
  Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
584
745
  SetValueTag(instance, external, &TypeInfoMarker);
@@ -586,17 +747,50 @@ static Napi::Value CreateCallbackType(const Napi::CallbackInfo &info)
586
747
  return external;
587
748
  }
588
749
 
589
- static Napi::Value GetTypeSize(const Napi::CallbackInfo &info)
750
+ static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
590
751
  {
591
752
  Napi::Env env = info.Env();
592
753
  InstanceData *instance = env.GetInstanceData<InstanceData>();
593
754
 
755
+ if (info.Length() < 2) {
756
+ ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
757
+ return env.Null();
758
+ }
759
+ if (!info[0].IsString()) {
760
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
761
+ return env.Null();
762
+ }
763
+
764
+ std::string name = info[0].As<Napi::String>();
765
+ const char *alias = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
766
+
767
+ const TypeInfo *type = ResolveType(info[1]);
768
+ if (!type)
769
+ return env.Null();
770
+
771
+ std::pair<const TypeInfo **, bool> ret = instance->types_map.TrySet(alias, type);
772
+
773
+ if (!ret.second) {
774
+ ThrowError<Napi::Error>(env, "Type name '%1' already exists", alias);
775
+ return env.Null();
776
+ }
777
+
778
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
779
+ SetValueTag(instance, external, &TypeInfoMarker);
780
+
781
+ return external;
782
+ }
783
+
784
+ static Napi::Value GetTypeSize(const Napi::CallbackInfo &info)
785
+ {
786
+ Napi::Env env = info.Env();
787
+
594
788
  if (info.Length() < 1) {
595
789
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
596
790
  return env.Null();
597
791
  }
598
792
 
599
- const TypeInfo *type = ResolveType(instance, info[0]);
793
+ const TypeInfo *type = ResolveType(info[0]);
600
794
  if (!type)
601
795
  return env.Null();
602
796
 
@@ -606,20 +800,39 @@ static Napi::Value GetTypeSize(const Napi::CallbackInfo &info)
606
800
  static Napi::Value GetTypeAlign(const Napi::CallbackInfo &info)
607
801
  {
608
802
  Napi::Env env = info.Env();
609
- InstanceData *instance = env.GetInstanceData<InstanceData>();
610
803
 
611
804
  if (info.Length() < 1) {
612
805
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
613
806
  return env.Null();
614
807
  }
615
808
 
616
- const TypeInfo *type = ResolveType(instance, info[0]);
809
+ const TypeInfo *type = ResolveType(info[0]);
617
810
  if (!type)
618
811
  return env.Null();
619
812
 
620
813
  return Napi::Number::New(env, type->align);
621
814
  }
622
815
 
816
+ static Napi::Value GetResolvedType(const Napi::CallbackInfo &info)
817
+ {
818
+ Napi::Env env = info.Env();
819
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
820
+
821
+ if (info.Length() < 1) {
822
+ ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
823
+ return env.Null();
824
+ }
825
+
826
+ const TypeInfo *type = ResolveType(info[0]);
827
+ if (!type)
828
+ return env.Null();
829
+
830
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
831
+ SetValueTag(instance, external, &TypeInfoMarker);
832
+
833
+ return external;
834
+ }
835
+
623
836
  static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
624
837
  {
625
838
  Napi::Env env = info.Env();
@@ -630,12 +843,62 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
630
843
  return env.Null();
631
844
  }
632
845
 
633
- const TypeInfo *type = ResolveType(instance, info[0]);
846
+ const TypeInfo *type = ResolveType(info[0]);
634
847
  if (!type)
635
848
  return env.Null();
849
+
636
850
  if (type->defn.IsEmpty()) {
637
- ThrowError<Napi::TypeError>(env, "Definition of type %1 is not available", type->name);
638
- return env.Null();
851
+ Napi::Object defn = Napi::Object::New(env);
852
+
853
+ defn.Set("name", Napi::String::New(env, type->name));
854
+ defn.Set("primitive", PrimitiveKindNames[(int)type->primitive]);
855
+ defn.Set("size", Napi::Number::New(env, (double)type->size));
856
+ defn.Set("alignment", Napi::Number::New(env, (double)type->align));
857
+
858
+ switch (type->primitive) {
859
+ case PrimitiveKind::Void:
860
+ case PrimitiveKind::Bool:
861
+ case PrimitiveKind::Int8:
862
+ case PrimitiveKind::UInt8:
863
+ case PrimitiveKind::Int16:
864
+ case PrimitiveKind::UInt16:
865
+ case PrimitiveKind::Int32:
866
+ case PrimitiveKind::UInt32:
867
+ case PrimitiveKind::Int64:
868
+ case PrimitiveKind::UInt64:
869
+ case PrimitiveKind::String:
870
+ case PrimitiveKind::String16:
871
+ case PrimitiveKind::Float32:
872
+ case PrimitiveKind::Float64:
873
+ case PrimitiveKind::Prototype:
874
+ case PrimitiveKind::Callback: {} break;
875
+
876
+ case PrimitiveKind::Array: {
877
+ uint32_t len = type->size / type->ref.type->size;
878
+ defn.Set("length", Napi::Number::New(env, (double)len));
879
+ } [[fallthrough]];
880
+ case PrimitiveKind::Pointer: {
881
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type->ref.type);
882
+ SetValueTag(instance, external, &TypeInfoMarker);
883
+
884
+ defn.Set("ref", external);
885
+ } break;
886
+ case PrimitiveKind::Record: {
887
+ Napi::Object members = Napi::Object::New(env);
888
+
889
+ for (const RecordMember &member: type->members) {
890
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)member.type);
891
+ SetValueTag(instance, external, &TypeInfoMarker);
892
+
893
+ members.Set(member.name, external);
894
+ }
895
+
896
+ defn.Set("members", members);
897
+ } break;
898
+ }
899
+
900
+ defn.Freeze();
901
+ type->defn.Reset(defn, 1);
639
902
  }
640
903
 
641
904
  return type->defn.Value();
@@ -743,12 +1006,11 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
743
1006
  for (Size i = func.parameters.len; i < (Size)info.Length(); i += 2) {
744
1007
  ParameterInfo param = {};
745
1008
 
746
- param.type = ResolveType(instance, info[i], &param.directions);
1009
+ param.type = ResolveType(info[i], &param.directions);
747
1010
  if (RG_UNLIKELY(!param.type))
748
1011
  return env.Null();
749
- if (RG_UNLIKELY(param.type->primitive == PrimitiveKind::Void ||
750
- param.type->primitive == PrimitiveKind::Array)) {
751
- ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", PrimitiveKindNames[(int)param.type->primitive]);
1012
+ if (RG_UNLIKELY(!CanPassType(param.type))) {
1013
+ ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", PrimitiveKindNames[(int)param.type->primitive]);
752
1014
  return env.Null();
753
1015
  }
754
1016
 
@@ -866,7 +1128,7 @@ static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
866
1128
  }
867
1129
  async->Queue();
868
1130
 
869
- return env.Null();
1131
+ return env.Undefined();
870
1132
  }
871
1133
 
872
1134
  static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConvention convention)
@@ -923,7 +1185,7 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
923
1185
  uint16_t ordinal = (uint16_t)info[0].As<Napi::Number>().Uint32Value();
924
1186
 
925
1187
  func->decorated_name = nullptr;
926
- func->func = (void *)GetProcAddress((HMODULE)lib->module, (LPCSTR)ordinal);
1188
+ func->func = (void *)GetProcAddress((HMODULE)lib->module, (LPCSTR)(size_t)ordinal);
927
1189
  }
928
1190
  #else
929
1191
  if (func->decorated_name) {
@@ -1032,6 +1294,89 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
1032
1294
  return obj;
1033
1295
  }
1034
1296
 
1297
+ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
1298
+ {
1299
+ Napi::Env env = info.Env();
1300
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
1301
+
1302
+ if (info.Length() < 2) {
1303
+ ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
1304
+ return env.Null();
1305
+ }
1306
+ if (!info[0].IsFunction()) {
1307
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for func, expected function", GetValueType(instance, info[0]));
1308
+ return env.Null();
1309
+ }
1310
+
1311
+ Napi::Function func = info[0].As<Napi::Function>();
1312
+
1313
+ const TypeInfo *type = ResolveType(info[1]);
1314
+ if (!type)
1315
+ return env.Null();
1316
+ if (type->primitive != PrimitiveKind::Callback) {
1317
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected <callback> * type", type->name);
1318
+ return env.Null();
1319
+ }
1320
+
1321
+ int idx = CountTrailingZeros(~instance->registered_trampolines);
1322
+
1323
+ if (RG_UNLIKELY(idx >= MaxTrampolines)) {
1324
+ ThrowError<Napi::Error>(env, "Too many registered callbacks are in use (max = %1)", MaxTrampolines);
1325
+ return env.Null();
1326
+ }
1327
+
1328
+ instance->registered_trampolines |= 1u << idx;
1329
+ idx += MaxTrampolines;
1330
+
1331
+ TrampolineInfo *trampoline = &instance->trampolines[idx];
1332
+
1333
+ trampoline->proto = type->ref.proto;
1334
+ trampoline->func.Reset(func, 1);
1335
+ trampoline->generation = -1;
1336
+
1337
+ void *ptr = GetTrampoline(idx, type->ref.proto);
1338
+
1339
+ Napi::External<void> external = Napi::External<void>::New(env, ptr);
1340
+ SetValueTag(instance, external, type->ref.marker);
1341
+
1342
+ return external;
1343
+ }
1344
+
1345
+ static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
1346
+ {
1347
+ Napi::Env env = info.Env();
1348
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
1349
+
1350
+ if (info.Length() < 1) {
1351
+ ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
1352
+ return env.Null();
1353
+ }
1354
+ if (!info[0].IsExternal()) {
1355
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for id, expected registered callback", GetValueType(instance, info[0]));
1356
+ return env.Null();
1357
+ }
1358
+
1359
+ Napi::External<void> external = info[0].As<Napi::External<void>>();
1360
+ void *ptr = external.Data();
1361
+
1362
+ for (Size i = 0; i < MaxTrampolines; i++) {
1363
+ Size idx = i + MaxTrampolines;
1364
+
1365
+ if (!(instance->registered_trampolines & (1u << i)))
1366
+ continue;
1367
+
1368
+ const TrampolineInfo &trampoline = instance->trampolines[idx];
1369
+
1370
+ if (GetTrampoline(idx, trampoline.proto) == ptr) {
1371
+ instance->registered_trampolines &= ~(1u << i);
1372
+ return env.Undefined();
1373
+ }
1374
+ }
1375
+
1376
+ ThrowError<Napi::Error>(env, "Could not find matching registered callback");
1377
+ return env.Null();
1378
+ }
1379
+
1035
1380
  LibraryHolder::~LibraryHolder()
1036
1381
  {
1037
1382
  #ifdef _WIN32
@@ -1058,108 +1403,91 @@ void LibraryHolder::Unref() const
1058
1403
  }
1059
1404
  }
1060
1405
 
1061
- static void RegisterPrimitiveType(InstanceData *instance, const char *name, PrimitiveKind primitive,
1062
- int16_t size, int16_t align)
1406
+ static inline PrimitiveKind GetIntegerPrimitive(Size len, bool sign)
1063
1407
  {
1408
+ switch (len) {
1409
+ case 1: return sign ? PrimitiveKind::Int8 : PrimitiveKind::UInt8;
1410
+ case 2: return sign ? PrimitiveKind::Int16 : PrimitiveKind::UInt16;
1411
+ case 4: return sign ? PrimitiveKind::Int32 : PrimitiveKind::UInt32;
1412
+ case 8: return sign ? PrimitiveKind::Int64 : PrimitiveKind::UInt64;
1413
+ }
1414
+
1415
+ RG_UNREACHABLE();
1416
+ }
1417
+
1418
+ static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initializer_list<const char *> names,
1419
+ PrimitiveKind primitive, int16_t size, int16_t align, const char *ref = nullptr)
1420
+ {
1421
+ RG_ASSERT(names.size() > 0);
1064
1422
  RG_ASSERT(align <= size);
1065
1423
 
1424
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
1425
+
1066
1426
  TypeInfo *type = instance->types.AppendDefault();
1067
1427
 
1068
- type->name = name;
1428
+ type->name = *names.begin();
1069
1429
 
1070
1430
  type->primitive = primitive;
1071
1431
  type->size = size;
1072
1432
  type->align = align;
1073
1433
 
1074
- RG_ASSERT(!instance->types_map.Find(name));
1075
- instance->types_map.Set(type);
1076
- }
1434
+ if (ref) {
1435
+ const TypeInfo *marker = instance->types_map.FindValue(ref, nullptr);
1436
+ RG_ASSERT(marker);
1077
1437
 
1078
- template <typename T>
1079
- static inline PrimitiveKind GetIntegerPrimitive(bool sign)
1080
- {
1081
- switch (RG_SIZE(T)) {
1082
- case 1: return sign ? PrimitiveKind::Int8 : PrimitiveKind::UInt8;
1083
- case 2: return sign ? PrimitiveKind::Int16 : PrimitiveKind::UInt16;
1084
- case 4: return sign ? PrimitiveKind::Int32 : PrimitiveKind::UInt32;
1085
- case 8: return sign ? PrimitiveKind::Int64 : PrimitiveKind::UInt64;
1438
+ type->ref.marker = marker;
1086
1439
  }
1087
1440
 
1088
- RG_UNREACHABLE();
1441
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
1442
+ SetValueTag(instance, external, &TypeInfoMarker);
1443
+
1444
+ for (const char *name: names) {
1445
+ std::pair<const TypeInfo **, bool> ret = instance->types_map.TrySet(name, type);
1446
+ RG_ASSERT(ret.second);
1447
+
1448
+ if (!EndsWith(name, "*")) {
1449
+ map.Set(name, external);
1450
+ }
1451
+ }
1089
1452
  }
1090
1453
 
1091
1454
  static Napi::Object InitBaseTypes(Napi::Env env)
1092
1455
  {
1093
1456
  InstanceData *instance = env.GetInstanceData<InstanceData>();
1094
1457
 
1095
- RG_ASSERT(!instance->types.len);
1096
-
1097
- RegisterPrimitiveType(instance, "void", PrimitiveKind::Void, 0, 0);
1098
- RegisterPrimitiveType(instance, "void *", PrimitiveKind::Pointer, RG_SIZE(void *), alignof(void *));
1099
- RegisterPrimitiveType(instance, "bool", PrimitiveKind::Bool, RG_SIZE(bool), alignof(bool));
1100
- RegisterPrimitiveType(instance, "int8", PrimitiveKind::Int8, 1, 1);
1101
- RegisterPrimitiveType(instance, "int8_t", PrimitiveKind::Int8, 1, 1);
1102
- RegisterPrimitiveType(instance, "uint8", PrimitiveKind::UInt8, 1, 1);
1103
- RegisterPrimitiveType(instance, "uint8_t", PrimitiveKind::UInt8, 1, 1);
1104
- RegisterPrimitiveType(instance, "char", PrimitiveKind::Int8, 1, 1);
1105
- RegisterPrimitiveType(instance, "uchar", PrimitiveKind::UInt8, 1, 1);
1106
- RegisterPrimitiveType(instance, "unsigned char", PrimitiveKind::UInt8, 1, 1);
1107
- RegisterPrimitiveType(instance, "char16", PrimitiveKind::Int16, 2, 2);
1108
- RegisterPrimitiveType(instance, "char16_t", PrimitiveKind::Int16, 2, 2);
1109
- RegisterPrimitiveType(instance, "int16", PrimitiveKind::Int16, 2, 2);
1110
- RegisterPrimitiveType(instance, "int16_t", PrimitiveKind::Int16, 2, 2);
1111
- RegisterPrimitiveType(instance, "uint16", PrimitiveKind::UInt16, 2, 2);
1112
- RegisterPrimitiveType(instance, "uint16_t", PrimitiveKind::UInt16, 2, 2);
1113
- RegisterPrimitiveType(instance, "short", PrimitiveKind::Int16, 2, 2);
1114
- RegisterPrimitiveType(instance, "ushort", PrimitiveKind::UInt16, 2, 2);
1115
- RegisterPrimitiveType(instance, "unsigned short", PrimitiveKind::UInt16, 2, 2);
1116
- RegisterPrimitiveType(instance, "int32", PrimitiveKind::Int32, 4, 4);
1117
- RegisterPrimitiveType(instance, "int32_t", PrimitiveKind::Int32, 4, 4);
1118
- RegisterPrimitiveType(instance, "uint32", PrimitiveKind::UInt32, 4, 4);
1119
- RegisterPrimitiveType(instance, "uint32_t", PrimitiveKind::UInt32, 4, 4);
1120
- RegisterPrimitiveType(instance, "int", PrimitiveKind::Int32, 4, 4);
1121
- RegisterPrimitiveType(instance, "uint", PrimitiveKind::UInt32, 4, 4);
1122
- RegisterPrimitiveType(instance, "unsigned int", PrimitiveKind::UInt32, 4, 4);
1123
- RegisterPrimitiveType(instance, "int64", PrimitiveKind::Int64, 8, alignof(int64_t));
1124
- RegisterPrimitiveType(instance, "int64_t", PrimitiveKind::Int64, 8, alignof(int64_t));
1125
- RegisterPrimitiveType(instance, "uint64", PrimitiveKind::UInt64, 8, alignof(int64_t));
1126
- RegisterPrimitiveType(instance, "uint64_t", PrimitiveKind::UInt64, 8, alignof(int64_t));
1127
- RegisterPrimitiveType(instance, "intptr", GetIntegerPrimitive<intptr_t>(true), RG_SIZE(intptr_t), alignof(intptr_t));
1128
- RegisterPrimitiveType(instance, "intptr_t", GetIntegerPrimitive<intptr_t>(true), RG_SIZE(intptr_t), alignof(intptr_t));
1129
- RegisterPrimitiveType(instance, "uintptr", GetIntegerPrimitive<intptr_t>(false), RG_SIZE(intptr_t), alignof(intptr_t));
1130
- RegisterPrimitiveType(instance, "uintptr_t", GetIntegerPrimitive<intptr_t>(false), RG_SIZE(intptr_t), alignof(intptr_t));
1131
- RegisterPrimitiveType(instance, "long", GetIntegerPrimitive<long>(true), RG_SIZE(long), alignof(long));
1132
- RegisterPrimitiveType(instance, "ulong", GetIntegerPrimitive<long>(false), RG_SIZE(long), alignof(long));
1133
- RegisterPrimitiveType(instance, "unsigned long", GetIntegerPrimitive<long>(false), RG_SIZE(long), alignof(long));
1134
- RegisterPrimitiveType(instance, "longlong", PrimitiveKind::Int64, RG_SIZE(int64_t), alignof(int64_t));
1135
- RegisterPrimitiveType(instance, "long long", PrimitiveKind::Int64, RG_SIZE(int64_t), alignof(int64_t));
1136
- RegisterPrimitiveType(instance, "ulonglong", PrimitiveKind::UInt64, RG_SIZE(uint64_t), alignof(uint64_t));
1137
- RegisterPrimitiveType(instance, "unsigned long long", PrimitiveKind::UInt64, RG_SIZE(uint64_t), alignof(uint64_t));
1138
- RegisterPrimitiveType(instance, "float32", PrimitiveKind::Float32, 4, alignof(float));
1139
- RegisterPrimitiveType(instance, "float64", PrimitiveKind::Float64, 8, alignof(double));
1140
- RegisterPrimitiveType(instance, "float", PrimitiveKind::Float32, 4, alignof(float));
1141
- RegisterPrimitiveType(instance, "double", PrimitiveKind::Float64, 8, alignof(double));
1142
- RegisterPrimitiveType(instance, "string", PrimitiveKind::String, RG_SIZE(void *), alignof(void *));
1143
- RegisterPrimitiveType(instance, "string16", PrimitiveKind::String16, RG_SIZE(void *), alignof(void *));
1144
- RegisterPrimitiveType(instance, "str", PrimitiveKind::String, RG_SIZE(void *), alignof(void *));
1145
- RegisterPrimitiveType(instance, "str16", PrimitiveKind::String16, RG_SIZE(void *), alignof(void *));
1146
-
1147
1458
  Napi::Object types = Napi::Object::New(env);
1148
- for (TypeInfo &type: instance->types) {
1149
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, &type);
1150
- SetValueTag(instance, external, &TypeInfoMarker);
1151
1459
 
1152
- types.Set(type.name, external);
1460
+ RegisterPrimitiveType(env, types, {"void"}, PrimitiveKind::Void, 0, 0);
1461
+ RegisterPrimitiveType(env, types, {"bool"}, PrimitiveKind::Bool, RG_SIZE(bool), alignof(bool));
1462
+ RegisterPrimitiveType(env, types, {"int8_t", "int8"}, PrimitiveKind::Int8, 1, 1);
1463
+ RegisterPrimitiveType(env, types, {"uint8_t", "uint8"}, PrimitiveKind::UInt8, 1, 1);
1464
+ RegisterPrimitiveType(env, types, {"char"}, PrimitiveKind::Int8, 1, 1);
1465
+ RegisterPrimitiveType(env, types, {"unsigned char", "uchar"}, PrimitiveKind::UInt8, 1, 1);
1466
+ RegisterPrimitiveType(env, types, {"char16_t", "char16"}, PrimitiveKind::Int16, 2, 2);
1467
+ RegisterPrimitiveType(env, types, {"int16_t", "int16"}, PrimitiveKind::Int16, 2, 2);
1468
+ RegisterPrimitiveType(env, types, {"uint16_t", "uint16"}, PrimitiveKind::UInt16, 2, 2);
1469
+ RegisterPrimitiveType(env, types, {"short"}, PrimitiveKind::Int16, 2, 2);
1470
+ RegisterPrimitiveType(env, types, {"unsigned short", "ushort"}, PrimitiveKind::UInt16, 2, 2);
1471
+ RegisterPrimitiveType(env, types, {"int32_t", "int32"}, PrimitiveKind::Int32, 4, 4);
1472
+ RegisterPrimitiveType(env, types, {"uint32_t", "uint32"}, PrimitiveKind::UInt32, 4, 4);
1473
+ RegisterPrimitiveType(env, types, {"int"}, PrimitiveKind::Int32, 4, 4);
1474
+ RegisterPrimitiveType(env, types, {"unsigned int", "uint"}, PrimitiveKind::UInt32, 4, 4);
1475
+ RegisterPrimitiveType(env, types, {"int64_t", "int64"}, PrimitiveKind::Int64, 8, alignof(int64_t));
1476
+ RegisterPrimitiveType(env, types, {"uint64_t", "uint64"}, PrimitiveKind::UInt64, 8, alignof(int64_t));
1477
+ RegisterPrimitiveType(env, types, {"intptr_t", "intptr"}, GetIntegerPrimitive(RG_SIZE(intptr_t), true), RG_SIZE(intptr_t), alignof(intptr_t));
1478
+ RegisterPrimitiveType(env, types, {"uintptr_t", "uintptr"}, GetIntegerPrimitive(RG_SIZE(intptr_t), false), RG_SIZE(intptr_t), alignof(intptr_t));
1479
+ RegisterPrimitiveType(env, types, {"long"}, GetIntegerPrimitive(RG_SIZE(long), true), RG_SIZE(long), alignof(long));
1480
+ RegisterPrimitiveType(env, types, {"unsigned long", "ulong"}, GetIntegerPrimitive(RG_SIZE(long), false), RG_SIZE(long), alignof(long));
1481
+ RegisterPrimitiveType(env, types, {"long long", "longlong"}, PrimitiveKind::Int64, RG_SIZE(int64_t), alignof(int64_t));
1482
+ RegisterPrimitiveType(env, types, {"unsigned long long", "ulonglong"}, PrimitiveKind::UInt64, RG_SIZE(uint64_t), alignof(uint64_t));
1483
+ RegisterPrimitiveType(env, types, {"float", "float32"}, PrimitiveKind::Float32, 4, alignof(float));
1484
+ RegisterPrimitiveType(env, types, {"double", "float64"}, PrimitiveKind::Float64, 8, alignof(double));
1485
+ RegisterPrimitiveType(env, types, {"char *", "str", "string"}, PrimitiveKind::String, RG_SIZE(void *), alignof(void *), "char");
1486
+ RegisterPrimitiveType(env, types, {"char16_t *", "char16 *", "str16", "string16"}, PrimitiveKind::String16, RG_SIZE(void *), alignof(void *), "char16_t");
1487
+
1488
+ instance->void_type = instance->types_map.FindValue("void", nullptr);
1489
+ RG_ASSERT(instance->void_type);
1153
1490
 
1154
- if (strchr(type.name, ' ')) {
1155
- char name_buf[64] = {};
1156
- for (Size i = 0; type.name[i]; i++) {
1157
- RG_ASSERT(i < RG_SIZE(name_buf) - 1);
1158
- name_buf[i] = type.name[i] != ' ' ? type.name[i] : '_';
1159
- }
1160
- types.Set(name_buf, external);
1161
- }
1162
- }
1163
1491
  types.Freeze();
1164
1492
 
1165
1493
  return types;
@@ -1211,6 +1539,37 @@ InstanceData::~InstanceData()
1211
1539
  }
1212
1540
  }
1213
1541
 
1542
+ static Napi::Value CastValue(const Napi::CallbackInfo &info)
1543
+ {
1544
+ Napi::Env env = info.Env();
1545
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
1546
+
1547
+ if (RG_UNLIKELY(info.Length() < 2)) {
1548
+ ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
1549
+ return env.Null();
1550
+ }
1551
+
1552
+ Napi::Value value = info[0];
1553
+
1554
+ const TypeInfo *type = ResolveType(info[1]);
1555
+ if (RG_UNLIKELY(!type))
1556
+ return env.Null();
1557
+ if (type->primitive != PrimitiveKind::Pointer) {
1558
+ ThrowError<Napi::TypeError>(env, "Only pointer types can be used for casting");
1559
+ return env.Null();
1560
+ }
1561
+
1562
+ ValueCast *cast = new ValueCast;
1563
+
1564
+ cast->ref.Reset(value, 1);
1565
+ cast->type = type;
1566
+
1567
+ Napi::External<ValueCast> external = Napi::External<ValueCast>::New(env, cast, [](Napi::Env, ValueCast *cast) { delete cast; });
1568
+ SetValueTag(instance, external, &CastMarker);
1569
+
1570
+ return external;
1571
+ }
1572
+
1214
1573
  template <typename Func>
1215
1574
  static void SetExports(Napi::Env env, Func func)
1216
1575
  {
@@ -1218,13 +1577,15 @@ static void SetExports(Napi::Env env, Func func)
1218
1577
 
1219
1578
  func("struct", Napi::Function::New(env, CreatePaddedStructType));
1220
1579
  func("pack", Napi::Function::New(env, CreatePackedStructType));
1221
- func("handle", Napi::Function::New(env, CreateHandleType));
1580
+ func("opaque", Napi::Function::New(env, CreateOpaqueType));
1222
1581
  func("pointer", Napi::Function::New(env, CreatePointerType));
1223
1582
  func("array", Napi::Function::New(env, CreateArrayType));
1224
1583
  func("callback", Napi::Function::New(env, CreateCallbackType));
1584
+ func("alias", Napi::Function::New(env, CreateTypeAlias));
1225
1585
 
1226
1586
  func("sizeof", Napi::Function::New(env, GetTypeSize));
1227
1587
  func("alignof", Napi::Function::New(env, GetTypeAlign));
1588
+ func("resolve", Napi::Function::New(env, GetResolvedType));
1228
1589
  func("introspect", Napi::Function::New(env, GetTypeDefinition));
1229
1590
 
1230
1591
  func("load", Napi::Function::New(env, LoadSharedLibrary));
@@ -1233,6 +1594,14 @@ static void SetExports(Napi::Env env, Func func)
1233
1594
  func("out", Napi::Function::New(env, MarkOut));
1234
1595
  func("inout", Napi::Function::New(env, MarkInOut));
1235
1596
 
1597
+ func("disposable", Napi::Function::New(env, CreateDisposableType));
1598
+ func("free", Napi::Function::New(env, CallFree));
1599
+
1600
+ func("register", Napi::Function::New(env, RegisterCallback));
1601
+ func("unregister", Napi::Function::New(env, UnregisterCallback));
1602
+
1603
+ func("as", Napi::Function::New(env, CastValue));
1604
+
1236
1605
  #if defined(_WIN32)
1237
1606
  func("extension", Napi::String::New(env, ".dll"));
1238
1607
  #elif defined(__APPLE__)