@psnext/slingcli 2.4.20260526-1 → 2.4.20260527-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/bin/sling.js +4 -1
  2. package/node_modules/@aws-sdk/core/package.json +2 -2
  3. package/node_modules/@aws-sdk/credential-provider-env/package.json +2 -2
  4. package/node_modules/@aws-sdk/credential-provider-http/dist-cjs/fromHttp/fromHttp.js +12 -6
  5. package/node_modules/@aws-sdk/credential-provider-http/dist-es/fromHttp/fromHttp.js +12 -6
  6. package/node_modules/@aws-sdk/credential-provider-http/package.json +3 -2
  7. package/node_modules/@aws-sdk/credential-provider-ini/package.json +9 -9
  8. package/node_modules/@aws-sdk/credential-provider-login/package.json +3 -3
  9. package/node_modules/@aws-sdk/credential-provider-node/package.json +7 -7
  10. package/node_modules/@aws-sdk/credential-provider-process/package.json +2 -2
  11. package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/package.json +3 -3
  12. package/node_modules/@aws-sdk/credential-provider-sso/package.json +4 -4
  13. package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +3 -3
  14. package/node_modules/@aws-sdk/middleware-websocket/package.json +2 -2
  15. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/cognito-identity/index.js +1 -1
  16. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/signin/index.js +1 -1
  17. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso/index.js +1 -1
  18. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso-oidc/index.js +1 -1
  19. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sts/index.js +1 -1
  20. package/node_modules/@aws-sdk/nested-clients/package.json +3 -3
  21. package/node_modules/@aws-sdk/signature-v4-multi-region/package.json +1 -2
  22. package/node_modules/@aws-sdk/xml-builder/package.json +2 -2
  23. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +18 -24
  24. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  25. package/node_modules/@earendil-works/pi-ai/dist/cli.js +14 -0
  26. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +73 -58
  27. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +2 -1
  28. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +8 -22
  29. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +1 -1
  30. package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js +1 -1
  31. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +60 -40
  32. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +1 -1
  33. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +1 -1
  34. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js +55 -0
  35. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js +45 -69
  36. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js +1 -0
  37. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +5 -2
  38. package/node_modules/@earendil-works/pi-ai/package.json +4 -3
  39. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/file-processor.js +2 -3
  40. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +18 -12
  41. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-runtime.js +2 -1
  42. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +3 -2
  43. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +8 -2
  44. package/node_modules/@earendil-works/pi-coding-agent/dist/core/auth-storage.js +2 -1
  45. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js +18 -24
  46. package/node_modules/@earendil-works/pi-coding-agent/dist/core/export-html/index.js +8 -6
  47. package/node_modules/@earendil-works/pi-coding-agent/dist/core/export-html/template.js +6 -3
  48. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js +12 -29
  49. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +5 -1
  50. package/node_modules/@earendil-works/pi-coding-agent/dist/core/output-guard.js +52 -22
  51. package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js +63 -36
  52. package/node_modules/@earendil-works/pi-coding-agent/dist/core/prompt-templates.js +6 -20
  53. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.js +38 -31
  54. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +9 -4
  55. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +32 -24
  56. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js +6 -13
  57. package/node_modules/@earendil-works/pi-coding-agent/dist/core/skills.js +8 -22
  58. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/bash.js +54 -53
  59. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit-diff.js +8 -1
  60. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js +44 -81
  61. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/file-mutation-queue.js +27 -12
  62. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.js +2 -3
  63. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.js +3 -3
  64. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js +5 -5
  65. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/output-accumulator.js +9 -3
  66. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/path-utils.js +39 -21
  67. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js +9 -8
  68. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/truncate.js +12 -2
  69. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js +20 -35
  70. package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +5 -6
  71. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.js +1 -1
  72. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -5
  73. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +29 -4
  74. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js +1 -1
  75. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -4
  76. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js +37 -28
  77. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-client.js +64 -7
  78. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +15 -3
  79. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/clipboard-native.js +14 -8
  80. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-core.js +124 -0
  81. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-worker.js +31 -0
  82. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize.js +75 -115
  83. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/paths.js +33 -7
  84. package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +13 -26
  85. package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -6
  86. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +40 -55
  87. package/node_modules/@earendil-works/pi-tui/dist/components/input.js +2 -2
  88. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +12 -2
  89. package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.js +53 -0
  90. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +4 -1
  91. package/node_modules/@earendil-works/pi-tui/dist/terminal.js +38 -16
  92. package/node_modules/@earendil-works/pi-tui/dist/utils.js +19 -12
  93. package/node_modules/@earendil-works/pi-tui/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
  94. package/node_modules/@earendil-works/pi-tui/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
  95. package/node_modules/@earendil-works/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  96. package/node_modules/@earendil-works/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  97. package/node_modules/@earendil-works/pi-tui/package.json +3 -5
  98. package/node_modules/@smithy/node-http-handler/package.json +2 -2
  99. package/package.json +6 -6
  100. package/slingshot/index.js +246 -244
  101. package/node_modules/koffi/CHANGELOG.md +0 -1093
  102. package/node_modules/koffi/LICENSE.txt +0 -22
  103. package/node_modules/koffi/README.md +0 -43
  104. package/node_modules/koffi/build/koffi/darwin_arm64/koffi.node +0 -0
  105. package/node_modules/koffi/build/koffi/darwin_x64/koffi.node +0 -0
  106. package/node_modules/koffi/build/koffi/freebsd_arm64/koffi.node +0 -0
  107. package/node_modules/koffi/build/koffi/freebsd_ia32/koffi.node +0 -0
  108. package/node_modules/koffi/build/koffi/freebsd_x64/koffi.node +0 -0
  109. package/node_modules/koffi/build/koffi/linux_arm64/koffi.node +0 -0
  110. package/node_modules/koffi/build/koffi/linux_armhf/koffi.node +0 -0
  111. package/node_modules/koffi/build/koffi/linux_ia32/koffi.node +0 -0
  112. package/node_modules/koffi/build/koffi/linux_loong64/koffi.node +0 -0
  113. package/node_modules/koffi/build/koffi/linux_riscv64d/koffi.node +0 -0
  114. package/node_modules/koffi/build/koffi/linux_x64/koffi.node +0 -0
  115. package/node_modules/koffi/build/koffi/musl_arm64/koffi.node +0 -0
  116. package/node_modules/koffi/build/koffi/musl_x64/koffi.node +0 -0
  117. package/node_modules/koffi/build/koffi/openbsd_ia32/koffi.node +0 -0
  118. package/node_modules/koffi/build/koffi/openbsd_x64/koffi.node +0 -0
  119. package/node_modules/koffi/build/koffi/win32_arm64/koffi.exp +0 -0
  120. package/node_modules/koffi/build/koffi/win32_arm64/koffi.lib +0 -0
  121. package/node_modules/koffi/build/koffi/win32_arm64/koffi.node +0 -0
  122. package/node_modules/koffi/build/koffi/win32_ia32/koffi.exp +0 -0
  123. package/node_modules/koffi/build/koffi/win32_ia32/koffi.lib +0 -0
  124. package/node_modules/koffi/build/koffi/win32_ia32/koffi.node +0 -0
  125. package/node_modules/koffi/build/koffi/win32_x64/koffi.exp +0 -0
  126. package/node_modules/koffi/build/koffi/win32_x64/koffi.lib +0 -0
  127. package/node_modules/koffi/build/koffi/win32_x64/koffi.node +0 -0
  128. package/node_modules/koffi/doc/benchmarks.md +0 -126
  129. package/node_modules/koffi/doc/callbacks.md +0 -210
  130. package/node_modules/koffi/doc/contribute.md +0 -148
  131. package/node_modules/koffi/doc/functions.md +0 -250
  132. package/node_modules/koffi/doc/index.md +0 -61
  133. package/node_modules/koffi/doc/input.md +0 -471
  134. package/node_modules/koffi/doc/migration.md +0 -159
  135. package/node_modules/koffi/doc/misc.md +0 -180
  136. package/node_modules/koffi/doc/output.md +0 -305
  137. package/node_modules/koffi/doc/packaging.md +0 -88
  138. package/node_modules/koffi/doc/platforms.md +0 -36
  139. package/node_modules/koffi/doc/pointers.md +0 -328
  140. package/node_modules/koffi/doc/start.md +0 -118
  141. package/node_modules/koffi/doc/unions.md +0 -186
  142. package/node_modules/koffi/doc/variables.md +0 -102
  143. package/node_modules/koffi/index.d.ts +0 -288
  144. package/node_modules/koffi/index.js +0 -634
  145. package/node_modules/koffi/indirect.js +0 -533
  146. package/node_modules/koffi/lib/native/base/base.cc +0 -11015
  147. package/node_modules/koffi/lib/native/base/base.hh +0 -6003
  148. package/node_modules/koffi/lib/native/base/crc.inc +0 -2214
  149. package/node_modules/koffi/lib/native/base/crc_gen.py +0 -72
  150. package/node_modules/koffi/lib/native/base/mimetypes.inc +0 -1248
  151. package/node_modules/koffi/lib/native/base/mimetypes_gen.py +0 -58
  152. package/node_modules/koffi/lib/native/base/tower.cc +0 -821
  153. package/node_modules/koffi/lib/native/base/tower.hh +0 -81
  154. package/node_modules/koffi/lib/native/base/unicode.inc +0 -408
  155. package/node_modules/koffi/lib/native/base/unicode_gen.py +0 -152
  156. package/node_modules/koffi/package.json +0 -38
  157. package/node_modules/koffi/src/cnoke/LICENSE.txt +0 -22
  158. package/node_modules/koffi/src/cnoke/README.md +0 -99
  159. package/node_modules/koffi/src/cnoke/assets/FindCNoke.cmake +0 -127
  160. package/node_modules/koffi/src/cnoke/assets/toolchains.json +0 -126
  161. package/node_modules/koffi/src/cnoke/assets/win_delay_hook.c +0 -36
  162. package/node_modules/koffi/src/cnoke/cnoke.js +0 -170
  163. package/node_modules/koffi/src/cnoke/package.json +0 -24
  164. package/node_modules/koffi/src/cnoke/src/builder.js +0 -511
  165. package/node_modules/koffi/src/cnoke/src/index.js +0 -10
  166. package/node_modules/koffi/src/cnoke/src/tools.js +0 -407
  167. package/node_modules/koffi/src/koffi/CMakeLists.txt +0 -182
  168. package/node_modules/koffi/src/koffi/src/abi_arm32.cc +0 -1018
  169. package/node_modules/koffi/src/koffi/src/abi_arm32_asm.S +0 -169
  170. package/node_modules/koffi/src/koffi/src/abi_arm64.cc +0 -1295
  171. package/node_modules/koffi/src/koffi/src/abi_arm64_asm.S +0 -195
  172. package/node_modules/koffi/src/koffi/src/abi_arm64_asm.asm +0 -174
  173. package/node_modules/koffi/src/koffi/src/abi_loong64.cc +0 -5
  174. package/node_modules/koffi/src/koffi/src/abi_loong64_asm.S +0 -204
  175. package/node_modules/koffi/src/koffi/src/abi_riscv64.cc +0 -915
  176. package/node_modules/koffi/src/koffi/src/abi_riscv64_asm.S +0 -203
  177. package/node_modules/koffi/src/koffi/src/abi_x64_sysv.cc +0 -939
  178. package/node_modules/koffi/src/koffi/src/abi_x64_sysv_asm.S +0 -231
  179. package/node_modules/koffi/src/koffi/src/abi_x64_win.cc +0 -715
  180. package/node_modules/koffi/src/koffi/src/abi_x64_win_asm.S +0 -166
  181. package/node_modules/koffi/src/koffi/src/abi_x64_win_asm.asm +0 -192
  182. package/node_modules/koffi/src/koffi/src/abi_x86.cc +0 -860
  183. package/node_modules/koffi/src/koffi/src/abi_x86_asm.S +0 -193
  184. package/node_modules/koffi/src/koffi/src/abi_x86_asm.asm +0 -177
  185. package/node_modules/koffi/src/koffi/src/call.cc +0 -1326
  186. package/node_modules/koffi/src/koffi/src/call.hh +0 -179
  187. package/node_modules/koffi/src/koffi/src/errno.inc +0 -462
  188. package/node_modules/koffi/src/koffi/src/ffi.cc +0 -2702
  189. package/node_modules/koffi/src/koffi/src/ffi.hh +0 -354
  190. package/node_modules/koffi/src/koffi/src/init.js +0 -105
  191. package/node_modules/koffi/src/koffi/src/parser.cc +0 -220
  192. package/node_modules/koffi/src/koffi/src/parser.hh +0 -54
  193. package/node_modules/koffi/src/koffi/src/util.cc +0 -1807
  194. package/node_modules/koffi/src/koffi/src/util.hh +0 -221
  195. package/node_modules/koffi/src/koffi/src/uv.cc +0 -193
  196. package/node_modules/koffi/src/koffi/src/uv.def +0 -10
  197. package/node_modules/koffi/src/koffi/src/uv.hh +0 -40
  198. package/node_modules/koffi/src/koffi/src/win32.cc +0 -198
  199. package/node_modules/koffi/src/koffi/src/win32.hh +0 -119
  200. package/node_modules/koffi/src/koffi/tools/write_trampolines.js +0 -77
  201. package/node_modules/koffi/vendor/node-addon-api/LICENSE.md +0 -9
  202. package/node_modules/koffi/vendor/node-addon-api/README.md +0 -95
  203. package/node_modules/koffi/vendor/node-addon-api/napi-inl.deprecated.h +0 -186
  204. package/node_modules/koffi/vendor/node-addon-api/napi-inl.h +0 -7033
  205. package/node_modules/koffi/vendor/node-addon-api/napi.h +0 -3309
  206. package/node_modules/koffi/vendor/node-api-headers/LICENSE +0 -21
  207. package/node_modules/koffi/vendor/node-api-headers/README.md +0 -95
  208. package/node_modules/koffi/vendor/node-api-headers/def/js_native_api.def +0 -125
  209. package/node_modules/koffi/vendor/node-api-headers/def/node_api.def +0 -157
  210. package/node_modules/koffi/vendor/node-api-headers/include/js_native_api.h +0 -591
  211. package/node_modules/koffi/vendor/node-api-headers/include/js_native_api_types.h +0 -210
  212. package/node_modules/koffi/vendor/node-api-headers/include/node_api.h +0 -265
  213. package/node_modules/koffi/vendor/node-api-headers/include/node_api_types.h +0 -58
  214. package/node_modules/koffi/vendor/node-api-headers/include/uv/aix.h +0 -32
  215. package/node_modules/koffi/vendor/node-api-headers/include/uv/bsd.h +0 -34
  216. package/node_modules/koffi/vendor/node-api-headers/include/uv/darwin.h +0 -61
  217. package/node_modules/koffi/vendor/node-api-headers/include/uv/errno.h +0 -483
  218. package/node_modules/koffi/vendor/node-api-headers/include/uv/linux.h +0 -34
  219. package/node_modules/koffi/vendor/node-api-headers/include/uv/os390.h +0 -33
  220. package/node_modules/koffi/vendor/node-api-headers/include/uv/posix.h +0 -31
  221. package/node_modules/koffi/vendor/node-api-headers/include/uv/sunos.h +0 -44
  222. package/node_modules/koffi/vendor/node-api-headers/include/uv/threadpool.h +0 -37
  223. package/node_modules/koffi/vendor/node-api-headers/include/uv/tree.h +0 -521
  224. package/node_modules/koffi/vendor/node-api-headers/include/uv/unix.h +0 -512
  225. package/node_modules/koffi/vendor/node-api-headers/include/uv/version.h +0 -43
  226. package/node_modules/koffi/vendor/node-api-headers/include/uv/win.h +0 -698
  227. package/node_modules/koffi/vendor/node-api-headers/include/uv.h +0 -1990
