koffi 2.14.1 → 2.15.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 (113) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/build/koffi/darwin_arm64/koffi.node +0 -0
  3. package/build/koffi/darwin_x64/koffi.node +0 -0
  4. package/build/koffi/freebsd_arm64/koffi.node +0 -0
  5. package/build/koffi/freebsd_ia32/koffi.node +0 -0
  6. package/build/koffi/freebsd_x64/koffi.node +0 -0
  7. package/build/koffi/linux_arm64/koffi.node +0 -0
  8. package/build/koffi/linux_armhf/koffi.node +0 -0
  9. package/build/koffi/linux_ia32/koffi.node +0 -0
  10. package/build/koffi/linux_loong64/koffi.node +0 -0
  11. package/build/koffi/linux_riscv64d/koffi.node +0 -0
  12. package/build/koffi/linux_x64/koffi.node +0 -0
  13. package/build/koffi/musl_arm64/koffi.node +0 -0
  14. package/build/koffi/musl_x64/koffi.node +0 -0
  15. package/build/koffi/openbsd_ia32/koffi.node +0 -0
  16. package/build/koffi/openbsd_x64/koffi.node +0 -0
  17. package/build/koffi/win32_arm64/koffi.node +0 -0
  18. package/build/koffi/win32_ia32/koffi.node +0 -0
  19. package/build/koffi/win32_x64/koffi.node +0 -0
  20. package/doc/assets.ini +2 -1
  21. package/doc/build.sh +9 -0
  22. package/doc/pages/404.md +17 -0
  23. package/doc/pages/index.md +5 -3
  24. package/doc/pages/misc.md +18 -11
  25. package/doc/pages.ini +4 -0
  26. package/doc/static/highlight.js +2 -14
  27. package/doc/static/koffi.css +3 -15
  28. package/doc/static/print.css +2 -14
  29. package/doc/templates/code.html +1 -2
  30. package/doc/templates/page.html +1 -2
  31. package/index.d.ts +29 -24
  32. package/index.js +9 -9
  33. package/indirect.js +9 -9
  34. package/{src/core → lib/native}/base/base.cc +1137 -674
  35. package/{src/core → lib/native}/base/base.hh +362 -195
  36. package/{src/core → lib/native}/base/crc.inc +2 -20
  37. package/lib/native/base/crc_gen.py +72 -0
  38. package/{src/core → lib/native}/base/mimetypes.inc +2 -20
  39. package/{src/core → lib/native}/base/mimetypes_gen.py +2 -21
  40. package/lib/native/base/tower.cc +821 -0
  41. package/lib/native/base/tower.hh +81 -0
  42. package/{src/core → lib/native}/base/unicode.inc +2 -20
  43. package/{src/core → lib/native}/base/unicode_gen.py +4 -41
  44. package/package.json +2 -2
  45. package/src/cnoke/assets/FindCNoke.cmake +24 -30
  46. package/src/cnoke/assets/win_delay_hook.c +6 -20
  47. package/src/cnoke/cnoke.js +2 -21
  48. package/src/cnoke/src/builder.js +51 -66
  49. package/src/cnoke/src/index.js +2 -20
  50. package/src/cnoke/src/tools.js +2 -20
  51. package/src/koffi/CMakeLists.txt +30 -23
  52. package/src/koffi/cmake/raylib.cmake +5 -22
  53. package/src/koffi/cmake/sqlite3.cmake +2 -20
  54. package/src/koffi/src/abi_arm32.cc +7 -25
  55. package/src/koffi/src/abi_arm32_asm.S +2 -20
  56. package/src/koffi/src/abi_arm64.cc +7 -25
  57. package/src/koffi/src/abi_arm64_asm.S +2 -20
  58. package/src/koffi/src/abi_arm64_asm.asm +2 -20
  59. package/src/koffi/src/abi_loong64.cc +2 -20
  60. package/src/koffi/src/abi_loong64_asm.S +2 -20
  61. package/src/koffi/src/abi_riscv64.cc +7 -25
  62. package/src/koffi/src/abi_riscv64_asm.S +2 -20
  63. package/src/koffi/src/abi_x64_sysv.cc +7 -25
  64. package/src/koffi/src/abi_x64_sysv_asm.S +2 -20
  65. package/src/koffi/src/abi_x64_win.cc +12 -30
  66. package/src/koffi/src/abi_x64_win_asm.S +162 -0
  67. package/src/koffi/src/abi_x64_win_asm.asm +2 -20
  68. package/src/koffi/src/abi_x86.cc +7 -25
  69. package/src/koffi/src/abi_x86_asm.S +2 -20
  70. package/src/koffi/src/abi_x86_asm.asm +2 -20
  71. package/src/koffi/src/call.cc +25 -45
  72. package/src/koffi/src/call.hh +3 -21
  73. package/src/koffi/src/errno.inc +2 -20
  74. package/src/koffi/src/ffi.cc +64 -63
  75. package/src/koffi/src/ffi.hh +15 -30
  76. package/src/koffi/src/init.js +2 -20
  77. package/src/koffi/src/parser.cc +13 -27
  78. package/src/koffi/src/parser.hh +3 -21
  79. package/src/koffi/src/trampolines/armasm.inc +0 -21
  80. package/src/koffi/src/trampolines/gnu.inc +0 -21
  81. package/src/koffi/src/trampolines/masm32.inc +0 -21
  82. package/src/koffi/src/trampolines/masm64.inc +0 -21
  83. package/src/koffi/src/trampolines/prototypes.inc +0 -21
  84. package/src/koffi/src/util.cc +50 -64
  85. package/src/koffi/src/util.hh +8 -25
  86. package/src/koffi/src/uv.cc +193 -0
  87. package/src/koffi/src/uv.def +10 -0
  88. package/src/koffi/src/uv.hh +40 -0
  89. package/src/koffi/src/win32.cc +2 -20
  90. package/src/koffi/src/win32.hh +3 -21
  91. package/vendor/node-api-headers/CHANGELOG.md +22 -0
  92. package/vendor/node-api-headers/README.md +6 -17
  93. package/vendor/node-api-headers/include/js_native_api.h +3 -13
  94. package/vendor/node-api-headers/include/js_native_api_types.h +15 -0
  95. package/vendor/node-api-headers/include/node_api.h +0 -4
  96. package/vendor/node-api-headers/include/node_api_types.h +6 -0
  97. package/vendor/node-api-headers/include/uv/aix.h +32 -0
  98. package/vendor/node-api-headers/include/uv/bsd.h +34 -0
  99. package/vendor/node-api-headers/include/uv/darwin.h +61 -0
  100. package/vendor/node-api-headers/include/uv/errno.h +483 -0
  101. package/vendor/node-api-headers/include/uv/linux.h +34 -0
  102. package/vendor/node-api-headers/include/uv/os390.h +33 -0
  103. package/vendor/node-api-headers/include/uv/posix.h +31 -0
  104. package/vendor/node-api-headers/include/uv/sunos.h +44 -0
  105. package/vendor/node-api-headers/include/uv/threadpool.h +37 -0
  106. package/vendor/node-api-headers/include/uv/tree.h +521 -0
  107. package/vendor/node-api-headers/include/uv/unix.h +512 -0
  108. package/vendor/node-api-headers/include/uv/version.h +43 -0
  109. package/vendor/node-api-headers/include/uv/win.h +698 -0
  110. package/vendor/node-api-headers/include/uv.h +1990 -0
  111. package/vendor/node-api-headers/package.json +1 -1
  112. package/vendor/node-api-headers/scripts/update-headers.js +6 -0
  113. package/src/core/base/crc_gen.py +0 -109
