koffi 1.3.10 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/CMakeLists.txt +7 -2
  2. package/ChangeLog.md +52 -14
  3. package/README.md +6 -0
  4. package/build/qemu/2.0.0/koffi_darwin_arm64.tar.gz +0 -0
  5. package/build/qemu/2.0.0/koffi_darwin_x64.tar.gz +0 -0
  6. package/build/qemu/2.0.0/koffi_freebsd_arm64.tar.gz +0 -0
  7. package/build/qemu/2.0.0/koffi_freebsd_ia32.tar.gz +0 -0
  8. package/build/qemu/2.0.0/koffi_freebsd_x64.tar.gz +0 -0
  9. package/build/qemu/2.0.0/koffi_linux_arm32hf.tar.gz +0 -0
  10. package/build/qemu/2.0.0/koffi_linux_arm64.tar.gz +0 -0
  11. package/build/qemu/2.0.0/koffi_linux_ia32.tar.gz +0 -0
  12. package/build/qemu/2.0.0/koffi_linux_riscv64hf64.tar.gz +0 -0
  13. package/build/qemu/2.0.0/koffi_linux_x64.tar.gz +0 -0
  14. package/build/qemu/2.0.0/koffi_openbsd_ia32.tar.gz +0 -0
  15. package/build/qemu/2.0.0/koffi_openbsd_x64.tar.gz +0 -0
  16. package/build/qemu/2.0.0/koffi_win32_arm64.tar.gz +0 -0
  17. package/build/qemu/2.0.0/koffi_win32_ia32.tar.gz +0 -0
  18. package/build/qemu/2.0.0/koffi_win32_x64.tar.gz +0 -0
  19. package/doc/benchmarks.md +2 -2
  20. package/doc/changes.md +156 -1
  21. package/doc/contribute.md +0 -1
  22. package/doc/dist/doctrees/changes.doctree +0 -0
  23. package/doc/dist/doctrees/environment.pickle +0 -0
  24. package/doc/dist/doctrees/functions.doctree +0 -0
  25. package/doc/dist/doctrees/types.doctree +0 -0
  26. package/doc/dist/html/_sources/changes.md.txt +156 -1
  27. package/doc/dist/html/_sources/functions.md.txt +8 -4
  28. package/doc/dist/html/_sources/types.md.txt +9 -0
  29. package/doc/dist/html/benchmarks.html +1 -1
  30. package/doc/dist/html/changes.html +226 -14
  31. package/doc/dist/html/contribute.html +1 -1
  32. package/doc/dist/html/functions.html +15 -12
  33. package/doc/dist/html/genindex.html +1 -1
  34. package/doc/dist/html/index.html +6 -16
  35. package/doc/dist/html/memory.html +3 -3
  36. package/doc/dist/html/objects.inv +0 -0
  37. package/doc/dist/html/platforms.html +1 -1
  38. package/doc/dist/html/search.html +1 -1
  39. package/doc/dist/html/searchindex.js +1 -1
  40. package/doc/dist/html/start.html +1 -1
  41. package/doc/dist/html/types.html +11 -3
  42. package/doc/functions.md +137 -13
  43. package/doc/types.md +35 -10
  44. package/package.json +9 -7
  45. package/qemu/registry/machines.json +5 -5
  46. package/qemu/registry/sha256sum.txt +16 -16
  47. package/src/abi_arm32.cc +90 -18
  48. package/src/abi_arm32_fwd.S +121 -57
  49. package/src/abi_arm64.cc +90 -18
  50. package/src/abi_arm64_fwd.S +96 -0
  51. package/src/abi_arm64_fwd.asm +128 -0
  52. package/src/abi_riscv64.cc +88 -18
  53. package/src/abi_riscv64_fwd.S +96 -0
  54. package/src/abi_x64_sysv.cc +93 -21
  55. package/src/abi_x64_sysv_fwd.S +96 -0
  56. package/src/abi_x64_win.cc +88 -18
  57. package/src/abi_x64_win_fwd.asm +128 -0
  58. package/src/abi_x86.cc +93 -18
  59. package/src/abi_x86_fwd.S +96 -0
  60. package/src/abi_x86_fwd.asm +128 -0
  61. package/src/call.cc +97 -63
  62. package/src/call.hh +2 -1
  63. package/src/ffi.cc +452 -140
  64. package/src/ffi.hh +23 -9
  65. package/src/parser.cc +20 -42
  66. package/src/util.cc +117 -27
  67. package/src/util.hh +3 -2
  68. package/test/callbacks.js +54 -8
  69. package/test/misc.c +30 -15
  70. package/test/raylib.js +1 -1
  71. package/test/sqlite.js +24 -16
  72. package/test/sync.js +43 -33
  73. package/vendor/libcc/libcc.cc +18 -5
  74. package/vendor/libcc/libcc.hh +70 -23
  75. package/build/qemu/1.3.10/koffi_darwin_arm64.tar.gz +0 -0
  76. package/build/qemu/1.3.10/koffi_darwin_x64.tar.gz +0 -0
  77. package/build/qemu/1.3.10/koffi_freebsd_arm64.tar.gz +0 -0
  78. package/build/qemu/1.3.10/koffi_freebsd_ia32.tar.gz +0 -0
  79. package/build/qemu/1.3.10/koffi_freebsd_x64.tar.gz +0 -0
  80. package/build/qemu/1.3.10/koffi_linux_arm32hf.tar.gz +0 -0
  81. package/build/qemu/1.3.10/koffi_linux_arm64.tar.gz +0 -0
  82. package/build/qemu/1.3.10/koffi_linux_ia32.tar.gz +0 -0
  83. package/build/qemu/1.3.10/koffi_linux_riscv64hf64.tar.gz +0 -0
  84. package/build/qemu/1.3.10/koffi_linux_x64.tar.gz +0 -0
  85. package/build/qemu/1.3.10/koffi_openbsd_ia32.tar.gz +0 -0
  86. package/build/qemu/1.3.10/koffi_openbsd_x64.tar.gz +0 -0
  87. package/build/qemu/1.3.10/koffi_win32_arm64.tar.gz +0 -0
  88. package/build/qemu/1.3.10/koffi_win32_ia32.tar.gz +0 -0
  89. package/build/qemu/1.3.10/koffi_win32_x64.tar.gz +0 -0