@@ -1,1807 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- // SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
3
-
4
- #include "lib/native/base/base.hh"
5
- #include "call.hh"
6
- #include "ffi.hh"
7
- #include "util.hh"
8
-
9
- #include <napi.h>
10
-
11
- namespace K {
12
-
13
- // Value does not matter, the tag system uses memory addresses
14
- const napi_type_tag TypeInfoMarker = { 0x1cc449675b294374, 0xbb13a50e97dcb017 };
15
- const napi_type_tag CastMarker = { 0x77f459614a0a412f, 0x80b3dda1341dc8df };
16
- const napi_type_tag MagicUnionMarker = { 0x5eaf2245526a4c7d, 0x8c86c9ee2b96ffc8 };
17
-
18
- Napi::Function MagicUnion::InitClass(Napi::Env env, const TypeInfo *type)
19
- {
20
- K_ASSERT(type->primitive == PrimitiveKind::Union);
21
-
22
- // node-addon-api wants std::vector
23
- std::vector<Napi::ClassPropertyDescriptor<MagicUnion>> properties;
24
- properties.reserve(type->members.len);
25
-
26
- for (Size i = 0; i < type->members.len; i++) {
27
- const RecordMember &member = type->members[i];
28
-
29
- napi_property_attributes attr = (napi_property_attributes)(napi_writable | napi_enumerable);
30
- Napi::ClassPropertyDescriptor<MagicUnion> prop = InstanceAccessor(member.name, &MagicUnion::Getter,
31
- &MagicUnion::Setter, attr, (void *)i);
32
-
33
- properties.push_back(prop);
34
- }
35
-
36
- Napi::Function constructor = DefineClass(env, type->name, properties, (void *)type);
37
- return constructor;
38
- }
39
-
40
- MagicUnion::MagicUnion(const Napi::CallbackInfo &info)
41
- : Napi::ObjectWrap<MagicUnion>(info), type((const TypeInfo *)info.Data())
42
- {
43
- Napi::Env env = info.Env();
44
- InstanceData *instance = env.GetInstanceData<InstanceData>();
45
-
46
- active_symbol.Reset(instance->active_symbol.Value(), 1);
47
- }
48
-
49
- void MagicUnion::SetRaw(const uint8_t *ptr)
50
- {
51
- raw.RemoveFrom(0);
52
- raw.Append(MakeSpan(ptr, type->size));
53
-
54
- Value().Set(active_symbol.Value(), Env().Undefined());
55
- active_idx = -1;
56
- }
57
-
58
- Napi::Value MagicUnion::Getter(const Napi::CallbackInfo &info)
59
- {
60
- Size idx = (Size)info.Data();
61
- const RecordMember &member = type->members[idx];
62
-
63
- Napi::Value value;
64
-
65
- if (idx == active_idx) {
66
- value = Value().Get(active_symbol.Value());
67
- } else {
68
- Napi::Env env = info.Env();
69
-
70
- if (!raw.len) [[unlikely]] {
71
- ThrowError<Napi::Error>(env, "Cannont convert %1 union value", active_idx < 0 ? "empty" : "assigned");
72
- return env.Null();
73
- }
74
-
75
- value = Decode(env, raw.ptr, member.type);
76
-
77
- Value().Set(active_symbol.Value(), value);
78
- active_idx = idx;
79
- }
80
-
81
- K_ASSERT(!value.IsEmpty());
82
- return value;
83
- }
84
-
85
- void MagicUnion::Setter(const Napi::CallbackInfo &info, const Napi::Value &value)
86
- {
87
- Size idx = (Size)info.Data();
88
-
89
- Value().Set(active_symbol.Value(), value);
90
- active_idx = idx;
91
-
92
- raw.Clear();
93
- }
94
-
95
- static inline bool IsIdentifierStart(char c)
96
- {
97
- return IsAsciiAlpha(c) || c == '_';
98
- }
99
-
100
- static inline bool IsIdentifierChar(char c)
101
- {
102
- return IsAsciiAlphaOrDigit(c) || c == '_';
103
- }
104
-
105
- static inline Span<const char> SplitIdentifier(Span<const char> str)
106
- {
107
- Size offset = 0;
108
-
109
- if (str.len && IsIdentifierStart(str[0])) {
110
- offset++;
111
-
112
- while (offset < str.len && IsIdentifierChar(str[offset])) {
113
- offset++;
114
- }
115
- }
116
-
117
- Span<const char> token = str.Take(0, offset);
118
- return token;
119
- }
120
-
121
- int ResolveDirections(Span<const char> str)
122
- {
123
- if (str == "_In_") {
124
- return 1;
125
- } else if (str == "_Out_") {
126
- return 2;
127
- } else if (str == "_Inout_") {
128
- return 3;
129
- } else {
130
- return 0;
131
- }
132
- }
133
-
134
- const TypeInfo *ResolveType(Napi::Value value, int *out_directions)
135
- {
136
- Napi::Env env = value.Env();
137
- InstanceData *instance = env.GetInstanceData<InstanceData>();
138
-
139
- if (value.IsString()) {
140
- std::string str = value.As<Napi::String>();
141
- Span<const char> remain = str.c_str();
142
-
143
- // Quick path for known types (int, float *, etc.)
144
- const TypeInfo *type = instance->types_map.FindValue(remain.ptr, nullptr);
145
-
146
- if (!type || (type->flags & (int)TypeFlag::IsIncomplete)) {
147
- if (out_directions) {
148
- Span<const char> prefix = SplitIdentifier(remain);
149
- int directions = ResolveDirections(prefix);
150
-
151
- if (directions) {
152
- remain = remain.Take(prefix.len, remain.len - prefix.len);
153
- remain = TrimStrLeft(remain);
154
-
155
- *out_directions = directions;
156
- } else {
157
- *out_directions = 1;
158
- }
159
- }
160
-
161
- type = ResolveType(env, remain.ptr);
162
-
163
- if (!type) {
164
- if (!env.IsExceptionPending()) {
165
- ThrowError<Napi::TypeError>(env, "Unknown or invalid type name '%1'", str.c_str());
166
- }
167
- return nullptr;
168
- }
169
-
170
- // Cache for quick future access
171
- bool inserted;
172
- auto bucket = instance->types_map.InsertOrGetDefault(remain.ptr, &inserted);
173
-
174
- if (inserted) {
175
- bucket->key = DuplicateString(remain, &instance->str_alloc).ptr;
176
- bucket->value = type;
177
- }
178
- } else if (out_directions) {
179
- *out_directions = 1;
180
- }
181
-
182
- return type;
183
- } else if (CheckValueTag(value, &TypeInfoMarker)) {
184
- Napi::External<TypeInfo> external = value.As<Napi::External<TypeInfo>>();
185
- const TypeInfo *raw = external.Data();
186
-
187
- const TypeInfo *type = AlignDown(raw, 4);
188
- K_ASSERT(type);
189
-
190
- if (out_directions) {
191
- Size delta = (uint8_t *)raw - (uint8_t *)type;
192
- *out_directions = 1 + (int)delta;
193
- }
194
-
195
- return type;
196
- } else {
197
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value as type specifier, expected string or type", GetValueType(instance, value));
198
- return nullptr;
199
- }
200
- }
201
-
202
- const TypeInfo *ResolveType(Napi::Env env, Span<const char> str)
203
- {
204
- InstanceData *instance = env.GetInstanceData<InstanceData>();
205
-
206
- // Each item can be > 0 for array or 0 for a pointer
207
- LocalArray<Size, 8> arrays;
208
- uint8_t disposables = 0;
209
-
210
- Span<const char> name;
211
- Span<const char> after;
212
- {
213
- Span<const char> remain = str;
214
-
215
- // Skip initial const qualifiers
216
- remain = TrimStrLeft(remain);
217
- while (SplitIdentifier(remain) == "const") {
218
- remain = remain.Take(6, remain.len - 6);
219
- remain = TrimStrLeft(remain);
220
- }
221
- remain = TrimStrLeft(remain);
222
-
223
- after = remain;
224
-
225
- // Consume one or more identifiers (e.g. unsigned int)
226
- for (;;) {
227
- after = TrimStrLeft(after);
228
-
229
- Span<const char> token = SplitIdentifier(after);
230
- if (!token.len)
231
- break;
232
- after = after.Take(token.len, after.len - token.len);
233
- }
234
-
235
- name = TrimStr(MakeSpan(remain.ptr, after.ptr - remain.ptr));
236
- }
237
-
238
- // Consume type indirections (pointer, array, etc.)
239
- while (after.len) {
240
- if (after[0] == '*') {
241
- after = after.Take(1, after.len - 1);
242
-
243
- if (!arrays.Available()) [[unlikely]] {
244
- ThrowError<Napi::Error>(env, "Too many type indirections");
245
- return nullptr;
246
- }
247
-
248
- arrays.Append(0);
249
- } else if (after[0] == '!') {
250
- after = after.Take(1, after.len - 1);
251
- disposables |= (1u << arrays.len);
252
- } else if (after[0] == '[') {
253
- after = after.Take(1, after.len - 1);
254
-
255
- Size len = 0;
256
-
257
- after = TrimStrLeft(after);
258
- if (!ParseInt(after, &len, 0, &after) || len < 0) [[unlikely]] {
259
- ThrowError<Napi::Error>(env, "Invalid array length");
260
- return nullptr;
261
- }
262
- after = TrimStrLeft(after);
263
- if (!after.len || after[0] != ']') [[unlikely]] {
264
- ThrowError<Napi::Error>(env, "Expected ']' after array length");
265
- return nullptr;
266
- }
267
- after = after.Take(1, after.len - 1);
268
-
269
- if (!arrays.Available()) [[unlikely]] {
270
- ThrowError<Napi::Error>(env, "Too many type indirections");
271
- return nullptr;
272
- }
273
-
274
- arrays.Append(len);
275
- } else if (SplitIdentifier(after) == "const") {
276
- after = after.Take(6, after.len - 6);
277
- } else {
278
- after = TrimStrRight(after);
279
-
280
- if (after.len) [[unlikely]] {
281
- ThrowError<Napi::Error>(env, "Unexpected character '%1' in type specifier", after[0]);
282
- return nullptr;
283
- }
284
-
285
- break;
286
- }
287
-
288
- after = TrimStrLeft(after);
289
- }
290
-
291
- const TypeInfo *type = instance->types_map.FindValue(name, nullptr);
292
-
293
- if (!type) {
294
- // Try with cleaned up spaces
295
- if (name.len < 256) {
296
- LocalArray<char, 256> buf;
297
- for (Size i = 0; i < name.len; i++) {
298
- char c = name[i];
299
-
300
- if (IsAsciiWhite(c)) {
301
- buf.Append(' ');
302
- while (++i < name.len && IsAsciiWhite(name[i]));
303
- i--;
304
- } else {
305
- buf.Append(c);
306
- }
307
- }
308
-
309
- type = instance->types_map.FindValue(buf, nullptr);
310
- }
311
-
312
- if (!type)
313
- return nullptr;
314
- }
315
-
316
- for (int i = 0;; i++) {
317
- if (disposables & (1u << i)) {
318
- if (type->primitive != PrimitiveKind::Pointer &&
319
- type->primitive != PrimitiveKind::String &&
320
- type->primitive != PrimitiveKind::String16 &&
321
- type->primitive != PrimitiveKind::String32) [[unlikely]] {
322
- ThrowError<Napi::Error>(env, "Cannot create disposable type for non-pointer");
323
- return nullptr;
324
- }
325
-
326
- TypeInfo *copy = instance->types.AppendDefault();
327
-
328
- memcpy((void *)copy, (const void *)type, K_SIZE(*type));
329
- copy->name = Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.count).ptr;
330
- copy->members.allocator = GetNullAllocator();
331
-
332
- copy->dispose = [](Napi::Env env, const TypeInfo *, const void *ptr) {
333
- InstanceData *instance = env.GetInstanceData<InstanceData>();
334
-
335
- free((void *)ptr);
336
- instance->stats.disposed++;
337
- };
338
-
339
- type = copy;
340
- }
341
-
342
- if (i >= arrays.len)
343
- break;
344
- Size len = arrays[i];
345
-
346
- if (len > 0) {
347
- if (type->flags & (int)TypeFlag::IsIncomplete) [[unlikely]] {
348
- ThrowError<Napi::TypeError>(env, "Cannot make array of incomplete type");
349
- return nullptr;
350
- }
351
-
352
- if (len > instance->config.max_type_size / type->size) {
353
- ThrowError<Napi::TypeError>(env, "Array length is too high (max = %1)", instance->config.max_type_size / type->size);
354
- return nullptr;
355
- }
356
-
357
- type = MakeArrayType(instance, type, len);
358
- K_ASSERT(type);
359
- } else {
360
- K_ASSERT(!len);
361
-
362
- type = MakePointerType(instance, type);
363
- K_ASSERT(type);
364
- }
365
- }
366
-
367
- if (type->flags & (int)TypeFlag::IsIncomplete) [[unlikely]] {
368
- ThrowError<Napi::TypeError>(env, "Cannot directly use incomplete type");
369
- return nullptr;
370
- }
371
-
372
- return type;
373
- }
374
-
375
- TypeInfo *MakePointerType(InstanceData *instance, const TypeInfo *ref, int count)
376
- {
377
- K_ASSERT(count >= 1);
378
-
379
- for (int i = 0; i < count; i++) {
380
- char name_buf[256];
381
- Fmt(name_buf, "%1%2*", ref->name, EndsWith(ref->name, "*") ? "" : " ");
382
-
383
- bool inserted;
384
- auto bucket = instance->types_map.InsertOrGetDefault(name_buf, &inserted);
385
-
386
- if (inserted) {
387
- TypeInfo *type = instance->types.AppendDefault();
388
-
389
- type->name = DuplicateString(name_buf, &instance->str_alloc).ptr;
390
-
391
- if (ref->primitive != PrimitiveKind::Prototype) {
392
- type->primitive = PrimitiveKind::Pointer;
393
- type->size = K_SIZE(void *);
394
- type->align = K_SIZE(void *);
395
- type->ref.type = ref;
396
- type->hint = (ref->flags & (int)TypeFlag::HasTypedArray) ? ArrayHint::Typed : ArrayHint::Array;
397
- } else {
398
- type->primitive = PrimitiveKind::Callback;
399
- type->size = K_SIZE(void *);
400
- type->align = K_SIZE(void *);
401
- type->ref.proto = ref->ref.proto;
402
- }
403
-
404
- bucket->key = type->name;
405
- bucket->value = type;
406
- }
407
-
408
- ref = bucket->value;
409
- }
410
-
411
- return (TypeInfo *)ref;
412
- }
413
-
414
- static TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len, ArrayHint hint, bool insert)
415
- {
416
- K_ASSERT(len >= 0);
417
- K_ASSERT(len <= instance->config.max_type_size / ref->size);
418
-
419
- TypeInfo *type = instance->types.AppendDefault();
420
-
421
- type->name = Fmt(&instance->str_alloc, "%1[%2]", ref->name, len).ptr;
422
-
423
- type->primitive = PrimitiveKind::Array;
424
- type->align = ref->align;
425
- type->size = (int32_t)(len * ref->size);
426
- type->ref.type = ref;
427
- type->hint = hint;
428
-
429
- if (insert) {
430
- bool inserted;
431
- type = (TypeInfo *)*instance->types_map.InsertOrGet(type->name, type, &inserted);
432
- instance->types.RemoveLast(!inserted);
433
- }
434
-
435
- return type;
436
- }
437
-
438
- TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len)
439
- {
440
- ArrayHint hint = {};
441
-
442
- if (ref->flags & (int)TypeFlag::IsCharLike) {
443
- hint = ArrayHint::String;
444
- } else if (ref->flags & (int)TypeFlag::HasTypedArray) {
445
- hint = ArrayHint::Typed;
446
- } else {
447
- hint = ArrayHint::Array;
448
- }
449
-
450
- return MakeArrayType(instance, ref, len, hint, true);
451
- }
452
-
453
- TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len, ArrayHint hint)
454
- {
455
- return MakeArrayType(instance, ref, len, hint, false);
456
- }
457
-
458
- Napi::External<TypeInfo> WrapType(Napi::Env env, const TypeInfo *type)
459
- {
460
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
461
- SetValueTag(external, &TypeInfoMarker);
462
-
463
- return external;
464
- }
465
-
466
- bool CanPassType(const TypeInfo *type, int directions)
467
- {
468
- if (type->countedby)
469
- return false;
470
-
471
- if (directions & 2) {
472
- if (type->primitive == PrimitiveKind::Pointer)
473
- return true;
474
- if (type->primitive == PrimitiveKind::String)
475
- return true;
476
- if (type->primitive == PrimitiveKind::String16)
477
- return true;
478
- if (type->primitive == PrimitiveKind::String32)
479
- return true;
480
-
481
- return false;
482
- } else {
483
- if (type->primitive == PrimitiveKind::Void)
484
- return false;
485
- if (type->primitive == PrimitiveKind::Array)
486
- return false;
487
- if (type->primitive == PrimitiveKind::Prototype)
488
- return false;
489
- if (type->primitive == PrimitiveKind::Callback && type->ref.proto->variadic)
490
- return false;
491
-
492
- return true;
493
- }
494
- }
495
-
496
- bool CanReturnType(const TypeInfo *type)
497
- {
498
- if (type->countedby)
499
- return false;
500
-
501
- if (type->primitive == PrimitiveKind::Void && !TestStr(type->name, "void"))
502
- return false;
503
- if (type->primitive == PrimitiveKind::Array)
504
- return false;
505
- if (type->primitive == PrimitiveKind::Prototype)
506
- return false;
507
-
508
- return true;
509
- }
510
-
511
- bool CanStoreType(const TypeInfo *type)
512
- {
513
- if (type->primitive == PrimitiveKind::Void)
514
- return false;
515
- if (type->primitive == PrimitiveKind::Prototype)
516
- return false;
517
- if (type->primitive == PrimitiveKind::Callback && type->ref.proto->variadic)
518
- return false;
519
-
520
- return true;
521
- }
522
-
523
- const char *GetValueType(const InstanceData *instance, Napi::Value value)
524
- {
525
- if (CheckValueTag(value, &CastMarker)) {
526
- Napi::External<ValueCast> external = value.As<Napi::External<ValueCast>>();
527
- ValueCast *cast = external.Data();
528
-
529
- return cast->type->name;
530
- }
531
-
532
- if (CheckValueTag(value, &TypeInfoMarker))
533
- return "Type";
534
- for (const TypeInfo &type: instance->types) {
535
- if (type.ref.marker && CheckValueTag(value, type.ref.marker))
536
- return type.name;
537
- }
538
-
539
- if (value.IsArray()) {
540
- return "Array";
541
- } else if (value.IsTypedArray()) {
542
- Napi::TypedArray array = value.As<Napi::TypedArray>();
543
-
544
- switch (array.TypedArrayType()) {
545
- case napi_int8_array: return "Int8Array";
546
- case napi_uint8_array: return "Uint8Array";
547
- case napi_uint8_clamped_array: return "Uint8ClampedArray";
548
- case napi_int16_array: return "Int16Array";
549
- case napi_uint16_array: return "Uint16Array";
550
- case napi_int32_array: return "Int32Array";
551
- case napi_uint32_array: return "Uint32Array";
552
- case napi_float16_array: return "Float16Array";
553
- case napi_float32_array: return "Float32Array";
554
- case napi_float64_array: return "Float64Array";
555
- case napi_bigint64_array: return "BigInt64Array";
556
- case napi_biguint64_array: return "BigUint64Array";
557
- }
558
- } else if (value.IsArrayBuffer()) {
559
- return "ArrayBuffer";
560
- } else if (value.IsBuffer()) {
561
- return "Buffer";
562
- }
563
-
564
- switch (value.Type()) {
565
- case napi_undefined: return "Undefined";
566
- case napi_null: return "Null";
567
- case napi_boolean: return "Boolean";
568
- case napi_number: return "Number";
569
- case napi_string: return "String";
570
- case napi_symbol: return "Symbol";
571
- case napi_object: return "Object";
572
- case napi_function: return "Function";
573
- case napi_external: return "External";
574
- case napi_bigint: return "BigInt";
575
- }
576
-
577
- // This should not be possible, but who knows...
578
- return "Unknown";
579
- }
580
-
581
- void SetValueTag(Napi::Value value, const void *marker)
582
- {
583
- static_assert(K_SIZE(TypeInfo) >= 16);
584
-
585
- // We used to make a temporary tag on the stack with lower set to a constant value and
586
- // upper to the pointer address, but this broke in Node 20.12 and Node 21.6 due to ExternalWrapper
587
- // storing a pointer to the tag and not the tag value itself (which seems wrong, but anyway).
588
- //
589
- // Since this is no longer an option, we just type alias whatever marker points to to napi_type_tag.
590
- // This may seem gross, but we disable strict aliasing anyway, so as long as what marker points
591
- // to is bigger than 16 bytes and does not change, it works!
592
- // Which holds true for us: the main thing pointed to is TypeInfo, which is constant and big enough,
593
- // and the few other markers we use, such as CastMarker, are actual const napi_type_tag structs.
594
- const napi_type_tag *tag = (const napi_type_tag *)marker;
595
-
596
- napi_status status = napi_type_tag_object(value.Env(), value, tag);
597
- K_ASSERT(status == napi_ok);
598
- }
599
-
600
- bool CheckValueTag(Napi::Value value, const void *marker)
601
- {
602
- bool match = false;
603
-
604
- if (!IsNullOrUndefined(value)) {
605
- const napi_type_tag *tag = (const napi_type_tag *)marker;
606
- napi_check_object_type_tag(value.Env(), value, tag, &match);
607
- }
608
-
609
- return match;
610
- }
611
-
612
- int GetTypedArrayType(const TypeInfo *type)
613
- {
614
- switch (type->primitive) {
615
- case PrimitiveKind::Int8: return napi_int8_array;
616
- case PrimitiveKind::UInt8: return napi_uint8_array;
617
- case PrimitiveKind::Int16: return napi_int16_array;
618
- case PrimitiveKind::UInt16: return napi_uint16_array;
619
- case PrimitiveKind::Int32: return napi_int32_array;
620
- case PrimitiveKind::UInt32: return napi_uint32_array;
621
- case PrimitiveKind::Float32: return napi_float32_array;
622
- case PrimitiveKind::Float64: return napi_float64_array;
623
-
624
- default: return -1;
625
- }
626
-
627
- K_UNREACHABLE();
628
- }
629
-
630
- Napi::String MakeStringFromUTF32(Napi::Env env, const char32_t *ptr, Size len)
631
- {
632
- static const char16_t ReplacementChar = 0xFFFD;
633
-
634
- HeapArray<char16_t> buf;
635
- buf.Reserve(len * 2);
636
-
637
- for (Size i = 0; i < len; i++) {
638
- char32_t uc = ptr[i];
639
-
640
- if (uc <= 0xFFFF) {
641
- if (uc < 0xD800 || uc > 0xDFFF) {
642
- buf.Append((char16_t)uc);
643
- } else {
644
- buf.Append(ReplacementChar);
645
- }
646
- } else if (uc <= 0x10FFFF) {
647
- uc -= 0x0010000UL;
648
-
649
- buf.Append((char16_t)((uc >> 10) + 0xD800));
650
- buf.Append((char16_t)((uc & 0x3FFul) + 0xDC00));
651
- } else {
652
- buf.Append(ReplacementChar);
653
- }
654
- }
655
-
656
- Napi::String str = Napi::String::New(env, buf.ptr, buf.len);
657
- return str;
658
- }
659
-
660
- Napi::Object DecodeObject(Napi::Env env, const uint8_t *origin, const TypeInfo *type)
661
- {
662
- // We can't decode unions because we don't know which member is valid
663
- if (type->primitive == PrimitiveKind::Union) {
664
- Napi::Object wrapper = type->construct.New({}).As<Napi::Object>();
665
- SetValueTag(wrapper, &MagicUnionMarker);
666
-
667
- MagicUnion *u = MagicUnion::Unwrap(wrapper);
668
- u->SetRaw(origin);
669
-
670
- return wrapper;
671
- }
672
-
673
- Napi::Object obj = Napi::Object::New(env);
674
- DecodeObject(obj, origin, type);
675
- return obj;
676
- }
677
-
678
- static uint32_t DecodeDynamicLength(const uint8_t *origin, const RecordMember &by)
679
- {
680
- const uint8_t *src = origin + by.offset;
681
-
682
- switch (by.type->primitive) {
683
- case PrimitiveKind::Int8: {
684
- int8_t i = *(int8_t *)src;
685
- return (uint32_t)i;
686
- } break;
687
- case PrimitiveKind::UInt8: {
688
- uint8_t u = *(uint8_t *)src;
689
- return (uint32_t)u;
690
- } break;
691
- case PrimitiveKind::Int16: {
692
- int16_t i = *(int16_t *)src;
693
- return (uint32_t)i;
694
- } break;
695
- case PrimitiveKind::Int16S: {
696
- int16_t i = ReverseBytes(*(int16_t *)src);
697
- return (uint32_t)i;
698
- } break;
699
- case PrimitiveKind::UInt16: {
700
- uint16_t u = *(uint16_t *)src;
701
- return (uint32_t)u;
702
- } break;
703
- case PrimitiveKind::UInt16S: {
704
- uint16_t u = ReverseBytes(*(uint16_t *)src);
705
- return (uint32_t)u;
706
- } break;
707
- case PrimitiveKind::Int32: {
708
- int32_t i = *(int32_t *)src;
709
- return (uint32_t)i;
710
- } break;
711
- case PrimitiveKind::Int32S: {
712
- int32_t i = ReverseBytes(*(int32_t *)src);
713
- return (uint32_t)i;
714
- } break;
715
- case PrimitiveKind::UInt32: {
716
- uint32_t u = *(uint32_t *)src;
717
- return (uint32_t)u;
718
- } break;
719
- case PrimitiveKind::UInt32S: {
720
- uint32_t u = ReverseBytes(*(uint32_t *)src);
721
- return (uint32_t)u;
722
- } break;
723
- case PrimitiveKind::Int64: {
724
- int64_t i = *(int64_t *)src;
725
- return (uint32_t)i;
726
- } break;
727
- case PrimitiveKind::Int64S: {
728
- int64_t i = ReverseBytes(*(int64_t *)src);
729
- return (uint32_t)i;
730
- } break;
731
- case PrimitiveKind::UInt64: {
732
- uint64_t u = *(uint64_t *)src;
733
- return (uint32_t)u;
734
- } break;
735
- case PrimitiveKind::UInt64S: {
736
- uint64_t u = ReverseBytes(*(uint64_t *)src);
737
- return (uint32_t)u;
738
- } break;
739
-
740
- case PrimitiveKind::Void:
741
- case PrimitiveKind::Bool:
742
- case PrimitiveKind::String:
743
- case PrimitiveKind::String16:
744
- case PrimitiveKind::String32:
745
- case PrimitiveKind::Pointer:
746
- case PrimitiveKind::Callback:
747
- case PrimitiveKind::Record:
748
- case PrimitiveKind::Union:
749
- case PrimitiveKind::Array:
750
- case PrimitiveKind::Float32:
751
- case PrimitiveKind::Float64:
752
- case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
753
- }
754
-
755
- K_UNREACHABLE();
756
- }
757
-
758
- void DecodeObject(Napi::Object obj, const uint8_t *origin, const TypeInfo *type)
759
- {
760
- Napi::Env env = obj.Env();
761
-
762
- K_ASSERT(type->primitive == PrimitiveKind::Record);
763
-
764
- for (Size i = 0; i < type->members.len; i++) {
765
- const RecordMember &member = type->members[i];
766
-
767
- const uint8_t *src = origin + member.offset;
768
-
769
- switch (member.type->primitive) {
770
- case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
771
-
772
- case PrimitiveKind::Bool: {
773
- bool b = *(bool *)src;
774
- obj.Set(member.name, Napi::Boolean::New(env, b));
775
- } break;
776
- case PrimitiveKind::Int8: {
777
- double d = (double)*(int8_t *)src;
778
- obj.Set(member.name, Napi::Number::New(env, d));
779
- } break;
780
- case PrimitiveKind::UInt8: {
781
- double d = (double)*(uint8_t *)src;
782
- obj.Set(member.name, Napi::Number::New(env, d));
783
- } break;
784
- case PrimitiveKind::Int16: {
785
- double d = (double)*(int16_t *)src;
786
- obj.Set(member.name, Napi::Number::New(env, d));
787
- } break;
788
- case PrimitiveKind::Int16S: {
789
- int16_t v = *(int16_t *)src;
790
- double d = (double)ReverseBytes(v);
791
-
792
- obj.Set(member.name, Napi::Number::New(env, d));
793
- } break;
794
- case PrimitiveKind::UInt16: {
795
- double d = (double)*(uint16_t *)src;
796
- obj.Set(member.name, Napi::Number::New(env, d));
797
- } break;
798
- case PrimitiveKind::UInt16S: {
799
- uint16_t v = *(uint16_t *)src;
800
- double d = (double)ReverseBytes(v);
801
-
802
- obj.Set(member.name, Napi::Number::New(env, d));
803
- } break;
804
- case PrimitiveKind::Int32: {
805
- double d = (double)*(int32_t *)src;
806
- obj.Set(member.name, Napi::Number::New(env, d));
807
- } break;
808
- case PrimitiveKind::Int32S: {
809
- int32_t v = *(int32_t *)src;
810
- double d = (double)ReverseBytes(v);
811
-
812
- obj.Set(member.name, Napi::Number::New(env, d));
813
- } break;
814
- case PrimitiveKind::UInt32: {
815
- double d = (double)*(uint32_t *)src;
816
- obj.Set(member.name, Napi::Number::New(env, d));
817
- } break;
818
- case PrimitiveKind::UInt32S: {
819
- uint32_t v = *(uint32_t *)src;
820
- double d = (double)ReverseBytes(v);
821
-
822
- obj.Set(member.name, Napi::Number::New(env, d));
823
- } break;
824
- case PrimitiveKind::Int64: {
825
- int64_t v = *(int64_t *)src;
826
- obj.Set(member.name, NewBigInt(env, v));
827
- } break;
828
- case PrimitiveKind::Int64S: {
829
- int64_t v = ReverseBytes(*(int64_t *)src);
830
- obj.Set(member.name, NewBigInt(env, v));
831
- } break;
832
- case PrimitiveKind::UInt64: {
833
- uint64_t v = *(uint64_t *)src;
834
- obj.Set(member.name, NewBigInt(env, v));
835
- } break;
836
- case PrimitiveKind::UInt64S: {
837
- uint64_t v = ReverseBytes(*(uint64_t *)src);
838
- obj.Set(member.name, NewBigInt(env, v));
839
- } break;
840
- case PrimitiveKind::String: {
841
- const char *str = *(const char **)src;
842
- obj.Set(member.name, str ? Napi::String::New(env, str) : env.Null());
843
-
844
- if (member.type->dispose) {
845
- member.type->dispose(env, member.type, str);
846
- }
847
- } break;
848
- case PrimitiveKind::String16: {
849
- const char16_t *str16 = *(const char16_t **)src;
850
- obj.Set(member.name, str16 ? Napi::String::New(env, str16) : env.Null());
851
-
852
- if (member.type->dispose) {
853
- member.type->dispose(env, member.type, str16);
854
- }
855
- } break;
856
- case PrimitiveKind::String32: {
857
- const char32_t *str32 = *(const char32_t **)src;
858
- obj.Set(member.name, str32 ? MakeStringFromUTF32(env, str32) : env.Null());
859
- } break;
860
- case PrimitiveKind::Pointer:
861
- case PrimitiveKind::Callback: {
862
- void *ptr2 = *(void **)src;
863
-
864
- if (member.countedby >= 0) {
865
- const RecordMember &by = type->members[member.countedby];
866
- uint32_t len = DecodeDynamicLength(origin, by);
867
-
868
- Napi::Value value = DecodeArray(env, (const uint8_t *)ptr2, member.type, len);
869
- obj.Set(member.name, value);
870
- } else if (ptr2) {
871
- Napi::External<void> external = Napi::External<void>::New(env, ptr2);
872
- SetValueTag(external, member.type->ref.marker);
873
-
874
- obj.Set(member.name, external);
875
- } else {
876
- obj.Set(member.name, env.Null());
877
- }
878
-
879
- if (member.type->dispose) {
880
- member.type->dispose(env, member.type, ptr2);
881
- }
882
- } break;
883
- case PrimitiveKind::Record:
884
- case PrimitiveKind::Union: {
885
- Napi::Object obj2 = DecodeObject(env, src, member.type);
886
- obj.Set(member.name, obj2);
887
- } break;
888
- case PrimitiveKind::Array: {
889
- if (member.countedby >= 0) {
890
- const RecordMember &by = type->members[member.countedby];
891
-
892
- uint32_t len = DecodeDynamicLength(origin, by);
893
- uint32_t max = member.type->size / member.type->ref.type->size;
894
-
895
- // Silently truncate result
896
- len = std::min(len, max);
897
-
898
- Napi::Value value = DecodeArray(env, src, member.type, len);
899
- obj.Set(member.name, value);
900
- } else {
901
- Napi::Value value = DecodeArray(env, src, member.type);
902
- obj.Set(member.name, value);
903
- }
904
- } break;
905
- case PrimitiveKind::Float32: {
906
- float f = *(float *)src;
907
- obj.Set(member.name, Napi::Number::New(env, (double)f));
908
- } break;
909
- case PrimitiveKind::Float64: {
910
- double d = *(double *)src;
911
- obj.Set(member.name, Napi::Number::New(env, d));
912
- } break;
913
-
914
- case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
915
- }
916
- }
917
- }
918
-
919
- Napi::Value DecodeArray(Napi::Env env, const uint8_t *origin, const TypeInfo *type, uint32_t len)
920
- {
921
- Size offset = 0;
922
-
923
- #define POP_ARRAY(SetCode) \
924
- do { \
925
- Napi::Array array = Napi::Array::New(env); \
926
- \
927
- for (uint32_t i = 0; i < len; i++) { \
928
- offset = AlignLen(offset, type->ref.type->align); \
929
- \
930
- const uint8_t *src = origin + offset; \
931
- \
932
- SetCode \
933
- \
934
- offset += type->ref.type->size; \
935
- } \
936
- \
937
- return array; \
938
- } while (false)
939
- #define POP_NUMBER_ARRAY(TypedArrayType, CType) \
940
- do { \
941
- if (type->hint == ArrayHint::Array) { \
942
- POP_ARRAY({ \
943
- double d = (double)*(CType *)src; \
944
- array.Set(i, Napi::Number::New(env, d)); \
945
- }); \
946
- } else { \
947
- Napi::TypedArrayType array = Napi::TypedArrayType::New(env, len); \
948
- Span<uint8_t> buffer = MakeSpan((uint8_t *)array.ArrayBuffer().Data(), (Size)len * K_SIZE(CType)); \
949
- \
950
- DecodeBuffer(buffer, origin, type->ref.type); \
951
- \
952
- return array; \
953
- } \
954
- } while (false)
955
- #define POP_NUMBER_ARRAY_SWAP(TypedArrayType, CType) \
956
- do { \
957
- if (type->hint == ArrayHint::Array) { \
958
- POP_ARRAY({ \
959
- CType v = *(CType *)src; \
960
- double d = (double)ReverseBytes(v); \
961
- array.Set(i, Napi::Number::New(env, d)); \
962
- }); \
963
- } else { \
964
- Napi::TypedArrayType array = Napi::TypedArrayType::New(env, len); \
965
- Span<uint8_t> buffer = MakeSpan((uint8_t *)array.ArrayBuffer().Data(), (Size)len * K_SIZE(CType)); \
966
- \
967
- DecodeBuffer(buffer, origin, type->ref.type); \
968
- \
969
- return array; \
970
- } \
971
- } while (false)
972
-
973
- switch (type->ref.type->primitive) {
974
- case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
975
-
976
- case PrimitiveKind::Bool: {
977
- POP_ARRAY({
978
- bool b = *(bool *)src;
979
- array.Set(i, Napi::Boolean::New(env, b));
980
- });
981
- } break;
982
- case PrimitiveKind::Int8: {
983
- if (type->hint == ArrayHint::String) {
984
- const char *ptr = (const char *)origin;
985
- size_t count = strnlen(ptr, (size_t)len);
986
-
987
- Napi::String str = Napi::String::New(env, ptr, count);
988
- return str;
989
- }
990
-
991
- POP_NUMBER_ARRAY(Int8Array, int8_t);
992
- } break;
993
- case PrimitiveKind::UInt8: { POP_NUMBER_ARRAY(Uint8Array, uint8_t); } break;
994
- case PrimitiveKind::Int16: {
995
- if (type->hint == ArrayHint::String) {
996
- const char16_t *ptr = (const char16_t *)origin;
997
- Size count = NullTerminatedLength(ptr, len);
998
-
999
- Napi::String str = Napi::String::New(env, ptr, count);
1000
- return str;
1001
- }
1002
-
1003
- POP_NUMBER_ARRAY(Int16Array, int16_t);
1004
- } break;
1005
- case PrimitiveKind::Int16S: { POP_NUMBER_ARRAY_SWAP(Int16Array, int16_t); } break;
1006
- case PrimitiveKind::UInt16: { POP_NUMBER_ARRAY(Uint16Array, uint16_t); } break;
1007
- case PrimitiveKind::UInt16S: { POP_NUMBER_ARRAY_SWAP(Uint16Array, uint16_t); } break;
1008
- case PrimitiveKind::Int32: {
1009
- if (type->hint == ArrayHint::String) {
1010
- const char32_t *ptr = (const char32_t *)origin;
1011
- Size count = NullTerminatedLength(ptr, len);
1012
-
1013
- Napi::String str = MakeStringFromUTF32(env, ptr, count);
1014
- return str;
1015
- }
1016
-
1017
- POP_NUMBER_ARRAY(Int32Array, int32_t);
1018
- } break;
1019
- case PrimitiveKind::Int32S: { POP_NUMBER_ARRAY_SWAP(Int32Array, int32_t); } break;
1020
- case PrimitiveKind::UInt32: { POP_NUMBER_ARRAY(Uint32Array, uint32_t); } break;
1021
- case PrimitiveKind::UInt32S: { POP_NUMBER_ARRAY_SWAP(Uint32Array, uint32_t); } break;
1022
- case PrimitiveKind::Int64: {
1023
- POP_ARRAY({
1024
- int64_t v = *(int64_t *)src;
1025
- array.Set(i, NewBigInt(env, v));
1026
- });
1027
- } break;
1028
- case PrimitiveKind::Int64S: {
1029
- POP_ARRAY({
1030
- int64_t v = ReverseBytes(*(int64_t *)src);
1031
- array.Set(i, NewBigInt(env, v));
1032
- });
1033
- } break;
1034
- case PrimitiveKind::UInt64: {
1035
- POP_ARRAY({
1036
- uint64_t v = *(uint64_t *)src;
1037
- array.Set(i, NewBigInt(env, v));
1038
- });
1039
- } break;
1040
- case PrimitiveKind::UInt64S: {
1041
- POP_ARRAY({
1042
- uint64_t v = ReverseBytes(*(uint64_t *)src);
1043
- array.Set(i, NewBigInt(env, v));
1044
- });
1045
- } break;
1046
- case PrimitiveKind::String: {
1047
- POP_ARRAY({
1048
- const char *str = *(const char **)src;
1049
- array.Set(i, str ? Napi::String::New(env, str) : env.Null());
1050
- });
1051
- } break;
1052
- case PrimitiveKind::String16: {
1053
- POP_ARRAY({
1054
- const char16_t *str16 = *(const char16_t **)src;
1055
- array.Set(i, str16 ? Napi::String::New(env, str16) : env.Null());
1056
- });
1057
- } break;
1058
- case PrimitiveKind::String32: {
1059
- POP_ARRAY({
1060
- const char32_t *str32 = *(const char32_t **)src;
1061
- array.Set(i, str32 ? MakeStringFromUTF32(env, str32) : env.Null());
1062
- });
1063
- } break;
1064
- case PrimitiveKind::Pointer:
1065
- case PrimitiveKind::Callback: {
1066
- POP_ARRAY({
1067
- void *ptr2 = *(void **)src;
1068
-
1069
- if (ptr2) {
1070
- Napi::External<void> external = Napi::External<void>::New(env, ptr2);
1071
- SetValueTag(external, type->ref.type->ref.marker);
1072
-
1073
- array.Set(i, external);
1074
- } else {
1075
- array.Set(i, env.Null());
1076
- }
1077
- });
1078
- } break;
1079
- case PrimitiveKind::Record:
1080
- case PrimitiveKind::Union: {
1081
- POP_ARRAY({
1082
- Napi::Object obj = DecodeObject(env, src, type->ref.type);
1083
- array.Set(i, obj);
1084
- });
1085
- } break;
1086
- case PrimitiveKind::Array: {
1087
- POP_ARRAY({
1088
- Napi::Value value = DecodeArray(env, src, type->ref.type);
1089
- array.Set(i, value);
1090
- });
1091
- } break;
1092
- case PrimitiveKind::Float32: { POP_NUMBER_ARRAY(Float32Array, float); } break;
1093
- case PrimitiveKind::Float64: { POP_NUMBER_ARRAY(Float64Array, double); } break;
1094
-
1095
- case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
1096
- }
1097
-
1098
- #undef POP_NUMBER_ARRAY_SWAP
1099
- #undef POP_NUMBER_ARRAY
1100
- #undef POP_ARRAY
1101
-
1102
- K_UNREACHABLE();
1103
- }
1104
-
1105
- Napi::Value DecodeArray(Napi::Env env, const uint8_t *origin, const TypeInfo *type)
1106
- {
1107
- K_ASSERT(type->primitive == PrimitiveKind::Array);
1108
-
1109
- uint32_t len = type->size / type->ref.type->size;
1110
- return DecodeArray(env, origin, type, len);
1111
- }
1112
-
1113
- void DecodeNormalArray(Napi::Array array, const uint8_t *origin, const TypeInfo *ref)
1114
- {
1115
- Napi::Env env = array.Env();
1116
-
1117
- K_ASSERT(array.IsArray());
1118
-
1119
- Size offset = 0;
1120
- uint32_t len = array.Length();
1121
-
1122
- #define POP_ARRAY(SetCode) \
1123
- do { \
1124
- for (uint32_t i = 0; i < len; i++) { \
1125
- offset = AlignLen(offset, ref->align); \
1126
- \
1127
- const uint8_t *src = origin + offset; \
1128
- \
1129
- SetCode \
1130
- \
1131
- offset += ref->size; \
1132
- } \
1133
- } while (false)
1134
- #define POP_NUMBER_ARRAY(CType) \
1135
- do { \
1136
- POP_ARRAY({ \
1137
- double d = (double)*(CType *)src; \
1138
- array.Set(i, Napi::Number::New(env, d)); \
1139
- }); \
1140
- } while (false)
1141
- #define POP_NUMBER_ARRAY_SWAP(CType) \
1142
- do { \
1143
- POP_ARRAY({ \
1144
- CType v = *(CType *)src; \
1145
- double d = (double)ReverseBytes(v); \
1146
- array.Set(i, Napi::Number::New(env, d)); \
1147
- }); \
1148
- } while (false)
1149
-
1150
- switch (ref->primitive) {
1151
- case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
1152
-
1153
- case PrimitiveKind::Bool: {
1154
- POP_ARRAY({
1155
- bool b = *(bool *)src;
1156
- array.Set(i, Napi::Boolean::New(env, b));
1157
- });
1158
- } break;
1159
- case PrimitiveKind::Int8: { POP_NUMBER_ARRAY(int8_t); } break;
1160
- case PrimitiveKind::UInt8: { POP_NUMBER_ARRAY(uint8_t); } break;
1161
- case PrimitiveKind::Int16: { POP_NUMBER_ARRAY(int16_t); } break;
1162
- case PrimitiveKind::Int16S: { POP_NUMBER_ARRAY_SWAP(int16_t); } break;
1163
- case PrimitiveKind::UInt16: { POP_NUMBER_ARRAY(uint16_t); } break;
1164
- case PrimitiveKind::UInt16S: { POP_NUMBER_ARRAY_SWAP(uint16_t); } break;
1165
- case PrimitiveKind::Int32: { POP_NUMBER_ARRAY(int32_t); } break;
1166
- case PrimitiveKind::Int32S: { POP_NUMBER_ARRAY_SWAP(int32_t); } break;
1167
- case PrimitiveKind::UInt32: { POP_NUMBER_ARRAY(uint32_t); } break;
1168
- case PrimitiveKind::UInt32S: { POP_NUMBER_ARRAY_SWAP(uint32_t); } break;
1169
- case PrimitiveKind::Int64: {
1170
- POP_ARRAY({
1171
- int64_t v = *(int64_t *)src;
1172
- array.Set(i, NewBigInt(env, v));
1173
- });
1174
- } break;
1175
- case PrimitiveKind::Int64S: {
1176
- POP_ARRAY({
1177
- int64_t v = ReverseBytes(*(int64_t *)src);
1178
- array.Set(i, NewBigInt(env, v));
1179
- });
1180
- } break;
1181
- case PrimitiveKind::UInt64: {
1182
- POP_ARRAY({
1183
- uint64_t v = *(uint64_t *)src;
1184
- array.Set(i, NewBigInt(env, v));
1185
- });
1186
- } break;
1187
- case PrimitiveKind::UInt64S: {
1188
- POP_ARRAY({
1189
- uint64_t v = ReverseBytes(*(uint64_t *)src);
1190
- array.Set(i, NewBigInt(env, v));
1191
- });
1192
- } break;
1193
- case PrimitiveKind::String: {
1194
- POP_ARRAY({
1195
- const char *str = *(const char **)src;
1196
- array.Set(i, str ? Napi::String::New(env, str) : env.Null());
1197
-
1198
- if (ref->dispose) {
1199
- ref->dispose(env, ref, str);
1200
- }
1201
- });
1202
- } break;
1203
- case PrimitiveKind::String16: {
1204
- POP_ARRAY({
1205
- const char16_t *str16 = *(const char16_t **)src;
1206
- array.Set(i, str16 ? Napi::String::New(env, str16) : env.Null());
1207
-
1208
- if (ref->dispose) {
1209
- ref->dispose(env, ref, str16);
1210
- }
1211
- });
1212
- } break;
1213
- case PrimitiveKind::String32: {
1214
- POP_ARRAY({
1215
- const char32_t *str32 = *(const char32_t **)src;
1216
- array.Set(i, str32 ? MakeStringFromUTF32(env, str32) : env.Null());
1217
-
1218
- if (ref->dispose) {
1219
- ref->dispose(env, ref, str32);
1220
- }
1221
- });
1222
- } break;
1223
- case PrimitiveKind::Pointer:
1224
- case PrimitiveKind::Callback: {
1225
- POP_ARRAY({
1226
- void *ptr2 = *(void **)src;
1227
-
1228
- if (ptr2) {
1229
- Napi::External<void> external = Napi::External<void>::New(env, ptr2);
1230
- SetValueTag(external, ref->ref.marker);
1231
-
1232
- array.Set(i, external);
1233
- } else {
1234
- array.Set(i, env.Null());
1235
- }
1236
-
1237
- if (ref->dispose) {
1238
- ref->dispose(env, ref, ptr2);
1239
- }
1240
- });
1241
- } break;
1242
- case PrimitiveKind::Record:
1243
- case PrimitiveKind::Union: {
1244
- POP_ARRAY({
1245
- Napi::Object obj = DecodeObject(env, src, ref);
1246
- array.Set(i, obj);
1247
- });
1248
- } break;
1249
- case PrimitiveKind::Array: {
1250
- POP_ARRAY({
1251
- Napi::Value value = DecodeArray(env, src, ref);
1252
- array.Set(i, value);
1253
- });
1254
- } break;
1255
- case PrimitiveKind::Float32: { POP_NUMBER_ARRAY(float); } break;
1256
- case PrimitiveKind::Float64: { POP_NUMBER_ARRAY(double); } break;
1257
-
1258
- case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
1259
- }
1260
-
1261
- #undef POP_NUMBER_ARRAY_SWAP
1262
- #undef POP_NUMBER_ARRAY
1263
- #undef POP_ARRAY
1264
- }
1265
-
1266
- void DecodeBuffer(Span<uint8_t> buffer, const uint8_t *origin, const TypeInfo *ref)
1267
- {
1268
- // Go fast brrrrr!
1269
- MemCpy(buffer.ptr, origin, (size_t)buffer.len);
1270
-
1271
- #define SWAP(CType) \
1272
- do { \
1273
- CType *data = (CType *)buffer.ptr; \
1274
- Size len = buffer.len / K_SIZE(CType); \
1275
- \
1276
- for (Size i = 0; i < len; i++) { \
1277
- data[i] = ReverseBytes(data[i]); \
1278
- } \
1279
- } while (false)
1280
-
1281
- if (ref->primitive == PrimitiveKind::Int16S || ref->primitive == PrimitiveKind::UInt16S) {
1282
- SWAP(uint16_t);
1283
- } else if (ref->primitive == PrimitiveKind::Int32S || ref->primitive == PrimitiveKind::UInt32S) {
1284
- SWAP(uint32_t);
1285
- } else if (ref->primitive == PrimitiveKind::Int64S || ref->primitive == PrimitiveKind::UInt64S) {
1286
- SWAP(uint64_t);
1287
- }
1288
-
1289
- #undef SWAP
1290
- }
1291
-
1292
- Napi::Value Decode(Napi::Value value, Size offset, const TypeInfo *type, const Size *len)
1293
- {
1294
- Napi::Env env = value.Env();
1295
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1296
-
1297
- const uint8_t *ptr = nullptr;
1298
-
1299
- if (value.IsExternal()) {
1300
- Napi::External<void> external = value.As<Napi::External<void>>();
1301
- ptr = (const uint8_t *)external.Data();
1302
- } else if (IsRawBuffer(value)) {
1303
- Span<uint8_t> buffer = GetRawBuffer(value);
1304
-
1305
- if (offset < 0) [[unlikely]] {
1306
- ThrowError<Napi::Error>(env, "Offset must be >= 0");
1307
- return env.Null();
1308
- }
1309
- if (buffer.len - offset < type->size) [[unlikely]] {
1310
- ThrowError<Napi::Error>(env, "Expected buffer with size superior or equal to type %1 (%2 bytes)",
1311
- type->name, type->size + offset);
1312
- return env.Null();
1313
- }
1314
-
1315
- ptr = (const uint8_t *)buffer.ptr;
1316
- } else {
1317
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for variable, expected external or TypedArray", GetValueType(instance, value));
1318
- return env.Null();
1319
- }
1320
-
1321
- if (!ptr)
1322
- return env.Null();
1323
- ptr += offset;
1324
-
1325
- Napi::Value ret = Decode(env, ptr, type, len);
1326
- return ret;
1327
- }
1328
-
1329
- Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, const Size *len)
1330
- {
1331
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1332
-
1333
- if (len && type->primitive != PrimitiveKind::String &&
1334
- type->primitive != PrimitiveKind::String16 &&
1335
- type->primitive != PrimitiveKind::String32 &&
1336
- type->primitive != PrimitiveKind::Prototype) {
1337
- if (*len >= 0) {
1338
- type = MakeArrayType(instance, type, *len);
1339
- } else {
1340
- switch (type->primitive) {
1341
- case PrimitiveKind::Int8:
1342
- case PrimitiveKind::UInt8: {
1343
- Size count = strlen((const char *)ptr);
1344
- type = MakeArrayType(instance, type, count);
1345
- } break;
1346
- case PrimitiveKind::Int16:
1347
- case PrimitiveKind::UInt16: {
1348
- Size count = NullTerminatedLength((const char16_t *)ptr, K_SIZE_MAX);
1349
- type = MakeArrayType(instance, type, count);
1350
- } break;
1351
- case PrimitiveKind::Int32:
1352
- case PrimitiveKind::UInt32: {
1353
- Size count = NullTerminatedLength((const char32_t *)ptr, K_SIZE_MAX);
1354
- type = MakeArrayType(instance, type, count);
1355
- } break;
1356
-
1357
- case PrimitiveKind::Pointer: {
1358
- Size count = NullTerminatedLength((const void **)ptr, K_SIZE_MAX);
1359
- type = MakeArrayType(instance, type, count);
1360
- } break;
1361
-
1362
- default: {
1363
- ThrowError<Napi::TypeError>(env, "Cannot determine null-terminated length for type %1", type->name);
1364
- return env.Null();
1365
- } break;
1366
- }
1367
- }
1368
- }
1369
-
1370
- #define RETURN_INT(Type, NewCall) \
1371
- do { \
1372
- Type v = *(Type *)ptr; \
1373
- return NewCall(env, v); \
1374
- } while (false)
1375
- #define RETURN_INT_SWAP(Type, NewCall) \
1376
- do { \
1377
- Type v = ReverseBytes(*(Type *)ptr); \
1378
- return NewCall(env, v); \
1379
- } while (false)
1380
-
1381
- switch (type->primitive) {
1382
- case PrimitiveKind::Void: {
1383
- ThrowError<Napi::TypeError>(env, "Cannot decode value of type %1", type->name);
1384
- return env.Null();
1385
- } break;
1386
-
1387
- case PrimitiveKind::Bool: {
1388
- bool v = *(bool *)ptr;
1389
- return Napi::Boolean::New(env, v);
1390
- } break;
1391
- case PrimitiveKind::Int8: { RETURN_INT(int8_t, Napi::Number::New); } break;
1392
- case PrimitiveKind::UInt8: { RETURN_INT(uint8_t, Napi::Number::New); } break;
1393
- case PrimitiveKind::Int16: { RETURN_INT(int16_t, Napi::Number::New); } break;
1394
- case PrimitiveKind::Int16S: { RETURN_INT_SWAP(int16_t, Napi::Number::New); } break;
1395
- case PrimitiveKind::UInt16: { RETURN_INT(uint16_t, Napi::Number::New); } break;
1396
- case PrimitiveKind::UInt16S: { RETURN_INT_SWAP(uint16_t, Napi::Number::New); } break;
1397
- case PrimitiveKind::Int32: { RETURN_INT(int32_t, Napi::Number::New); } break;
1398
- case PrimitiveKind::Int32S: { RETURN_INT_SWAP(int32_t, Napi::Number::New); } break;
1399
- case PrimitiveKind::UInt32: { RETURN_INT(uint32_t, Napi::Number::New); } break;
1400
- case PrimitiveKind::UInt32S: { RETURN_INT_SWAP(uint32_t, Napi::Number::New); } break;
1401
- case PrimitiveKind::Int64: { RETURN_INT(int64_t, NewBigInt); } break;
1402
- case PrimitiveKind::Int64S: { RETURN_INT_SWAP(int64_t, NewBigInt); } break;
1403
- case PrimitiveKind::UInt64: { RETURN_INT(uint64_t, NewBigInt); } break;
1404
- case PrimitiveKind::UInt64S: { RETURN_INT_SWAP(uint64_t, NewBigInt); } break;
1405
- case PrimitiveKind::String: {
1406
- if (len) {
1407
- const char *str = *(const char **)ptr;
1408
- return str ? Napi::String::New(env, str, *len) : env.Null();
1409
- } else {
1410
- const char *str = *(const char **)ptr;
1411
- return str ? Napi::String::New(env, str) : env.Null();
1412
- }
1413
- } break;
1414
- case PrimitiveKind::String16: {
1415
- if (len) {
1416
- const char16_t *str16 = *(const char16_t **)ptr;
1417
- return str16 ? Napi::String::New(env, str16, *len) : env.Null();
1418
- } else {
1419
- const char16_t *str16 = *(const char16_t **)ptr;
1420
- return str16 ? Napi::String::New(env, str16) : env.Null();
1421
- }
1422
- } break;
1423
- case PrimitiveKind::String32: {
1424
- if (len) {
1425
- const char32_t *str32 = *(const char32_t **)ptr;
1426
- return str32 ? MakeStringFromUTF32(env, str32, *len) : env.Null();
1427
- } else {
1428
- const char32_t *str32 = *(const char32_t **)ptr;
1429
- return str32 ? MakeStringFromUTF32(env, str32) : env.Null();
1430
- }
1431
- } break;
1432
- case PrimitiveKind::Pointer:
1433
- case PrimitiveKind::Callback: {
1434
- void *ptr2 = *(void **)ptr;
1435
- return ptr2 ? Napi::External<void>::New(env, ptr2, [](Napi::Env, void *) {}) : env.Null();
1436
- } break;
1437
- case PrimitiveKind::Record:
1438
- case PrimitiveKind::Union: {
1439
- Napi::Object obj = DecodeObject(env, ptr, type);
1440
- return obj;
1441
- } break;
1442
- case PrimitiveKind::Array: {
1443
- Napi::Value array = DecodeArray(env, ptr, type);
1444
- return array;
1445
- } break;
1446
- case PrimitiveKind::Float32: {
1447
- float f = *(float *)ptr;
1448
- return Napi::Number::New(env, f);
1449
- } break;
1450
- case PrimitiveKind::Float64: {
1451
- double d = *(double *)ptr;
1452
- return Napi::Number::New(env, d);
1453
- } break;
1454
-
1455
- case PrimitiveKind::Prototype: {
1456
- const FunctionInfo *proto = type->ref.proto;
1457
- K_ASSERT(!proto->variadic);
1458
- K_ASSERT(!proto->lib);
1459
-
1460
- FunctionInfo *func = new FunctionInfo();
1461
- K_DEFER { func->Unref(); };
1462
-
1463
- memcpy((void *)func, proto, K_SIZE(*proto));
1464
- memset((void *)&func->parameters, 0, K_SIZE(func->parameters));
1465
- func->parameters = proto->parameters;
1466
-
1467
- func->name = "<anonymous>";
1468
- func->native = (void *)ptr;
1469
-
1470
- // Fix back parameter offset
1471
- for (ParameterInfo &param: func->parameters) {
1472
- param.offset -= 2;
1473
- }
1474
- func->required_parameters -= 2;
1475
-
1476
- Napi::Function wrapper = WrapFunction(env, func);
1477
- return wrapper;
1478
- } break;
1479
- }
1480
-
1481
- #undef RETURN_BIGINT
1482
- #undef RETURN_INT
1483
-
1484
- return env.Null();
1485
- }
1486
-
1487
- bool Encode(Napi::Value ref, Size offset, Napi::Value value, const TypeInfo *type, const Size *len)
1488
- {
1489
- Napi::Env env = ref.Env();
1490
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1491
-
1492
- uint8_t *ptr = nullptr;
1493
-
1494
- if (ref.IsExternal()) {
1495
- Napi::External<void> external = ref.As<Napi::External<void>>();
1496
- ptr = (uint8_t *)external.Data();
1497
- } else if (IsRawBuffer(ref)) {
1498
- Span<uint8_t> buffer = GetRawBuffer(ref);
1499
-
1500
- if (offset < 0) [[unlikely]] {
1501
- ThrowError<Napi::Error>(env, "Offset must be >= 0");
1502
- return env.Null();
1503
- }
1504
- if (buffer.len - offset < type->size) [[unlikely]] {
1505
- ThrowError<Napi::Error>(env, "Expected buffer with size superior or equal to type %1 (%2 bytes)",
1506
- type->name, type->size + offset);
1507
- return env.Null();
1508
- }
1509
-
1510
- ptr = (uint8_t *)buffer.ptr;
1511
- } else {
1512
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for reference, expected external or TypedArray", GetValueType(instance, ref));
1513
- return env.Null();
1514
- }
1515
-
1516
- if (!ptr) [[unlikely]] {
1517
- ThrowError<Napi::Error>(env, "Cannot encode data in NULL pointer");
1518
- return env.Null();
1519
- }
1520
- ptr += offset;
1521
-
1522
- return Encode(env, ptr, value, type, len);
1523
- }
1524
-
1525
- bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *type, const Size *len)
1526
- {
1527
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1528
-
1529
- if (len && type->primitive != PrimitiveKind::String &&
1530
- type->primitive != PrimitiveKind::String16 &&
1531
- type->primitive != PrimitiveKind::String32 &&
1532
- type->primitive != PrimitiveKind::Prototype) {
1533
- if (*len < 0) [[unlikely]] {
1534
- ThrowError<Napi::TypeError>(env, "Automatic (negative) length is only supported when decoding");
1535
- return env.Null();
1536
- }
1537
-
1538
- type = MakeArrayType(instance, type, *len);
1539
- }
1540
-
1541
- InstanceMemory mem = {};
1542
- CallData call(env, instance, &mem);
1543
-
1544
- #define PUSH_INTEGER(CType) \
1545
- do { \
1546
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
1547
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
1548
- return false; \
1549
- } \
1550
- \
1551
- CType v = GetNumber<CType>(value); \
1552
- *(CType *)origin = v; \
1553
- } while (false)
1554
- #define PUSH_INTEGER_SWAP(CType) \
1555
- do { \
1556
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
1557
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
1558
- return false; \
1559
- } \
1560
- \
1561
- CType v = GetNumber<CType>(value); \
1562
- *(CType *)origin = ReverseBytes(v); \
1563
- } while (false)
1564
-
1565
- switch (type->primitive) {
1566
- case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
1567
-
1568
- case PrimitiveKind::Bool: {
1569
- if (!value.IsBoolean()) [[unlikely]] {
1570
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
1571
- return false;
1572
- }
1573
-
1574
- bool b = value.As<Napi::Boolean>();
1575
- *(bool *)origin = b;
1576
- } break;
1577
- case PrimitiveKind::Int8: { PUSH_INTEGER(int8_t); } break;
1578
- case PrimitiveKind::UInt8: { PUSH_INTEGER(uint8_t); } break;
1579
- case PrimitiveKind::Int16: { PUSH_INTEGER(int16_t); } break;
1580
- case PrimitiveKind::Int16S: { PUSH_INTEGER_SWAP(int16_t); } break;
1581
- case PrimitiveKind::UInt16: { PUSH_INTEGER(uint16_t); } break;
1582
- case PrimitiveKind::UInt16S: { PUSH_INTEGER_SWAP(uint16_t); } break;
1583
- case PrimitiveKind::Int32: { PUSH_INTEGER(int32_t); } break;
1584
- case PrimitiveKind::Int32S: { PUSH_INTEGER_SWAP(int32_t); } break;
1585
- case PrimitiveKind::UInt32: { PUSH_INTEGER(uint32_t); } break;
1586
- case PrimitiveKind::UInt32S: { PUSH_INTEGER_SWAP(uint32_t); } break;
1587
- case PrimitiveKind::Int64: { PUSH_INTEGER(int64_t); } break;
1588
- case PrimitiveKind::Int64S: { PUSH_INTEGER_SWAP(int64_t); } break;
1589
- case PrimitiveKind::UInt64: { PUSH_INTEGER(uint64_t); } break;
1590
- case PrimitiveKind::UInt64S: { PUSH_INTEGER_SWAP(uint64_t); } break;
1591
- case PrimitiveKind::String: {
1592
- const char *str;
1593
- if (!call.PushString(value, 1, &str)) [[unlikely]]
1594
- return false;
1595
- *(const char **)origin = str;
1596
- } break;
1597
- case PrimitiveKind::String16: {
1598
- const char16_t *str16;
1599
- if (!call.PushString16(value, 1, &str16)) [[unlikely]]
1600
- return false;
1601
- *(const char16_t **)origin = str16;
1602
- } break;
1603
- case PrimitiveKind::String32: {
1604
- const char32_t *str32;
1605
- if (!call.PushString32(value, 1, &str32)) [[unlikely]]
1606
- return false;
1607
- *(const char32_t **)origin = str32;
1608
- } break;
1609
- case PrimitiveKind::Pointer: {
1610
- void *ptr;
1611
- if (!call.PushPointer(value, type, 1, &ptr)) [[unlikely]]
1612
- return false;
1613
- *(void **)origin = ptr;
1614
- } break;
1615
- case PrimitiveKind::Record:
1616
- case PrimitiveKind::Union: {
1617
- if (!IsObject(value)) [[unlikely]] {
1618
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
1619
- return false;
1620
- }
1621
-
1622
- Napi::Object obj = value.As<Napi::Object>();
1623
-
1624
- if (!call.PushObject(obj, type, origin))
1625
- return false;
1626
- } break;
1627
- case PrimitiveKind::Array: {
1628
- if (value.IsArray()) {
1629
- Napi::Array array = value.As<Napi::Array>();
1630
- if (!call.PushNormalArray(array, type, type->size, origin))
1631
- return false;
1632
- } else if (IsRawBuffer(value)) {
1633
- Span<const uint8_t> buffer = GetRawBuffer(value);
1634
- call.PushBuffer(buffer, type, origin);
1635
- } else if (value.IsString()) {
1636
- if (!call.PushStringArray(value, type, origin))
1637
- return false;
1638
- } else {
1639
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected array", GetValueType(instance, value));
1640
- return false;
1641
- }
1642
- } break;
1643
- case PrimitiveKind::Float32: {
1644
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
1645
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
1646
- return false;
1647
- }
1648
-
1649
- float f = GetNumber<float>(value);
1650
- *(float *)origin = f;
1651
- } break;
1652
- case PrimitiveKind::Float64: {
1653
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
1654
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
1655
- return false;
1656
- }
1657
-
1658
- double d = GetNumber<double>(value);
1659
- *(double *)origin = d;
1660
- } break;
1661
- case PrimitiveKind::Callback: {
1662
- void *ptr;
1663
-
1664
- if (value.IsFunction()) {
1665
- ThrowError<Napi::Error>(env, "Cannot encode non-registered callback");
1666
- return false;
1667
- } else if (CheckValueTag(value, type->ref.marker)) {
1668
- ptr = value.As<Napi::External<void>>().Data();
1669
- } else if (IsNullOrUndefined(value)) {
1670
- ptr = nullptr;
1671
- } else {
1672
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
1673
- return false;
1674
- }
1675
-
1676
- *(void **)origin = ptr;
1677
- } break;
1678
-
1679
- case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
1680
- }
1681
-
1682
- #undef PUSH_INTEGER_SWAP
1683
- #undef PUSH_INTEGER
1684
-
1685
- // Keep memory around if any was allocated
1686
- if (call.alloc.IsUsed()) {
1687
- BlockAllocator *copy = instance->encode_map.FindValue(origin, nullptr);
1688
-
1689
- if (!copy) {
1690
- copy = instance->encode_allocators.AppendDefault();
1691
- instance->encode_map.Set(origin, copy);
1692
- }
1693
-
1694
- std::swap(call.alloc, *copy);
1695
- }
1696
-
1697
- return true;
1698
- }
1699
-
1700
- Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
1701
- {
1702
- Napi::Function wrapper;
1703
- if (func->variadic) {
1704
- Napi::Function::Callback call = TranslateVariadicCall;
1705
- wrapper = Napi::Function::New(env, call, func->name, (void *)func->Ref());
1706
- } else {
1707
- Napi::Function::Callback call = TranslateNormalCall;
1708
- wrapper = Napi::Function::New(env, call, func->name, (void *)func->Ref());
1709
- }
1710
- wrapper.AddFinalizer([](Napi::Env, FunctionInfo *func) { func->Unref(); }, (FunctionInfo *)func);
1711
-
1712
- if (!func->variadic) {
1713
- Napi::Function::Callback call = TranslateAsyncCall;
1714
- Napi::Function async = Napi::Function::New(env, call, func->name, (void *)func->Ref());
1715
-
1716
- async.AddFinalizer([](Napi::Env, FunctionInfo *func) { func->Unref(); }, (FunctionInfo *)func);
1717
- wrapper.Set("async", async);
1718
- }
1719
-
1720
- // Create info object
1721
- {
1722
- Napi::Object meta = Napi::Object::New(env);
1723
- Napi::Array arguments = Napi::Array::New(env, func->parameters.len);
1724
-
1725
- meta.Set("name", Napi::String::New(env, func->name));
1726
- meta.Set("arguments", arguments);
1727
- meta.Set("result", WrapType(env, func->ret.type));
1728
-
1729
- for (Size i = 0; i < func->parameters.len; i++) {
1730
- const ParameterInfo &param = func->parameters[i];
1731
- arguments.Set((uint32_t)i, WrapType(env, param.type));
1732
- }
1733
-
1734
- wrapper.Set("info", meta);
1735
- }
1736
-
1737
- return wrapper;
1738
- }
1739
-
1740
- bool DetectCallConvention(Span<const char> name, CallConvention *out_convention)
1741
- {
1742
- if (name == "__cdecl") {
1743
- *out_convention = CallConvention::Cdecl;
1744
- return true;
1745
- } else if (name == "__stdcall") {
1746
- *out_convention = CallConvention::Stdcall;
1747
- return true;
1748
- } else if (name == "__fastcall") {
1749
- *out_convention = CallConvention::Fastcall;
1750
- return true;
1751
- } else if (name == "__thiscall") {
1752
- *out_convention = CallConvention::Thiscall;
1753
- return true;
1754
- } else {
1755
- return false;
1756
- }
1757
- }
1758
-
1759
- static int AnalyseFlatRec(const TypeInfo *type, int offset, int count, FunctionRef<void(const TypeInfo *type, int offset, int count)> func)
1760
- {
1761
- if (type->primitive == PrimitiveKind::Record) {
1762
- for (int i = 0; i < count; i++) {
1763
- for (const RecordMember &member: type->members) {
1764
- offset = AnalyseFlatRec(member.type, offset, 1, func);
1765
- }
1766
- }
1767
- } else if (type->primitive == PrimitiveKind::Union) {
1768
- for (int i = 0; i < count; i++) {
1769
- for (const RecordMember &member: type->members) {
1770
- AnalyseFlatRec(member.type, offset, 1, func);
1771
- }
1772
- }
1773
- offset += count;
1774
- } else if (type->primitive == PrimitiveKind::Array) {
1775
- count *= type->size / type->ref.type->size;
1776
- offset = AnalyseFlatRec(type->ref.type, offset, count, func);
1777
- } else {
1778
- func(type, offset, count);
1779
- offset += count;
1780
- }
1781
-
1782
- return offset;
1783
- }
1784
-
1785
- int AnalyseFlat(const TypeInfo *type, FunctionRef<void(const TypeInfo *type, int offset, int count)> func)
1786
- {
1787
- return AnalyseFlatRec(type, 0, 1, func);
1788
- }
1789
-
1790
- void DumpMemory(const char *type, Span<const uint8_t> bytes)
1791
- {
1792
- if (bytes.len) {
1793
- PrintLn(StdErr, "%1 at 0x%2 (%3):", type, bytes.ptr, FmtMemSize(bytes.len));
1794
-
1795
- for (const uint8_t *ptr = bytes.begin(); ptr < bytes.end();) {
1796
- Print(StdErr, " [0x%1 %2 %3] ", FmtHex((uintptr_t)ptr, 16),
1797
- FmtInt((ptr - bytes.begin()) / sizeof(void *), 4, ' '),
1798
- FmtInt(ptr - bytes.begin(), 4, ' '));
1799
- for (int i = 0; ptr < bytes.end() && i < (int)sizeof(void *); i++, ptr++) {
1800
- Print(StdErr, " %1", FmtHex(*ptr, 2));
1801
- }
1802
- PrintLn(StdErr);
1803
- }
1804
- }
1805
- }
1806
-
1807
- }