@@ -1,24 +1,3 @@
1
- ; Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
2
- ;
3
- ; Permission is hereby granted, free of charge, to any person obtaining a copy of
4
- ; this software and associated documentation files (the “Software”), to deal in
5
- ; the Software without restriction, including without limitation the rights to use,
6
- ; copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
7
- ; Software, and to permit persons to whom the Software is furnished to do so,
8
- ; subject to the following conditions:
9
- ;
10
- ; The above copyright notice and this permission notice shall be included in all
11
- ; copies or substantial portions of the Software.
12
- ;
13
- ; THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
14
- ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
- ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
- ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
- ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
- ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
- ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
- ; OTHER DEALINGS IN THE SOFTWARE.
21
-
22
1
  public Trampoline0
23
2
  public Trampoline1
24
3
  public Trampoline2
@@ -1,24 +1,3 @@
1
- // Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
2
- //
3
- // Permission is hereby granted, free of charge, to any person obtaining a copy of
4
- // this software and associated documentation files (the “Software”), to deal in
5
- // the Software without restriction, including without limitation the rights to use,
6
- // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
7
- // Software, and to permit persons to whom the Software is furnished to do so,
8
- // subject to the following conditions:
9
- //
10
- // The above copyright notice and this permission notice shall be included in all
11
- // copies or substantial portions of the Software.
12
- //
13
- // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
14
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
- // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
- // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
- // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
- // OTHER DEALINGS IN THE SOFTWARE.
21
-
22
1
  extern "C" int Trampoline0; extern "C" int TrampolineX0;
23
2
  extern "C" int Trampoline1; extern "C" int TrampolineX1;
24
3
  extern "C" int Trampoline2; extern "C" int TrampolineX2;
@@ -1,25 +1,7 @@
1
- // Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
2
- //
3
- // Permission is hereby granted, free of charge, to any person obtaining a copy of
4
- // this software and associated documentation files (the “Software”), to deal in
5
- // the Software without restriction, including without limitation the rights to use,
6
- // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
7
- // Software, and to permit persons to whom the Software is furnished to do so,
8
- // subject to the following conditions:
9
- //
10
- // The above copyright notice and this permission notice shall be included in all
11
- // copies or substantial portions of the Software.
12
- //
13
- // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
14
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
- // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
- // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
- // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
- // OTHER DEALINGS IN THE SOFTWARE.
21
-
22
- #include "src/core/base/base.hh"
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
3
+
4
+ #include "lib/native/base/base.hh"
23
5
  #include "call.hh"