package/src/ffi.cc CHANGED
@@ -199,8 +199,6 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
199
199
 
200
200
  type->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
201
201
 
202
- type->defn.Reset(obj, 1);
203
-
204
202
  type->primitive = PrimitiveKind::Record;
205
203
  type->align = 1;
206
204
 
@@ -213,18 +211,20 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
213
211
  Napi::Value value = obj[key];
214
212
 
215
213
  member.name = DuplicateString(key.c_str(), &instance->str_alloc).ptr;
216
- member.type = ResolveType(instance, value);
214
+ member.type = ResolveType(value);
217
215
  if (!member.type)
218
216
  return env.Null();
219
- if (member.type->primitive == PrimitiveKind::Void) {
220
- ThrowError<Napi::TypeError>(env, "Type Void cannot be used as a member");
217
+ if (member.type->primitive == PrimitiveKind::Void ||
218
+ member.type->primitive == PrimitiveKind::Prototype) {
219
+ ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a member (maybe try %1 *)", member.type->name);
221
220
  return env.Null();
222
221
  }
223
222
 
224
- member.align = pad ? member.type->align : 1;
223
+ int16_t align = pad ? member.type->align : 1;
224
+ member.offset = (int16_t)AlignLen(type->size, align);
225
225
 
226
- type->size = (int16_t)(AlignLen(type->size, member.align) + member.type->size);
227
- type->align = std::max(type->align, member.align);
226
+ type->size = (int16_t)(member.offset + member.type->size);
227
+ type->align = std::max(type->align, align);
228
228
 
229
229
  if (!members.TrySet(member.name).second) {
230
230
  ThrowError<Napi::Error>(env, "Duplicate member '%1' in struct '%2'", member.name, type->name);
@@ -242,7 +242,7 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
242
242
  type->size = (int16_t)AlignLen(type->size, type->align);
243
243
 
244
244
  // If the insert succeeds, we cannot fail anymore
245
- if (named && !instance->types_map.TrySet(type).second) {
245
+ if (named && !instance->types_map.TrySet(type->name, type).second) {
246
246
  ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
247
247
  return env.Null();
248
248
  }
@@ -269,40 +269,26 @@ static Napi::Value CreateHandleType(const Napi::CallbackInfo &info)
269
269
  Napi::Env env = info.Env();
270
270
  InstanceData *instance = env.GetInstanceData<InstanceData>();
271
271
 
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()) {
272
+ bool named = (info.Length() >= 1);
273
+
274
+ if (named && !info[0].IsString()) {
277
275
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
278
276
  return env.Null();
279
277
  }
280
278
 
279
+ std::string name = named ? info[0].As<Napi::String>() : std::string("<anonymous>");
280
+
281
281
  TypeInfo *type = instance->types.AppendDefault();
282
282
  RG_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
283
283
 
284
- std::string name = info[0].As<Napi::String>();
285
-
286
284
  type->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
287
285
 
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
- }
286
+ type->primitive = PrimitiveKind::Void;
287
+ type->size = 0;
288
+ type->align = 0;
303
289
 
304
290
  // If the insert succeeds, we cannot fail anymore
305
- if (!instance->types_map.TrySet(type).second) {
291
+ if (named && !instance->types_map.TrySet(type->name, type).second) {
306
292
  ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
307
293
  return env.Null();
308
294
  }
@@ -320,18 +306,65 @@ static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
320
306
  InstanceData *instance = env.GetInstanceData<InstanceData>();
321
307
 
322
308
  if (info.Length() < 1) {
323
- ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
309
+ ThrowError<Napi::TypeError>(env, "Expected 1 to 3 arguments, got %1", info.Length());
324
310
  return env.Null();
325
311
  }
326
312
 
327
- const TypeInfo *ref = ResolveType(instance, info[0]);
328
- if (!ref)
313
+ bool named = (info.Length() >= 2 && !info[1].IsNumber());
314
+
315
+ if (named && !info[0].IsString()) {
316
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
329
317
  return env.Null();
318
+ }
319
+
320
+ std::string name = named ? info[0].As<Napi::String>() : std::string();
330
321
 
331
- TypeInfo *type = (TypeInfo *)GetPointerType(instance, ref);
322
+ const TypeInfo *type = ResolveType(info[named]);
323
+ if (!type)
324
+ return env.Null();
325
+ if (type->dispose) {
326
+ ThrowError<Napi::TypeError>(env, "Cannot create pointer to disposable type '%1'", type->name);
327
+ return env.Null();
328
+ }
329
+
330
+ int count = 0;
331
+ if (info.Length() >= 2u + named) {
332
+ if (!info[1 + named].IsNumber()) {
333
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for count, expected number", GetValueType(instance, info[1 + named]));
334
+ return env.Null();
335
+ }
336
+
337
+ count = info[1 + named].As<Napi::Number>();
338
+
339
+ if (count < 1 || count > 4) {
340
+ ThrowError<Napi::TypeError>(env, "Value of count must be between 1 and 4");
341
+ return env.Null();
342
+ }
343
+ } else {
344
+ count = 1;
345
+ }
346
+
347
+ type = MakePointerType(instance, type, count);
332
348
  RG_ASSERT(type);
333
349
 
334
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
350
+ if (named) {
351
+ TypeInfo *copy = instance->types.AppendDefault();
352
+ RG_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
353
+
354
+ memcpy((void *)copy, type, RG_SIZE(*type));
355
+ copy->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
356
+
357
+ // If the insert succeeds, we cannot fail anymore
358
+ if (!instance->types_map.TrySet(copy->name, copy).second) {
359
+ ThrowError<Napi::Error>(env, "Duplicate type name '%1'", copy->name);
360
+ return env.Null();
361
+ }
362
+ err_guard.Disable();
363
+
364
+ type = copy;
365
+ }
366
+
367
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
335
368
  SetValueTag(instance, external, &TypeInfoMarker);
336
369
 
337
370
  return external;
@@ -349,7 +382,7 @@ static Napi::Value EncodePointerDirection(const Napi::CallbackInfo &info, int di
349
382
  return env.Null();
350
383
  }
351
384
 
352
- const TypeInfo *type = ResolveType(instance, info[0]);
385
+ const TypeInfo *type = ResolveType(info[0]);
353
386
  if (!type)
354
387
  return env.Null();
355
388
 
@@ -382,6 +415,112 @@ static Napi::Value MarkInOut(const Napi::CallbackInfo &info)
382
415
  return EncodePointerDirection(info, 3);
383
416
  }
384
417
 
418
+ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
419
+ {
420
+ Napi::Env env = info.Env();
421
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
422
+
423
+ if (info.Length() < 1) {
424
+ ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
425
+ return env.Null();
426
+ }
427
+
428
+ bool named = (info.Length() >= 2 && !info[1].IsFunction());
429
+
430
+ if (named && !info[0].IsString()) {
431
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
432
+ return env.Null();
433
+ }
434
+
435
+ std::string name = named ? info[0].As<Napi::String>() : std::string("<anonymous>");
436
+
437
+ const TypeInfo *src = ResolveType(info[named]);
438
+ if (!src)
439
+ return env.Null();
440
+ if (src->primitive != PrimitiveKind::String &&
441
+ src->primitive != PrimitiveKind::String16 &&
442
+ src->primitive != PrimitiveKind::Pointer) {
443
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected pointer or string type", PrimitiveKindNames[(int)src->primitive]);
444
+ return env.Null();
445
+ }
446
+ if (src->dispose) {
447
+ ThrowError<Napi::TypeError>(env, "Cannot use disposable type '%1' to create new disposable", src->name);
448
+ return env.Null();
449
+ }
450
+
451
+ DisposeFunc *dispose;
452
+ Napi::Function dispose_func;
453
+ if (info.Length() >= 2u + named && !IsNullOrUndefined(info[1 + named])) {
454
+ Napi::Function func = info[1 + named].As<Napi::Function>();
455
+
456
+ if (!func.IsFunction()) {
457
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for func, expected function", GetValueType(instance, func));
458
+ return env.Null();
459
+ }
460
+
461
+ dispose = [](Napi::Env env, const TypeInfo *type, const void *ptr) {
462
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
463
+ const Napi::FunctionReference &ref = type->dispose_ref;
464
+
465
+ Napi::External<void> external = Napi::External<void>::New(env, (void *)ptr);
466
+ SetValueTag(instance, external, type->ref.marker);
467
+
468
+ Napi::Value self = env.Null();
469
+ napi_value args[] = {
470
+ external
471
+ };
472
+
473
+ ref.Call(self, RG_LEN(args), args);
474
+ };
475
+ dispose_func = func;
476
+ } else {
477
+ dispose = [](Napi::Env, const TypeInfo *, const void *ptr) { free((void *)ptr); };
478
+ }
479
+
480
+ TypeInfo *type = instance->types.AppendDefault();
481
+ RG_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
482
+
483
+ memcpy((void *)type, (const void *)src, RG_SIZE(*src));
484
+ type->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
485
+ type->members.allocator = GetNullAllocator();
486
+ type->dispose = dispose;
487
+ type->dispose_ref = Napi::Persistent(dispose_func);
488
+
489
+ // If the insert succeeds, we cannot fail anymore
490
+ if (named && !instance->types_map.TrySet(type->name, type).second) {
491
+ ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
492
+ return env.Null();
493
+ }
494
+ err_guard.Disable();
495
+
496
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
497
+ SetValueTag(instance, external, &TypeInfoMarker);
498
+
499
+ return external;
500
+ }
501
+
502
+ static Napi::Value CallFree(const Napi::CallbackInfo &info)
503
+ {
504
+ Napi::Env env = info.Env();
505
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
506
+
507
+ if (info.Length() < 1) {
508
+ ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
509
+ return env.Null();
510
+ }
511
+ if (!info[0].IsExternal() || CheckValueTag(instance, info[0], &TypeInfoMarker)) {
512
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected external", GetValueType(instance, info[0]));
513
+ return env.Null();
514
+ }
515
+
516
+ Napi::External<void> external = info[0].As<Napi::External<void>>();
517
+ void *ptr = external.Data();
518
+
519
+ free(ptr);
520
+
521
+ return env.Null();
522
+ }
523
+
385
524
  static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
386
525
  {
387
526
  Napi::Env env = info.Env();
@@ -396,7 +535,7 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
396
535
  return env.Null();
397
536
  }
398
537
 
399
- const TypeInfo *ref = ResolveType(instance, info[0]);
538
+ const TypeInfo *ref = ResolveType(info[0]);
400
539
  int64_t len = (uint16_t)info[1].As<Napi::Number>().Int64Value();
401
540
 
402
541
  if (!ref)
@@ -448,7 +587,7 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
448
587
  type->primitive = PrimitiveKind::Array;
449
588
  type->align = ref->align;
450
589
  type->size = (int16_t)(len * ref->size);
451
- type->ref = ref;
590
+ type->ref.type = ref;
452
591
  type->hint = hint;
453
592
 
454
593
  Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
@@ -476,7 +615,7 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
476
615
 
477
616
  func->name = DuplicateString(name.ToString().Utf8Value().c_str(), &instance->str_alloc).ptr;
478
617
 
479
- func->ret.type = ResolveType(instance, ret);
618
+ func->ret.type = ResolveType(ret);
480
619
  if (!func->ret.type)
481
620
  return false;
482
621
  if (func->ret.type->primitive == PrimitiveKind::Array) {
@@ -503,12 +642,13 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
503
642
  for (uint32_t j = 0; j < parameters_len; j++) {
504
643
  ParameterInfo param = {};
505
644
 
506
- param.type = ResolveType(instance, parameters[j], &param.directions);
645
+ param.type = ResolveType(parameters[j], &param.directions);
507
646
  if (!param.type)
508
647
  return false;
509
648
  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);
649
+ param.type->primitive == PrimitiveKind::Array ||
650
+ param.type->primitive == PrimitiveKind::Prototype) {
651
+ ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
512
652
  return false;
513
653
  }
514
654
 
@@ -573,12 +713,12 @@ static Napi::Value CreateCallbackType(const Napi::CallbackInfo &info)
573
713
 
574
714
  type->name = func->name;
575
715
 
576
- type->primitive = PrimitiveKind::Callback;
716
+ type->primitive = PrimitiveKind::Prototype;
577
717
  type->align = alignof(void *);
578
718
  type->size = RG_SIZE(void *);
579
- type->proto = func;
719
+ type->ref.proto = func;
580
720
 
581
- instance->types_map.Set(type);
721
+ instance->types_map.Set(type->name, type);
582
722
 
583
723
  Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
584
724
  SetValueTag(instance, external, &TypeInfoMarker);
@@ -586,17 +726,50 @@ static Napi::Value CreateCallbackType(const Napi::CallbackInfo &info)
586
726
  return external;
587
727
  }
588
728
 
589
- static Napi::Value GetTypeSize(const Napi::CallbackInfo &info)
729
+ static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
590
730
  {
591
731
  Napi::Env env = info.Env();
592
732
  InstanceData *instance = env.GetInstanceData<InstanceData>();
593
733
 
734
+ if (info.Length() < 2) {
735
+ ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
736
+ return env.Null();
737
+ }
738
+ if (!info[0].IsString()) {
739
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
740
+ return env.Null();
741
+ }
742
+
743
+ std::string name = info[0].As<Napi::String>();
744
+ const char *alias = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
745
+
746
+ const TypeInfo *type = ResolveType(info[1]);
747
+ if (!type)
748
+ return env.Null();
749
+
750
+ std::pair<const TypeInfo **, bool> ret = instance->types_map.TrySet(alias, type);
751
+
752
+ if (!ret.second) {
753
+ ThrowError<Napi::Error>(env, "Type name '%1' already exists", alias);
754
+ return env.Null();
755
+ }
756
+
757
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
758
+ SetValueTag(instance, external, &TypeInfoMarker);
759
+
760
+ return external;
761
+ }
762
+
763
+ static Napi::Value GetTypeSize(const Napi::CallbackInfo &info)
764
+ {
765
+ Napi::Env env = info.Env();
766
+
594
767
  if (info.Length() < 1) {
595
768
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
596
769
  return env.Null();
597
770
  }
598
771
 
599
- const TypeInfo *type = ResolveType(instance, info[0]);
772
+ const TypeInfo *type = ResolveType(info[0]);
600
773
  if (!type)
601
774
  return env.Null();
602
775
 
@@ -606,20 +779,39 @@ static Napi::Value GetTypeSize(const Napi::CallbackInfo &info)
606
779
  static Napi::Value GetTypeAlign(const Napi::CallbackInfo &info)
607
780
  {
608
781
  Napi::Env env = info.Env();
609
- InstanceData *instance = env.GetInstanceData<InstanceData>();
610
782
 
611
783
  if (info.Length() < 1) {
612
784
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
613
785
  return env.Null();
614
786
  }
615
787
 
616
- const TypeInfo *type = ResolveType(instance, info[0]);
788
+ const TypeInfo *type = ResolveType(info[0]);
617
789
  if (!type)
618
790
  return env.Null();
619
791
 
620
792
  return Napi::Number::New(env, type->align);
621
793
  }
622
794
 
795
+ static Napi::Value GetResolvedType(const Napi::CallbackInfo &info)
796
+ {
797
+ Napi::Env env = info.Env();
798
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
799
+
800
+ if (info.Length() < 1) {
801
+ ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
802
+ return env.Null();
803
+ }
804
+
805
+ const TypeInfo *type = ResolveType(info[0]);
806
+ if (!type)
807
+ return env.Null();
808
+
809
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
810
+ SetValueTag(instance, external, &TypeInfoMarker);
811
+
812
+ return external;
813
+ }
814
+
623
815
  static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
624
816
  {
625
817
  Napi::Env env = info.Env();
@@ -630,12 +822,62 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
630
822
  return env.Null();
631
823
  }
632
824
 
633
- const TypeInfo *type = ResolveType(instance, info[0]);
825
+ const TypeInfo *type = ResolveType(info[0]);
634
826
  if (!type)
635
827
  return env.Null();
828
+
636
829
  if (type->defn.IsEmpty()) {
637
- ThrowError<Napi::TypeError>(env, "Definition of type %1 is not available", type->name);
638
- return env.Null();
830
+ Napi::Object defn = Napi::Object::New(env);
831
+
832
+ defn.Set("name", Napi::String::New(env, type->name));
833
+ defn.Set("primitive", PrimitiveKindNames[(int)type->primitive]);
834
+ defn.Set("size", Napi::Number::New(env, (double)type->size));
835
+ defn.Set("alignment", Napi::Number::New(env, (double)type->align));
836
+
837
+ switch (type->primitive) {
838
+ case PrimitiveKind::Void:
839
+ case PrimitiveKind::Bool:
840
+ case PrimitiveKind::Int8:
841
+ case PrimitiveKind::UInt8:
842
+ case PrimitiveKind::Int16:
843
+ case PrimitiveKind::UInt16:
844
+ case PrimitiveKind::Int32:
845
+ case PrimitiveKind::UInt32:
846
+ case PrimitiveKind::Int64:
847
+ case PrimitiveKind::UInt64:
848
+ case PrimitiveKind::String:
849
+ case PrimitiveKind::String16:
850
+ case PrimitiveKind::Float32:
851
+ case PrimitiveKind::Float64:
852
+ case PrimitiveKind::Prototype:
853
+ case PrimitiveKind::Callback: {} break;
854
+
855
+ case PrimitiveKind::Array: {
856
+ uint32_t len = type->size / type->ref.type->size;
857
+ defn.Set("length", Napi::Number::New(env, (double)len));
858
+ } [[fallthrough]];
859
+ case PrimitiveKind::Pointer: {
860
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type->ref.type);
861
+ SetValueTag(instance, external, &TypeInfoMarker);
862
+
863
+ defn.Set("ref", external);
864
+ } break;
865
+ case PrimitiveKind::Record: {
866
+ Napi::Object members = Napi::Object::New(env);
867
+
868
+ for (const RecordMember &member: type->members) {
869
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)member.type);
870
+ SetValueTag(instance, external, &TypeInfoMarker);
871
+
872
+ members.Set(member.name, external);
873
+ }
874
+
875
+ defn.Set("members", members);
876
+ } break;
877
+ }
878
+
879
+ defn.Freeze();
880
+ type->defn.Reset(defn, 1);
639
881
  }
