@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.
- package/bin/sling.js +4 -1
- package/node_modules/@aws-sdk/core/package.json +2 -2
- package/node_modules/@aws-sdk/credential-provider-env/package.json +2 -2
- package/node_modules/@aws-sdk/credential-provider-http/dist-cjs/fromHttp/fromHttp.js +12 -6
- package/node_modules/@aws-sdk/credential-provider-http/dist-es/fromHttp/fromHttp.js +12 -6
- package/node_modules/@aws-sdk/credential-provider-http/package.json +3 -2
- package/node_modules/@aws-sdk/credential-provider-ini/package.json +9 -9
- package/node_modules/@aws-sdk/credential-provider-login/package.json +3 -3
- package/node_modules/@aws-sdk/credential-provider-node/package.json +7 -7
- package/node_modules/@aws-sdk/credential-provider-process/package.json +2 -2
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/package.json +3 -3
- package/node_modules/@aws-sdk/credential-provider-sso/package.json +4 -4
- package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +3 -3
- package/node_modules/@aws-sdk/middleware-websocket/package.json +2 -2
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/cognito-identity/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/signin/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso-oidc/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sts/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/package.json +3 -3
- package/node_modules/@aws-sdk/signature-v4-multi-region/package.json +1 -2
- package/node_modules/@aws-sdk/xml-builder/package.json +2 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +18 -24
- package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/cli.js +14 -0
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +73 -58
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +2 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +8 -22
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +60 -40
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js +55 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js +45 -69
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +5 -2
- package/node_modules/@earendil-works/pi-ai/package.json +4 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/file-processor.js +2 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +18 -12
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-runtime.js +2 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +3 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +8 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/auth-storage.js +2 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js +18 -24
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/export-html/index.js +8 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/export-html/template.js +6 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js +12 -29
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +5 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/output-guard.js +52 -22
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js +63 -36
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/prompt-templates.js +6 -20
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.js +38 -31
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +9 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +32 -24
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js +6 -13
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/skills.js +8 -22
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/bash.js +54 -53
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit-diff.js +8 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js +44 -81
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/file-mutation-queue.js +27 -12
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.js +2 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.js +3 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js +5 -5
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/output-accumulator.js +9 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/path-utils.js +39 -21
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js +9 -8
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/truncate.js +12 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js +20 -35
- package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +5 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -5
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +29 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js +37 -28
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-client.js +64 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +15 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/clipboard-native.js +14 -8
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-core.js +124 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-worker.js +31 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize.js +75 -115
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/paths.js +33 -7
- package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +13 -26
- package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -6
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +40 -55
- package/node_modules/@earendil-works/pi-tui/dist/components/input.js +2 -2
- package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +12 -2
- package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.js +53 -0
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +4 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js +38 -16
- package/node_modules/@earendil-works/pi-tui/dist/utils.js +19 -12
- package/node_modules/@earendil-works/pi-tui/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
- package/node_modules/@earendil-works/pi-tui/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
- package/node_modules/@earendil-works/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
- package/node_modules/@earendil-works/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
- package/node_modules/@earendil-works/pi-tui/package.json +3 -5
- package/node_modules/@smithy/node-http-handler/package.json +2 -2
- package/package.json +6 -6
- package/slingshot/index.js +246 -244
- package/node_modules/koffi/CHANGELOG.md +0 -1093
- package/node_modules/koffi/LICENSE.txt +0 -22
- package/node_modules/koffi/README.md +0 -43
- package/node_modules/koffi/build/koffi/darwin_arm64/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/darwin_x64/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/freebsd_arm64/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/freebsd_x64/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/linux_arm64/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/linux_armhf/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/linux_ia32/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/linux_loong64/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/linux_riscv64d/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/linux_x64/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/musl_arm64/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/musl_x64/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/openbsd_x64/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/win32_arm64/koffi.exp +0 -0
- package/node_modules/koffi/build/koffi/win32_arm64/koffi.lib +0 -0
- package/node_modules/koffi/build/koffi/win32_arm64/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/win32_ia32/koffi.exp +0 -0
- package/node_modules/koffi/build/koffi/win32_ia32/koffi.lib +0 -0
- package/node_modules/koffi/build/koffi/win32_ia32/koffi.node +0 -0
- package/node_modules/koffi/build/koffi/win32_x64/koffi.exp +0 -0
- package/node_modules/koffi/build/koffi/win32_x64/koffi.lib +0 -0
- package/node_modules/koffi/build/koffi/win32_x64/koffi.node +0 -0
- package/node_modules/koffi/doc/benchmarks.md +0 -126
- package/node_modules/koffi/doc/callbacks.md +0 -210
- package/node_modules/koffi/doc/contribute.md +0 -148
- package/node_modules/koffi/doc/functions.md +0 -250
- package/node_modules/koffi/doc/index.md +0 -61
- package/node_modules/koffi/doc/input.md +0 -471
- package/node_modules/koffi/doc/migration.md +0 -159
- package/node_modules/koffi/doc/misc.md +0 -180
- package/node_modules/koffi/doc/output.md +0 -305
- package/node_modules/koffi/doc/packaging.md +0 -88
- package/node_modules/koffi/doc/platforms.md +0 -36
- package/node_modules/koffi/doc/pointers.md +0 -328
- package/node_modules/koffi/doc/start.md +0 -118
- package/node_modules/koffi/doc/unions.md +0 -186
- package/node_modules/koffi/doc/variables.md +0 -102
- package/node_modules/koffi/index.d.ts +0 -288
- package/node_modules/koffi/index.js +0 -634
- package/node_modules/koffi/indirect.js +0 -533
- package/node_modules/koffi/lib/native/base/base.cc +0 -11015
- package/node_modules/koffi/lib/native/base/base.hh +0 -6003
- package/node_modules/koffi/lib/native/base/crc.inc +0 -2214
- package/node_modules/koffi/lib/native/base/crc_gen.py +0 -72
- package/node_modules/koffi/lib/native/base/mimetypes.inc +0 -1248
- package/node_modules/koffi/lib/native/base/mimetypes_gen.py +0 -58
- package/node_modules/koffi/lib/native/base/tower.cc +0 -821
- package/node_modules/koffi/lib/native/base/tower.hh +0 -81
- package/node_modules/koffi/lib/native/base/unicode.inc +0 -408
- package/node_modules/koffi/lib/native/base/unicode_gen.py +0 -152
- package/node_modules/koffi/package.json +0 -38
- package/node_modules/koffi/src/cnoke/LICENSE.txt +0 -22
- package/node_modules/koffi/src/cnoke/README.md +0 -99
- package/node_modules/koffi/src/cnoke/assets/FindCNoke.cmake +0 -127
- package/node_modules/koffi/src/cnoke/assets/toolchains.json +0 -126
- package/node_modules/koffi/src/cnoke/assets/win_delay_hook.c +0 -36
- package/node_modules/koffi/src/cnoke/cnoke.js +0 -170
- package/node_modules/koffi/src/cnoke/package.json +0 -24
- package/node_modules/koffi/src/cnoke/src/builder.js +0 -511
- package/node_modules/koffi/src/cnoke/src/index.js +0 -10
- package/node_modules/koffi/src/cnoke/src/tools.js +0 -407
- package/node_modules/koffi/src/koffi/CMakeLists.txt +0 -182
- package/node_modules/koffi/src/koffi/src/abi_arm32.cc +0 -1018
- package/node_modules/koffi/src/koffi/src/abi_arm32_asm.S +0 -169
- package/node_modules/koffi/src/koffi/src/abi_arm64.cc +0 -1295
- package/node_modules/koffi/src/koffi/src/abi_arm64_asm.S +0 -195
- package/node_modules/koffi/src/koffi/src/abi_arm64_asm.asm +0 -174
- package/node_modules/koffi/src/koffi/src/abi_loong64.cc +0 -5
- package/node_modules/koffi/src/koffi/src/abi_loong64_asm.S +0 -204
- package/node_modules/koffi/src/koffi/src/abi_riscv64.cc +0 -915
- package/node_modules/koffi/src/koffi/src/abi_riscv64_asm.S +0 -203
- package/node_modules/koffi/src/koffi/src/abi_x64_sysv.cc +0 -939
- package/node_modules/koffi/src/koffi/src/abi_x64_sysv_asm.S +0 -231
- package/node_modules/koffi/src/koffi/src/abi_x64_win.cc +0 -715
- package/node_modules/koffi/src/koffi/src/abi_x64_win_asm.S +0 -166
- package/node_modules/koffi/src/koffi/src/abi_x64_win_asm.asm +0 -192
- package/node_modules/koffi/src/koffi/src/abi_x86.cc +0 -860
- package/node_modules/koffi/src/koffi/src/abi_x86_asm.S +0 -193
- package/node_modules/koffi/src/koffi/src/abi_x86_asm.asm +0 -177
- package/node_modules/koffi/src/koffi/src/call.cc +0 -1326
- package/node_modules/koffi/src/koffi/src/call.hh +0 -179
- package/node_modules/koffi/src/koffi/src/errno.inc +0 -462
- package/node_modules/koffi/src/koffi/src/ffi.cc +0 -2702
- package/node_modules/koffi/src/koffi/src/ffi.hh +0 -354
- package/node_modules/koffi/src/koffi/src/init.js +0 -105
- package/node_modules/koffi/src/koffi/src/parser.cc +0 -220
- package/node_modules/koffi/src/koffi/src/parser.hh +0 -54
- package/node_modules/koffi/src/koffi/src/util.cc +0 -1807
- package/node_modules/koffi/src/koffi/src/util.hh +0 -221
- package/node_modules/koffi/src/koffi/src/uv.cc +0 -193
- package/node_modules/koffi/src/koffi/src/uv.def +0 -10
- package/node_modules/koffi/src/koffi/src/uv.hh +0 -40
- package/node_modules/koffi/src/koffi/src/win32.cc +0 -198
- package/node_modules/koffi/src/koffi/src/win32.hh +0 -119
- package/node_modules/koffi/src/koffi/tools/write_trampolines.js +0 -77
- package/node_modules/koffi/vendor/node-addon-api/LICENSE.md +0 -9
- package/node_modules/koffi/vendor/node-addon-api/README.md +0 -95
- package/node_modules/koffi/vendor/node-addon-api/napi-inl.deprecated.h +0 -186
- package/node_modules/koffi/vendor/node-addon-api/napi-inl.h +0 -7033
- package/node_modules/koffi/vendor/node-addon-api/napi.h +0 -3309
- package/node_modules/koffi/vendor/node-api-headers/LICENSE +0 -21
- package/node_modules/koffi/vendor/node-api-headers/README.md +0 -95
- package/node_modules/koffi/vendor/node-api-headers/def/js_native_api.def +0 -125
- package/node_modules/koffi/vendor/node-api-headers/def/node_api.def +0 -157
- package/node_modules/koffi/vendor/node-api-headers/include/js_native_api.h +0 -591
- package/node_modules/koffi/vendor/node-api-headers/include/js_native_api_types.h +0 -210
- package/node_modules/koffi/vendor/node-api-headers/include/node_api.h +0 -265
- package/node_modules/koffi/vendor/node-api-headers/include/node_api_types.h +0 -58
- package/node_modules/koffi/vendor/node-api-headers/include/uv/aix.h +0 -32
- package/node_modules/koffi/vendor/node-api-headers/include/uv/bsd.h +0 -34
- package/node_modules/koffi/vendor/node-api-headers/include/uv/darwin.h +0 -61
- package/node_modules/koffi/vendor/node-api-headers/include/uv/errno.h +0 -483
- package/node_modules/koffi/vendor/node-api-headers/include/uv/linux.h +0 -34
- package/node_modules/koffi/vendor/node-api-headers/include/uv/os390.h +0 -33
- package/node_modules/koffi/vendor/node-api-headers/include/uv/posix.h +0 -31
- package/node_modules/koffi/vendor/node-api-headers/include/uv/sunos.h +0 -44
- package/node_modules/koffi/vendor/node-api-headers/include/uv/threadpool.h +0 -37
- package/node_modules/koffi/vendor/node-api-headers/include/uv/tree.h +0 -521
- package/node_modules/koffi/vendor/node-api-headers/include/uv/unix.h +0 -512
- package/node_modules/koffi/vendor/node-api-headers/include/uv/version.h +0 -43
- package/node_modules/koffi/vendor/node-api-headers/include/uv/win.h +0 -698
- 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 ¶m: 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 ¶m = 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
|
-
}
|