24
6
  #include "ffi.hh"
25
7
  #include "util.hh"
@@ -38,7 +20,7 @@ Napi::Function MagicUnion::InitClass(Napi::Env env, const TypeInfo *type)
38
20
  K_ASSERT(type->primitive == PrimitiveKind::Union);
39
21
 
40
22
  // node-addon-api wants std::vector
41
- std::vector<Napi::ClassPropertyDescriptor<MagicUnion>> properties;
23
+ std::vector<Napi::ClassPropertyDescriptor<MagicUnion>> properties;
42
24
  properties.reserve(type->members.len);
43
25
 
44
26
  for (Size i = 0; i < type->members.len; i++) {
@@ -61,7 +43,7 @@ MagicUnion::MagicUnion(const Napi::CallbackInfo &info)
61
43
  Napi::Env env = info.Env();
62
44
  InstanceData *instance = env.GetInstanceData<InstanceData>();
63
45
 
64
- active_symbol = instance->active_symbol;
46
+ active_symbol.Reset(instance->active_symbol.Value(), 1);
65
47
  }
66
48
 
67
49
  void MagicUnion::SetRaw(const uint8_t *ptr)
@@ -69,7 +51,7 @@ void MagicUnion::SetRaw(const uint8_t *ptr)
69
51
  raw.RemoveFrom(0);
70
52
  raw.Append(MakeSpan(ptr, type->size));
71
53
 
72
- Value().Set(active_symbol, Env().Undefined());
54
+ Value().Set(active_symbol.Value(), Env().Undefined());
73
55
  active_idx = -1;
74
56
  }
75
57
 
@@ -81,7 +63,7 @@ Napi::Value MagicUnion::Getter(const Napi::CallbackInfo &info)
81
63
  Napi::Value value;
82
64
 
83
65
  if (idx == active_idx) {
84
- value = Value().Get(active_symbol);
66
+ value = Value().Get(active_symbol.Value());
85
67
  } else {
86
68
  Napi::Env env = info.Env();
87
69
 
@@ -92,7 +74,7 @@ Napi::Value MagicUnion::Getter(const Napi::CallbackInfo &info)
92
74
 
93
75
  value = Decode(env, raw.ptr, member.type);
94
76
 
95
- Value().Set(active_symbol, value);
77
+ Value().Set(active_symbol.Value(), value);
96
78
  active_idx = idx;
97
79
  }
98
80
 