640
882
 
641
883
  return type->defn.Value();
@@ -743,12 +985,13 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
743
985
  for (Size i = func.parameters.len; i < (Size)info.Length(); i += 2) {
744
986
  ParameterInfo param = {};
745
987
 
746
- param.type = ResolveType(instance, info[i], &param.directions);
988
+ param.type = ResolveType(info[i], &param.directions);
747
989
  if (RG_UNLIKELY(!param.type))
748
990
  return env.Null();
749
991
  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]);
992
+ param.type->primitive == PrimitiveKind::Array ||
993
+ param.type->primitive == PrimitiveKind::Prototype)) {
994
+ ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", PrimitiveKindNames[(int)param.type->primitive]);
752
995
  return env.Null();
753
996
  }
754
997
 
@@ -923,7 +1166,7 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
923
1166
  uint16_t ordinal = (uint16_t)info[0].As<Napi::Number>().Uint32Value();
924
1167
 
925
1168
  func->decorated_name = nullptr;
926
- func->func = (void *)GetProcAddress((HMODULE)lib->module, (LPCSTR)ordinal);
1169
+ func->func = (void *)GetProcAddress((HMODULE)lib->module, (LPCSTR)(size_t)ordinal);
927
1170
  }
928
1171
  #else
929
1172
  if (func->decorated_name) {
@@ -1032,6 +1275,89 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
1032
1275
  return obj;
1033
1276
  }