@@ -104,7 +86,7 @@ void MagicUnion::Setter(const Napi::CallbackInfo &info, const Napi::Value &value
104
86
  {
105
87
  Size idx = (Size)info.Data();
106
88
 
107
- Value().Set(active_symbol, value);
89
+ Value().Set(active_symbol.Value(), value);
108
90
  active_idx = idx;
109
91
 
110
92
  raw.Clear();
@@ -187,7 +169,7 @@ const TypeInfo *ResolveType(Napi::Value value, int *out_directions)
187
169
 
188
170
  // Cache for quick future access
189
171
  bool inserted;
190
- auto bucket = instance->types_map.TrySetDefault(remain.ptr, &inserted);
172
+ auto bucket = instance->types_map.InsertOrGetDefault(remain.ptr, &inserted);
191
173
 
192
174
  if (inserted) {
193
175
  bucket->key = DuplicateString(remain, &instance->str_alloc).ptr;
@@ -198,7 +180,7 @@ const TypeInfo *ResolveType(Napi::Value value, int *out_directions)
198
180
  }
199
181
 
200
182
  return type;
201
- } else if (CheckValueTag(instance, value, &TypeInfoMarker)) {
183
+ } else if (CheckValueTag(value, &TypeInfoMarker)) {
202
184
  Napi::External<TypeInfo> external = value.As<Napi::External<TypeInfo>>();
203
185
  const TypeInfo *raw = external.Data();
204
186
 
@@ -399,7 +381,7 @@ TypeInfo *MakePointerType(InstanceData *instance, const TypeInfo *ref, int count
399
381
  Fmt(name_buf, "%1%2*", ref->name, EndsWith(ref->name, "*") ? "" : " ");
400
382
 
401
383
  bool inserted;
402
- auto bucket = instance->types_map.TrySetDefault(name_buf, &inserted);
384
+ auto bucket = instance->types_map.InsertOrGetDefault(name_buf, &inserted);
403
385
 
404
386
  if (inserted) {
405
387
  TypeInfo *type = instance->types.AppendDefault();
@@ -446,7 +428,7 @@ static TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size
446
428
 
447
429
  if (insert) {
448
430
  bool inserted;
449
- type = (TypeInfo *)*instance->types_map.TrySet(type->name, type, &inserted);
431
+ type = (TypeInfo *)*instance->types_map.InsertOrGet(type->name, type, &inserted);
450
432
  instance->types.RemoveLast(!inserted);
451
433
  }
452
434
 
@@ -473,10 +455,10 @@ TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len, A
473
455
  return MakeArrayType(instance, ref, len, hint, false);
474
456
  }
475
457
 
476
- Napi::External<TypeInfo> WrapType(Napi::Env env, InstanceData *instance, const TypeInfo *type)
458
+ Napi::External<TypeInfo> WrapType(Napi::Env env, const TypeInfo *type)
477
459
  {
478
460
  Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
479
- SetValueTag(instance, external, &TypeInfoMarker);
461
+ SetValueTag(external, &TypeInfoMarker);
480
462
 
481
463
  return external;
482
464
  }
@@ -540,17 +522,17 @@ bool CanStoreType(const TypeInfo *type)
540
522
 
541
523
  const char *GetValueType(const InstanceData *instance, Napi::Value value)
542
524
  {
543
- if (CheckValueTag(instance, value, &CastMarker)) {
525
+ if (CheckValueTag(value, &CastMarker)) {
544
526
  Napi::External<ValueCast> external = value.As<Napi::External<ValueCast>>();
545
527
  ValueCast *cast = external.Data();
546
528
 
547
529
  return cast->type->name;
548
530
  }
549
531
 
550
- if (CheckValueTag(instance, value, &TypeInfoMarker))
532
+ if (CheckValueTag(value, &TypeInfoMarker))
551
533
  return "Type";
552
534
  for (const TypeInfo &type: instance->types) {
553
- if (type.ref.marker && CheckValueTag(instance, value, type.ref.marker))
535
+ if (type.ref.marker && CheckValueTag(value, type.ref.marker))
554
536
  return type.name;
555
537
  }
556
538
 
@@ -567,6 +549,7 @@ const char *GetValueType(const InstanceData *instance, Napi::Value value)
567
549
  case napi_uint16_array: return "Uint16Array";
568
550
  case napi_int32_array: return "Int32Array";
569
551
  case napi_uint32_array: return "Uint32Array";
552
+ case napi_float16_array: return "Float16Array";
570
553
  case napi_float32_array: return "Float32Array";
571
554
  case napi_float64_array: return "Float64Array";
572
555
  case napi_bigint64_array: return "BigInt64Array";
@@ -595,7 +578,7 @@ const char *GetValueType(const InstanceData *instance, Napi::Value value)
595
578
  return "Unknown";
596
579
  }
597
580
 
598
- void SetValueTag(const InstanceData *instance, Napi::Value value, const void *marker)
581
+ void SetValueTag(Napi::Value value, const void *marker)
599
582
  {
600
583
  static_assert(K_SIZE(TypeInfo) >= 16);
601
584
 
@@ -614,7 +597,7 @@ void SetValueTag(const InstanceData *instance, Napi::Value value, const void *ma
614
597
  K_ASSERT(status == napi_ok);
615
598
  }
616
599
 
617
- bool CheckValueTag(const InstanceData *instance, Napi::Value value, const void *marker)
600
+ bool CheckValueTag(Napi::Value value, const void *marker)
618
601
  {
619
602
  bool match = false;
620
603
 
@@ -646,25 +629,27 @@ int GetTypedArrayType(const TypeInfo *type)
646
629
 
647
630
  Napi::String MakeStringFromUTF32(Napi::Env env, const char32_t *ptr, Size len)
648
631
  {
632
+ static const char16_t ReplacementChar = 0xFFFD;
633
+
649
634
  HeapArray<char16_t> buf;
650
635
  buf.Reserve(len * 2);
651
636
 
652
637
  for (Size i = 0; i < len; i++) {
653
638
  char32_t uc = ptr[i];
654
639
 
655
- if (uc < 0xFFFF) {
640
+ if (uc <= 0xFFFF) {
656
641
  if (uc < 0xD800 || uc > 0xDFFF) {
657
642
  buf.Append((char16_t)uc);
658
643
  } else {
659
- buf.Append('?');
644
+ buf.Append(ReplacementChar);
660
645
  }
661
- } else if (uc < 0x10FFFF) {
646
+ } else if (uc <= 0x10FFFF) {
662
647
  uc -= 0x0010000UL;
663
648
 
664
649
  buf.Append((char16_t)((uc >> 10) + 0xD800));
665
650
  buf.Append((char16_t)((uc & 0x3FFul) + 0xDC00));
666
651
  } else {
667
- buf.Append('?');
652
+ buf.Append(ReplacementChar);
668
653
  }
669
654
  }
670
655
 
@@ -676,10 +661,8 @@ Napi::Object DecodeObject(Napi::Env env, const uint8_t *origin, const TypeInfo *
676
661
  {
677
662
  // We can't decode unions because we don't know which member is valid
678
663
  if (type->primitive == PrimitiveKind::Union) {
679
- InstanceData *instance = env.GetInstanceData<InstanceData>();
680
-
681
664
  Napi::Object wrapper = type->construct.New({}).As<Napi::Object>();
682
- SetValueTag(instance, wrapper, &MagicUnionMarker);
665
+ SetValueTag(wrapper, &MagicUnionMarker);
683
666
 
684
667
  MagicUnion *u = MagicUnion::Unwrap(wrapper);
685
668
  u->SetRaw(origin);
@@ -775,7 +758,6 @@ static uint32_t DecodeDynamicLength(const uint8_t *origin, const RecordMember &b
775
758
  void DecodeObject(Napi::Object obj, const uint8_t *origin, const TypeInfo *type)
776
759
  {
777
760
  Napi::Env env = obj.Env();
778
- InstanceData *instance = env.GetInstanceData<InstanceData>();
779
761
 
780
762
  K_ASSERT(type->primitive == PrimitiveKind::Record);
781
763
 
@@ -887,7 +869,7 @@ void DecodeObject(Napi::Object obj, const uint8_t *origin, const TypeInfo *type)
887
869
  obj.Set(member.name, value);
888
870
  } else if (ptr2) {
889
871
  Napi::External<void> external = Napi::External<void>::New(env, ptr2);
890
- SetValueTag(instance, external, member.type->ref.marker);
872
+ SetValueTag(external, member.type->ref.marker);
891
873
 
892
874
  obj.Set(member.name, external);
893
875
  } else {
@@ -936,7 +918,6 @@ void DecodeObject(Napi::Object obj, const uint8_t *origin, const TypeInfo *type)
936
918
 
937
919
  Napi::Value DecodeArray(Napi::Env env, const uint8_t *origin, const TypeInfo *type, uint32_t len)
938
920
  {
939
- InstanceData *instance = env.GetInstanceData<InstanceData>();
940
921
  Size offset = 0;
941
922
 
942
923
  #define POP_ARRAY(SetCode) \
@@ -1087,7 +1068,7 @@ Napi::Value DecodeArray(Napi::Env env, const uint8_t *origin, const TypeInfo *ty
1087
1068
 
1088
1069
  if (ptr2) {
1089
1070
  Napi::External<void> external = Napi::External<void>::New(env, ptr2);
1090
- SetValueTag(instance, external, type->ref.type->ref.marker);
1071
+ SetValueTag(external, type->ref.type->ref.marker);
1091
1072
 
1092
1073
  array.Set(i, external);
1093
1074
  } else {
@@ -1132,7 +1113,6 @@ Napi::Value DecodeArray(Napi::Env env, const uint8_t *origin, const TypeInfo *ty
1132
1113
  void DecodeNormalArray(Napi::Array array, const uint8_t *origin, const TypeInfo *ref)
1133
1114
  {
1134
1115
  Napi::Env env = array.Env();
1135
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1136
1116
 
1137
1117
  K_ASSERT(array.IsArray());
1138
1118
 
@@ -1247,7 +1227,7 @@ void DecodeNormalArray(Napi::Array array, const uint8_t *origin, const TypeInfo
1247
1227
 
1248
1228
  if (ptr2) {
1249
1229
  Napi::External<void> external = Napi::External<void>::New(env, ptr2);
1250
- SetValueTag(instance, external, ref->ref.marker);
1230
+ SetValueTag(external, ref->ref.marker);
1251
1231
 
1252
1232
  array.Set(i, external);
1253
1233
  } else {
@@ -1322,6 +1302,10 @@ Napi::Value Decode(Napi::Value value, Size offset, const TypeInfo *type, const S
1322
1302
  } else if (IsRawBuffer(value)) {
1323
1303
  Span<uint8_t> buffer = GetRawBuffer(value);
1324
1304
 
1305
+ if (offset < 0) [[unlikely]] {
1306
+ ThrowError<Napi::Error>(env, "Offset must be >= 0");
1307
+ return env.Null();
1308
+ }
1325
1309
  if (buffer.len - offset < type->size) [[unlikely]] {
1326
1310
  ThrowError<Napi::Error>(env, "Expected buffer with size superior or equal to type %1 (%2 bytes)",
1327
1311
  type->name, type->size + offset);
@@ -1354,12 +1338,12 @@ Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, cons
1354
1338
  type = MakeArrayType(instance, type, *len);
1355
1339
  } else {
1356
1340
  switch (type->primitive) {
1357
- case PrimitiveKind::Int8:
1341
+ case PrimitiveKind::Int8:
1358
1342
  case PrimitiveKind::UInt8: {
1359
1343
  Size count = strlen((const char *)ptr);
1360
1344
  type = MakeArrayType(instance, type, count);
1361
1345
  } break;
1362
- case PrimitiveKind::Int16:
1346
+ case PrimitiveKind::Int16:
1363
1347
  case PrimitiveKind::UInt16: {
1364
1348
  Size count = NullTerminatedLength((const char16_t *)ptr, K_SIZE_MAX);
1365
1349
  type = MakeArrayType(instance, type, count);
@@ -1513,6 +1497,10 @@ bool Encode(Napi::Value ref, Size offset, Napi::Value value, const TypeInfo *typ
1513
1497
  } else if (IsRawBuffer(ref)) {
1514
1498
  Span<uint8_t> buffer = GetRawBuffer(ref);
1515
1499
 
1500
+ if (offset < 0) [[unlikely]] {
1501
+ ThrowError<Napi::Error>(env, "Offset must be >= 0");
1502
+ return env.Null();
1503
+ }
1516
1504
  if (buffer.len - offset < type->size) [[unlikely]] {
1517
1505
  ThrowError<Napi::Error>(env, "Expected buffer with size superior or equal to type %1 (%2 bytes)",
1518
1506
  type->name, type->size + offset);
@@ -1521,7 +1509,7 @@ bool Encode(Napi::Value ref, Size offset, Napi::Value value, const TypeInfo *typ
1521
1509
 
1522
1510
  ptr = (uint8_t *)buffer.ptr;
1523
1511
  } else {
1524
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for reference, expected external or TypedArray", GetValueType(instance, value));
1512
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for reference, expected external or TypedArray", GetValueType(instance, ref));
1525
1513
  return env.Null();
1526
1514
  }
1527
1515
 
@@ -1676,7 +1664,7 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
1676
1664
  if (value.IsFunction()) {
1677
1665
  ThrowError<Napi::Error>(env, "Cannot encode non-registered callback");
1678
1666
  return false;
1679
- } else if (CheckValueTag(instance, value, type->ref.marker)) {
1667
+ } else if (CheckValueTag(value, type->ref.marker)) {
1680
1668
  ptr = value.As<Napi::External<void>>().Data();
1681
1669
  } else if (IsNullOrUndefined(value)) {
1682
1670
  ptr = nullptr;
@@ -1715,8 +1703,6 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
1715
1703
 
1716
1704
  Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
1717
1705
  {
1718
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1719
-
1720
1706
  Napi::Function wrapper;
1721
1707
  if (func->variadic) {
1722
1708
  Napi::Function::Callback call = TranslateVariadicCall;
@@ -1742,11 +1728,11 @@ Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
1742
1728
 
1743
1729
  meta.Set("name", Napi::String::New(env, func->name));
1744
1730
  meta.Set("arguments", arguments);
1745
- meta.Set("result", WrapType(env, instance, func->ret.type));
1731
+ meta.Set("result", WrapType(env, func->ret.type));
1746
1732
 
1747
1733
  for (Size i = 0; i < func->parameters.len; i++) {
1748
1734
  const ParameterInfo &param = func->parameters[i];
1749
- arguments.Set((uint32_t)i, WrapType(env, instance, param.type));
1735
+ arguments.Set((uint32_t)i, WrapType(env, param.type));
1750
1736
  }
1751
1737
 
1752
1738
  wrapper.Set("info", meta);
@@ -1811,11 +1797,11 @@ void DumpMemory(const char *type, Span<const uint8_t> bytes)
1811
1797
  PrintLn(StdErr, "%1 at 0x%2 (%3):", type, bytes.ptr, FmtMemSize(bytes.len));
1812
1798
 
1813
1799
  for (const uint8_t *ptr = bytes.begin(); ptr < bytes.end();) {
1814
- Print(StdErr, " [0x%1 %2 %3] ", FmtArg(ptr).Pad0(-16),
1815
- FmtArg((ptr - bytes.begin()) / sizeof(void *)).Pad(-4),
1816
- FmtArg(ptr - bytes.begin()).Pad(-4));
1800
+ Print(StdErr, " [0x%1 %2 %3] ", FmtInt((uintptr_t)ptr, 16),
1801
+ FmtInt((ptr - bytes.begin()) / sizeof(void *), 4, ' '),
1802
+ FmtInt(ptr - bytes.begin(), 4, ' '));
1817
1803
  for (int i = 0; ptr < bytes.end() && i < (int)sizeof(void *); i++, ptr++) {
1818
- Print(StdErr, " %1", FmtHex(*ptr).Pad0(-2));
1804
+ Print(StdErr, " %1", FmtHex(*ptr, 2));
1819
1805
  }
1820
1806
  PrintLn(StdErr);
1821
1807
  }
@@ -1,27 +1,9 @@
1
- // Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
2
- //
3
- // Permission is hereby granted, free of charge, to any person obtaining a copy of
4
- // this software and associated documentation files (the “Software”), to deal in
5
- // the Software without restriction, including without limitation the rights to use,
6
- // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
7
- // Software, and to permit persons to whom the Software is furnished to do so,
8
- // subject to the following conditions:
9
- //
10
- // The above copyright notice and this permission notice shall be included in all
11
- // copies or substantial portions of the Software.
12
- //
13
- // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
14
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
- // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
- // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
- // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
- // OTHER DEALINGS IN THE SOFTWARE.
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
21
3
 
22
4
  #pragma once
23
5
 
24
- #include "src/core/base/base.hh"
6
+ #include "lib/native/base/base.hh"
25
7
  #include "ffi.hh"
26
8
 
27
9
  #include <napi.h>
@@ -35,7 +17,7 @@ extern const napi_type_tag MagicUnionMarker;
35
17
  class MagicUnion: public Napi::ObjectWrap<MagicUnion> {
36
18
  const TypeInfo *type;
37
19
 
38
- napi_value active_symbol;
20
+ Napi::Reference<Napi::Symbol> active_symbol;
39
21
  Size active_idx = -1;
40
22
 
41
23
  HeapArray<uint8_t> raw;
@@ -94,7 +76,7 @@ TypeInfo *MakePointerType(InstanceData *instance, const TypeInfo *ref, int count
94
76
  TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len);
95
77
  TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len, ArrayHint hint);
96
78
 
97
- Napi::External<TypeInfo> WrapType(Napi::Env env, InstanceData *instance, const TypeInfo *type);
79
+ Napi::External<TypeInfo> WrapType(Napi::Env env, const TypeInfo *type);
98
80
 
99
81
  bool CanPassType(const TypeInfo *type, int directions);
100
82
  bool CanReturnType(const TypeInfo *type);
@@ -103,8 +85,8 @@ bool CanStoreType(const TypeInfo *type);
103
85
  // Can be slow, only use for error messages
104
86
  const char *GetValueType(const InstanceData *instance, Napi::Value value);
105
87
 
106
- void SetValueTag(const InstanceData *instance, Napi::Value value, const void *marker);
107
- bool CheckValueTag(const InstanceData *instance, Napi::Value value, const void *marker);
88
+ void SetValueTag(Napi::Value value, const void *marker);
89
+ bool CheckValueTag(Napi::Value value, const void *marker);
108
90
 
109
91
  static inline bool IsNullOrUndefined(Napi::Value value)
110
92
  {
@@ -138,6 +120,7 @@ static inline Span<uint8_t> GetRawBuffer(Napi::Value value)
138
120
  case napi_uint16_array: { length *= 2; } break;
139
121
  case napi_int32_array: { length *= 4; } break;
140
122
  case napi_uint32_array: { length *= 4; } break;
123
+ case napi_float16_array: { length *= 2; } break;
141
124
  case napi_float32_array: { length *= 4; } break;
142
125
  case napi_float64_array: { length *= 8; } break;
143
126
  case napi_bigint64_array: { length *= 8; } break;
@@ -0,0 +1,193 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ #include "uv.hh"
4
+ #include "util.hh"
5
+
6
+ #include <uv.h>
7
+
8
+ namespace K {
9
+
10
+ Napi::Function PollHandle::Define(Napi::Env env)
11
+ {
12
+ return DefineClass(env, "PollHandle", {
13
+ InstanceMethod("start", &PollHandle::Start),
14
+ InstanceMethod("stop", &PollHandle::Stop),
15
+ InstanceMethod("close", &PollHandle::Close),
16
+ InstanceMethod("unref", &PollHandle::Unref),
17
+ InstanceMethod("ref", &PollHandle::Ref)
18
+ });
19
+ }
20
+
21
+ PollHandle::PollHandle(const Napi::CallbackInfo &info)
22
+ : Napi::ObjectWrap<PollHandle>(info), env(info.Env())
23
+ {
24
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
25
+
26
+ if (info.Length() < 1 || !info[0].IsNumber()) {
27
+ ThrowError<Napi::Error>(env, "Expected 1 argument, got %1", info.Length());
28
+ return;
29
+ }
30
+ if (!info[0].IsNumber()) {
31
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for descriptor, expected number", GetValueType(instance, info[0]));
32
+ return;
33
+ }
34
+
35
+ int fd = info[0].As<Napi::Number>().Int32Value();
36
+
37
+ uv_loop_t *loop = nullptr;
38
+ if (napi_get_uv_event_loop(env, &loop) != napi_ok || !loop) {
39
+ ThrowError<Napi::Error>(env, "napi_get_uv_event_loop() failed");
40
+ return;
41
+ }
42
+
43
+ // We would store it inside the class, but the definition of uv_poll_t involves windows.h...
44
+ // and we won't want that on Windows. Heap allocation it is!
45
+ // Also, it may have to outlive the object, because uv_close() is asynchronous.
46
+ handle = new uv_poll_t();
47
+
48
+ if (int ret = uv_poll_init_socket(loop, handle, (uv_os_sock_t)fd); ret != 0) {
49
+ ThrowError<Napi::Error>(env, "Failed to init UV poll: %1", uv_strerror(ret));
50
+ return;
51
+ }
52
+
53
+ handle->data = this;
54
+ }
55
+
56
+ void PollHandle::Start(const Napi::CallbackInfo &info)
57
+ {
58
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
59
+
60
+ bool has_opts = (info.Length() >= 2 && info[0].IsObject());
61
+
62
+ if (info.Length() < 1u + has_opts) {
63
+ ThrowError<Napi::TypeError>(env, "Expected 1 to 2 arguments, got %1", info.Length());
64
+ return;
65
+ }
66
+ if (!info[0u + has_opts].IsFunction()) {
67
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for callback, expected function", GetValueType(instance, info[0u + has_opts]));
68
+ return;
69
+ }
70
+
71
+ int events = 0;
72
+ Napi::Function cb = info[0 + has_opts].As<Napi::Function>();
73
+
74
+ if (has_opts) {
75
+ Napi::Object opts = has_opts ? info[0].As<Napi::Object>() : Napi::Object::New(env);
76
+
77
+ events |= opts.Get("readable").ToBoolean() ? UV_READABLE : 0;
78
+ events |= opts.Get("writable").ToBoolean() ? UV_WRITABLE : 0;
79
+ events |= opts.Get("disconnect").ToBoolean() ? UV_DISCONNECT : 0;
80
+ } else {
81
+ events = UV_READABLE;
82
+ }
83
+
84
+ callback.Reset(cb, 1);
85
+
86
+ if (int ret = uv_poll_start(handle, events, &PollHandle::OnPoll); ret != 0) {
87
+ callback.Reset();
88
+ ThrowError<Napi::Error>(env, "Failed to start UV poll: %1", uv_strerror(ret));
89
+ }
90
+ }
91
+
92
+ void PollHandle::Stop(const Napi::CallbackInfo &)
93
+ {
94
+ uv_poll_stop(handle);
95
+ callback.Reset();
96
+ }
97
+
98
+ void PollHandle::Close(const Napi::CallbackInfo &)
99
+ {
100
+ Close();
101
+ callback.Reset();
102
+ }
103
+
104
+ void PollHandle::Ref(const Napi::CallbackInfo &)
105
+ {
106
+ uv_ref((uv_handle_t *)handle);
107
+ }
108
+
109
+ void PollHandle::Unref(const Napi::CallbackInfo &)
110
+ {
111
+ uv_unref((uv_handle_t *)handle);
112
+ }
113
+
114
+ void PollHandle::Close()
115
+ {
116
+ if (!handle)
117
+ return;
118
+
119
+ const auto release = [](uv_handle_t *ptr) {
120
+ uv_poll_t *handle = (uv_poll_t *)ptr;
121
+ delete handle;
122
+ };
123
+
124
+ uv_poll_stop(handle);
125
+ uv_close((uv_handle_t *)handle, release);
126
+
127
+ handle = nullptr;
128
+ }
129
+
130
+ void PollHandle::OnPoll(uv_poll_t *h, int status, int events)
131
+ {
132
+ PollHandle *poll = (PollHandle *)h->data;
133
+
134
+ if (poll->callback.IsEmpty()) [[unlikely]]
135
+ return;
136
+
137
+ Napi::Env env = poll->env;
138
+ Napi::HandleScope scope(env);
139
+
140
+ Napi::Object obj = Napi::Object::New(env);
141
+
142
+ obj.Set("readable", !!(events & UV_READABLE));
143
+ obj.Set("writable", !!(events & UV_WRITABLE));
144
+ obj.Set("disconnect", !!(events & UV_DISCONNECT));
145
+
146
+ napi_value args[] = { Napi::Number::New(env, status), obj };
147
+ poll->callback.Call(poll->Value(), K_LEN(args), args);
148
+ }
149
+
150
+ Napi::Value Poll(const Napi::CallbackInfo &info)
151
+ {
152
+ Napi::Env env = info.Env();
153
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
154
+
155
+ bool has_opts = (info.Length() >= 3 && info[1].IsObject());
156
+
157
+ if (info.Length() < 2u + has_opts) {
158
+ ThrowError<Napi::TypeError>(env, "Expected 2 to 3 arguments, got %1", info.Length());
159
+ return env.Null();
160
+ }
161
+
162
+ if (!info[0].IsNumber()) {
163
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for descriptor, expected number", GetValueType(instance, info[0]));
164
+ return env.Null();
165
+ }
166
+ if (!info[1 + has_opts].IsFunction()) {
167
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for callback, expected function", GetValueType(instance, info[1 + has_opts]));
168
+ return env.Null();
169
+ }
170
+
171
+ int fd = info[0].As<Napi::Number>().Int32Value();
172
+
173
+ Napi::Function ctor = PollHandle::Define(env);
174
+ Napi::Object inst = ctor.New({ Napi::Number::New(env, fd) });
175
+ Napi::Function start = inst.Get("start").As<Napi::Function>();
176
+
177
+ if (env.IsExceptionPending()) [[unlikely]]
178
+ return env.Null();
179
+
180
+ if (has_opts) {
181
+ Napi::Value opts = info[1];
182
+ Napi::Function cb = info[2].As<Napi::Function>();
183
+
184
+ start.Call(inst, { opts, cb });
185
+ } else {
186
+ Napi::Function cb = info[1].As<Napi::Function>();
187
+ start.Call(inst, { cb });
188
+ }
189
+
190
+ return inst;
191
+ }
192
+
193
+ }
@@ -0,0 +1,10 @@
1
+ NAME NODE.EXE
2
+ EXPORTS
3
+ uv_close
4
+ uv_ref
5
+ uv_unref
6
+ uv_strerror
7
+ uv_poll_init
8
+ uv_poll_init_socket
9
+ uv_poll_start
10
+ uv_poll_stop