1034
1277
 
1278
+ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
1279
+ {
1280
+ Napi::Env env = info.Env();
1281
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
1282
+
1283
+ if (info.Length() < 2) {
1284
+ ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
1285
+ return env.Null();
1286
+ }
1287
+ if (!info[0].IsFunction()) {
1288
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for func, expected function", GetValueType(instance, info[0]));
1289
+ return env.Null();
1290
+ }
1291
+
1292
+ Napi::Function func = info[0].As<Napi::Function>();
1293
+
1294
+ const TypeInfo *type = ResolveType(info[1]);
1295
+ if (!type)
1296
+ return env.Null();
1297
+ if (type->primitive != PrimitiveKind::Callback) {
1298
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected <callback> * type", type->name);
1299
+ return env.Null();
1300
+ }
1301
+
1302
+ int idx = CountTrailingZeros(~instance->registered_trampolines);
1303
+
1304
+ if (RG_UNLIKELY(idx >= MaxTrampolines)) {
1305
+ ThrowError<Napi::Error>(env, "Too many registered callbacks are in use (max = %1)", MaxTrampolines);
1306
+ return env.Null();
1307
+ }
1308
+
1309
+ instance->registered_trampolines |= 1u << idx;
1310
+ idx += MaxTrampolines;
1311
+
1312
+ TrampolineInfo *trampoline = &instance->trampolines[idx];
1313
+
1314
+ trampoline->proto = type->ref.proto;
1315
+ trampoline->func.Reset(func, 1);
1316
+ trampoline->generation = -1;
1317
+
1318
+ void *ptr = GetTrampoline(idx, type->ref.proto);
1319
+
1320
+ Napi::External<void> external = Napi::External<void>::New(env, ptr);
1321
+ SetValueTag(instance, external, type->ref.marker);
1322
+
1323
+ return external;
1324
+ }
1325
+
1326
+ static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
1327
+ {
1328
+ Napi::Env env = info.Env();
1329
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
1330
+
1331
+ if (info.Length() < 1) {
1332
+ ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
1333
+ return env.Null();
1334
+ }
1335
+ if (!info[0].IsExternal()) {
1336
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for id, expected registered callback", GetValueType(instance, info[0]));
1337
+ return env.Null();
1338
+ }
1339
+
1340
+ Napi::External<void> external = info[0].As<Napi::External<void>>();
1341
+ void *ptr = external.Data();
1342
+
1343
+ for (Size i = 0; i < MaxTrampolines; i++) {
1344
+ Size idx = i + MaxTrampolines;
1345
+
1346
+ if (!(instance->registered_trampolines & (1u << i)))
1347
+ continue;
1348
+
1349
+ const TrampolineInfo &trampoline = instance->trampolines[idx];
1350
+
1351
+ if (GetTrampoline(idx, trampoline.proto) == ptr) {
1352
+ instance->registered_trampolines &= ~(1u << i);
1353
+ return env.Null();
1354
+ }
1355
+ }
1356
+
1357
+ ThrowError<Napi::Error>(env, "Could not find matching registered callback");
1358
+ return env.Null();
1359
+ }
1360
+
1035
1361
  LibraryHolder::~LibraryHolder()
1036
1362
  {
1037
1363
  #ifdef _WIN32
@@ -1058,108 +1384,86 @@ void LibraryHolder::Unref() const
1058
1384
  }
1059
1385
  }
1060
1386
 
1061
- static void RegisterPrimitiveType(InstanceData *instance, const char *name, PrimitiveKind primitive,
1062
- int16_t size, int16_t align)
1387
+ static inline PrimitiveKind GetIntegerPrimitive(Size len, bool sign)
1388
+ {
1389
+ switch (len) {
1390
+ case 1: return sign ? PrimitiveKind::Int8 : PrimitiveKind::UInt8;
1391
+ case 2: return sign ? PrimitiveKind::Int16 : PrimitiveKind::UInt16;
1392
+ case 4: return sign ? PrimitiveKind::Int32 : PrimitiveKind::UInt32;
1393
+ case 8: return sign ? PrimitiveKind::Int64 : PrimitiveKind::UInt64;
1394
+ }
1395
+
1396
+ RG_UNREACHABLE();
1397
+ }
1398
+
1399
+ static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initializer_list<const char *> names,
1400
+ PrimitiveKind primitive, int16_t size, int16_t align, const char *ref = nullptr)
1063
1401
  {
1402
+ RG_ASSERT(names.size() > 0);
1064
1403
  RG_ASSERT(align <= size);
1065
1404
 
1405
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
1406
+
1066
1407
  TypeInfo *type = instance->types.AppendDefault();
1067
1408
 
1068
- type->name = name;
1409
+ type->name = *names.begin();
1069
1410
 
1070
1411
  type->primitive = primitive;
1071
1412
  type->size = size;
1072
1413
  type->align = align;
1073
1414
 
1074
- RG_ASSERT(!instance->types_map.Find(name));
1075
- instance->types_map.Set(type);
1076
- }
1415
+ if (ref) {
1416
+ const TypeInfo *marker = instance->types_map.FindValue(ref, nullptr);
1417
+ RG_ASSERT(marker);
1077
1418
 
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;
1419
+ type->ref.marker = marker;
1086
1420
  }
1087
1421
 
1088
- RG_UNREACHABLE();
1422
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
1423
+ SetValueTag(instance, external, &TypeInfoMarker);
1424
+
1425
+ for (const char *name: names) {
1426
+ std::pair<const TypeInfo **, bool> ret = instance->types_map.TrySet(name, type);
1427
+ RG_ASSERT(ret.second);
1428
+
1429
+ if (!EndsWith(name, "*")) {
1430
+ map.Set(name, external);
1431
+ }
1432
+ }
1089
1433
  }
1090
1434
 
1091
1435
  static Napi::Object InitBaseTypes(Napi::Env env)
1092
1436
  {
1093
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1094
-
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
1437
  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
1438
 
1152
- types.Set(type.name, external);
1439
+ RegisterPrimitiveType(env, types, {"void"}, PrimitiveKind::Void, 0, 0);
1440
+ RegisterPrimitiveType(env, types, {"bool"}, PrimitiveKind::Bool, RG_SIZE(bool), alignof(bool));
1441
+ RegisterPrimitiveType(env, types, {"int8_t", "int8"}, PrimitiveKind::Int8, 1, 1);
1442
+ RegisterPrimitiveType(env, types, {"uint8_t", "uint8"}, PrimitiveKind::UInt8, 1, 1);
1443
+ RegisterPrimitiveType(env, types, {"char"}, PrimitiveKind::Int8, 1, 1);
1444
+ RegisterPrimitiveType(env, types, {"unsigned char", "uchar"}, PrimitiveKind::UInt8, 1, 1);
1445
+ RegisterPrimitiveType(env, types, {"char16_t", "char16"}, PrimitiveKind::Int16, 2, 2);
1446
+ RegisterPrimitiveType(env, types, {"int16_t", "int16"}, PrimitiveKind::Int16, 2, 2);
1447
+ RegisterPrimitiveType(env, types, {"uint16_t", "uint16"}, PrimitiveKind::UInt16, 2, 2);
1448
+ RegisterPrimitiveType(env, types, {"short"}, PrimitiveKind::Int16, 2, 2);
1449
+ RegisterPrimitiveType(env, types, {"unsigned short", "ushort"}, PrimitiveKind::UInt16, 2, 2);
1450
+ RegisterPrimitiveType(env, types, {"int32_t", "int32"}, PrimitiveKind::Int32, 4, 4);
1451
+ RegisterPrimitiveType(env, types, {"uint32_t", "uint32"}, PrimitiveKind::UInt32, 4, 4);
1452
+ RegisterPrimitiveType(env, types, {"int"}, PrimitiveKind::Int32, 4, 4);
1453
+ RegisterPrimitiveType(env, types, {"unsigned int", "uint"}, PrimitiveKind::UInt32, 4, 4);
1454
+ RegisterPrimitiveType(env, types, {"int64_t", "int64"}, PrimitiveKind::Int64, 8, alignof(int64_t));
1455
+ RegisterPrimitiveType(env, types, {"uint64_t", "uint64"}, PrimitiveKind::UInt64, 8, alignof(int64_t));
1456
+ RegisterPrimitiveType(env, types, {"intptr_t", "intptr"}, GetIntegerPrimitive(RG_SIZE(intptr_t), true), RG_SIZE(intptr_t), alignof(intptr_t));
1457
+ RegisterPrimitiveType(env, types, {"uintptr_t", "uintptr"}, GetIntegerPrimitive(RG_SIZE(intptr_t), false), RG_SIZE(intptr_t), alignof(intptr_t));
1458
+ RegisterPrimitiveType(env, types, {"long"}, GetIntegerPrimitive(RG_SIZE(long), true), RG_SIZE(long), alignof(long));
1459
+ RegisterPrimitiveType(env, types, {"unsigned long", "ulong"}, GetIntegerPrimitive(RG_SIZE(long), false), RG_SIZE(long), alignof(long));
1460
+ RegisterPrimitiveType(env, types, {"long long", "longlong"}, PrimitiveKind::Int64, RG_SIZE(int64_t), alignof(int64_t));
1461
+ RegisterPrimitiveType(env, types, {"unsigned long long", "ulonglong"}, PrimitiveKind::UInt64, RG_SIZE(uint64_t), alignof(uint64_t));
1462
+ RegisterPrimitiveType(env, types, {"float", "float32"}, PrimitiveKind::Float32, 4, alignof(float));
1463
+ RegisterPrimitiveType(env, types, {"double", "float64"}, PrimitiveKind::Float64, 8, alignof(double));
1464
+ RegisterPrimitiveType(env, types, {"char *", "str", "string"}, PrimitiveKind::String, RG_SIZE(void *), alignof(void *), "char");
1465
+ RegisterPrimitiveType(env, types, {"char16_t *", "char16 *", "str16", "string16"}, PrimitiveKind::String16, RG_SIZE(void *), alignof(void *), "char16_t");
1153
1466
 
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
1467
  types.Freeze();
1164
1468
 
1165
1469
  return types;
@@ -1222,9 +1526,11 @@ static void SetExports(Napi::Env env, Func func)
1222
1526
  func("pointer", Napi::Function::New(env, CreatePointerType));
1223
1527
  func("array", Napi::Function::New(env, CreateArrayType));
1224
1528
  func("callback", Napi::Function::New(env, CreateCallbackType));
1529
+ func("alias", Napi::Function::New(env, CreateTypeAlias));
1225
1530
 
1226
1531
  func("sizeof", Napi::Function::New(env, GetTypeSize));
1227
1532
  func("alignof", Napi::Function::New(env, GetTypeAlign));
1533
+ func("resolve", Napi::Function::New(env, GetResolvedType));
1228
1534
  func("introspect", Napi::Function::New(env, GetTypeDefinition));
1229
1535
 
1230
1536
  func("load", Napi::Function::New(env, LoadSharedLibrary));
@@ -1233,6 +1539,12 @@ static void SetExports(Napi::Env env, Func func)
1233
1539
  func("out", Napi::Function::New(env, MarkOut));
1234
1540
  func("inout", Napi::Function::New(env, MarkInOut));
1235
1541
 
1542
+ func("disposable", Napi::Function::New(env, CreateDisposableType));
1543
+ func("free", Napi::Function::New(env, CallFree));
1544
+
1545
+ func("register", Napi::Function::New(env, RegisterCallback));
1546
+ func("unregister", Napi::Function::New(env, UnregisterCallback));
1547
+
1236
1548
  #if defined(_WIN32)
1237
1549
  func("extension", Napi::String::New(env, ".dll"));
1238
1550
  #elif defined(__APPLE__)