From 79c8a2f76e0ab3a56f4bb959f5741c0d538fa517 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Fri, 3 Feb 2023 13:39:22 +0200 Subject: [PATCH] Fix --- .github/workflows/publish-native-ts.yml | 4 +- .gitignore | 1 + .../package.json | 3 +- .../src/Bannerlord.Common.hpp | 29 +++++++ .../src/Bannerlord.FetchVersion.hpp | 13 ++-- .../src/lib/FetchBannerlordVersion.ts | 6 +- .../src/main.cpp | 6 +- .../src/test/FetchBannerlordVersion.spec.ts | 7 +- .../src/utils.hpp | 76 ++++++++++++++++--- .../Bindings.Shared.cs | 21 +++-- src/FetchBannerlordVersion.Native/Bindings.cs | 20 ++--- .../FetchBannerlordVersion.Native.csproj | 8 +- .../FetchBannerlordVersion.Native.h | 33 -------- .../Utils2.cs | 20 +++-- 14 files changed, 153 insertions(+), 94 deletions(-) create mode 100644 src/FetchBannerlordVersion.Native.TypeScript/src/Bannerlord.Common.hpp delete mode 100644 src/FetchBannerlordVersion.Native/FetchBannerlordVersion.Native.h diff --git a/.github/workflows/publish-native-ts.yml b/.github/workflows/publish-native-ts.yml index 7889bea..65e636b 100644 --- a/.github/workflows/publish-native-ts.yml +++ b/.github/workflows/publish-native-ts.yml @@ -24,9 +24,11 @@ jobs: with: dotnet-version: 7.x.x + - run: dotnet publish -r win-x64 --self-contained -c Debug src/FetchBannerlordVersion.Native - run: dotnet publish -r win-x64 --self-contained -c Release src/FetchBannerlordVersion.Native - - run: dotnet test test/FetchBannerlordVersion.Native.Tests + - run: dotnet test test/FetchBannerlordVersion.Native.Tests -c Debug + - run: dotnet test test/FetchBannerlordVersion.Native.Tests -c Release - uses: actions/setup-node@v3.5.1 with: diff --git a/.gitignore b/.gitignore index dfcfd56..c368911 100644 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,4 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ +/src/FetchBannerlordVersion.Native/FetchBannerlordVersion.Native.h diff --git a/src/FetchBannerlordVersion.Native.TypeScript/package.json b/src/FetchBannerlordVersion.Native.TypeScript/package.json index dae623f..2311f03 100644 --- a/src/FetchBannerlordVersion.Native.TypeScript/package.json +++ b/src/FetchBannerlordVersion.Native.TypeScript/package.json @@ -26,7 +26,6 @@ "native:1": "copyfiles -f ../FetchBannerlordVersion.Native/bin/Release/net7.0/win-x64/native/FetchBannerlordVersion.Native.dll .", "native:2": "copyfiles -f ../FetchBannerlordVersion.Native/bin/Release/net7.0/win-x64/native/FetchBannerlordVersion.Native.lib .", "native:3": "copyfiles -f ../FetchBannerlordVersion.Native/bin/Release/net7.0/win-x64/FetchBannerlordVersion.Native.h .", - "native:4": "copyfiles -f ../FetchBannerlordVersion.Native/bin/Release/net7.0/win-x64/Common.Native.h .", "build": "run-s native:* && run-s build:*", "build-ts": "run-s build:*", "build-native": "run-s native:*", @@ -105,4 +104,4 @@ "**/*.spec.*" ] } -} +} \ No newline at end of file diff --git a/src/FetchBannerlordVersion.Native.TypeScript/src/Bannerlord.Common.hpp b/src/FetchBannerlordVersion.Native.TypeScript/src/Bannerlord.Common.hpp new file mode 100644 index 0000000..3b8b52e --- /dev/null +++ b/src/FetchBannerlordVersion.Native.TypeScript/src/Bannerlord.Common.hpp @@ -0,0 +1,29 @@ +#ifndef BFE_COMMON_GUARD_HPP_ +#define BFE_COMMON_GUARD_HPP_ + +#include +#include "FetchBannerlordVersion.Native.h" + +using namespace Napi; +using namespace FetchBannerlordVersion::Native; + +namespace Bannerlord::Common +{ + + Value AllocAliveCount(const CallbackInfo &info) + { + const auto env = info.Env(); + + const auto result = common_alloc_alive_count(); + return Number::New(env, result); + } + + Object Init(const Env env, const Object exports) + { + exports.Set("allocAliveCount", Function::New(env, AllocAliveCount)); + + return exports; + } + +} +#endif \ No newline at end of file diff --git a/src/FetchBannerlordVersion.Native.TypeScript/src/Bannerlord.FetchVersion.hpp b/src/FetchBannerlordVersion.Native.TypeScript/src/Bannerlord.FetchVersion.hpp index 01cfa60..db553aa 100644 --- a/src/FetchBannerlordVersion.Native.TypeScript/src/Bannerlord.FetchVersion.hpp +++ b/src/FetchBannerlordVersion.Native.TypeScript/src/Bannerlord.FetchVersion.hpp @@ -2,19 +2,16 @@ #define BFE_GUARD_HPP_ #include "utils.hpp" -#include "Common.Native.h" -#include "FetchBannerlordVersion.Native.h" #include using namespace Napi; -using namespace Common; using namespace Utils; -using namespace Bannerlord::FetchVersion; +using namespace FetchBannerlordVersion::Native; namespace Bannerlord::FetchVersion { - const Value GetChangeSetWrapped(const CallbackInfo &info) + Value GetChangeSetWrapped(const CallbackInfo &info) { const auto env = info.Env(); const auto gameFolderPath = info[0].As(); @@ -27,7 +24,7 @@ namespace Bannerlord::FetchVersion return ThrowOrReturnUInt32(env, result); } - const Value GetVersionWrapped(const CallbackInfo &info) + Value GetVersionWrapped(const CallbackInfo &info) { const auto env = info.Env(); const auto gameFolderPath = info[0].As(); @@ -40,7 +37,7 @@ namespace Bannerlord::FetchVersion return ThrowOrReturnString(env, result); } - const Value GetVersionTypeWrapped(const CallbackInfo &info) + Value GetVersionTypeWrapped(const CallbackInfo &info) { const auto env = info.Env(); const auto gameFolderPath = info[0].As(); @@ -53,7 +50,7 @@ namespace Bannerlord::FetchVersion return ThrowOrReturnUInt32(env, result); } - const Object Init(Env env, Object exports) + Object Init(const Env env, const Object exports) { exports.Set("getChangeSet", Function::New(env, GetChangeSetWrapped)); diff --git a/src/FetchBannerlordVersion.Native.TypeScript/src/lib/FetchBannerlordVersion.ts b/src/FetchBannerlordVersion.Native.TypeScript/src/lib/FetchBannerlordVersion.ts index 7d7ad0a..c76df3a 100644 --- a/src/FetchBannerlordVersion.Native.TypeScript/src/lib/FetchBannerlordVersion.ts +++ b/src/FetchBannerlordVersion.Native.TypeScript/src/lib/FetchBannerlordVersion.ts @@ -1,6 +1,10 @@ import { IFetchBannerlordVersion } from "./types"; -const fetcher: IFetchBannerlordVersion = require('./../../fetchblversion.node'); +const fetcher: IFetchBannerlordVersion & { allocAliveCount(): number; } = require('./../../fetchblversion.node'); + +export const allocAliveCount = (): number => { + return fetcher.allocAliveCount(); +} export class FetchBannerlordVersion { /* istanbul ignore next */ diff --git a/src/FetchBannerlordVersion.Native.TypeScript/src/main.cpp b/src/FetchBannerlordVersion.Native.TypeScript/src/main.cpp index 9689dc5..7076164 100644 --- a/src/FetchBannerlordVersion.Native.TypeScript/src/main.cpp +++ b/src/FetchBannerlordVersion.Native.TypeScript/src/main.cpp @@ -1,12 +1,14 @@ +#include "Bannerlord.Common.hpp" #include "Bannerlord.FetchVersion.hpp" #include using namespace Napi; -using namespace Bannerlord::FetchVersion; Object InitAll(const Env env, const Object exports) { - return Init(env, exports); + Bannerlord::Common::Init(env, exports); + Bannerlord::FetchVersion::Init(env, exports); + return exports; } NODE_API_MODULE(NODE_GYP_MODULE_NAME, InitAll) diff --git a/src/FetchBannerlordVersion.Native.TypeScript/src/test/FetchBannerlordVersion.spec.ts b/src/FetchBannerlordVersion.Native.TypeScript/src/test/FetchBannerlordVersion.spec.ts index 70c818e..2b69877 100644 --- a/src/FetchBannerlordVersion.Native.TypeScript/src/test/FetchBannerlordVersion.spec.ts +++ b/src/FetchBannerlordVersion.Native.TypeScript/src/test/FetchBannerlordVersion.spec.ts @@ -1,6 +1,8 @@ import test from 'ava'; -import { FetchBannerlordVersion } from '../lib/FetchBannerlordVersion'; +import { FetchBannerlordVersion, allocAliveCount } from '../lib/FetchBannerlordVersion'; + +const isDebug = process.argv[2] == "Debug"; test('Main', async (t) => { const path = __dirname; @@ -15,5 +17,8 @@ test('Main', async (t) => { const versionType = FetchBannerlordVersion.getVersionType(path, dllName); t.is(versionType, 4); + if (isDebug) + t.deepEqual(allocAliveCount(), 0); + t.pass(); }); \ No newline at end of file diff --git a/src/FetchBannerlordVersion.Native.TypeScript/src/utils.hpp b/src/FetchBannerlordVersion.Native.TypeScript/src/utils.hpp index 7259110..53d9608 100644 --- a/src/FetchBannerlordVersion.Native.TypeScript/src/utils.hpp +++ b/src/FetchBannerlordVersion.Native.TypeScript/src/utils.hpp @@ -1,16 +1,70 @@ #ifndef BFE_UTILS_GUARD_HPP_ #define BFE_UTILS_GUARD_HPP_ -#include #include #include +#include "FetchBannerlordVersion.Native.h" using namespace Napi; -using namespace Common; +using namespace FetchBannerlordVersion::Native; namespace Utils { + template + struct deleter + { + void operator()(T *const ptr) const { common_dealloc(static_cast(ptr)); } + }; + + using del_void = std::unique_ptr>; + using del_string = std::unique_ptr>; + using del_json = std::unique_ptr>; + using del_bool = std::unique_ptr>; + using del_int32 = std::unique_ptr>; + using del_uint32 = std::unique_ptr>; + using del_ptr = std::unique_ptr>; + + char16_t *const Copy(const std::u16string str) + { + const auto src = str.c_str(); + const auto srcChar16Length = str.length(); + const auto srcByteLength = srcChar16Length * sizeof(char16_t); + const auto size = srcByteLength + sizeof(char16_t); + + auto dst = static_cast(common_alloc(size)); + if (dst == nullptr) + { + throw std::bad_alloc(); + } + std::memmove(dst, src, srcByteLength); + dst[srcChar16Length] = '\0'; + return dst; + } + + std::unique_ptr> CopyWithFree(const std::u16string str) + { + return std::unique_ptr>(Copy(str)); + } + + const char16_t *const NoCopy(const std::u16string str) noexcept + { + return str.c_str(); + } + + template + T *const Create(const T val) + { + const auto size = sizeof(T); + auto dst = static_cast(alloc(size)); + if (dst == nullptr) + { + throw std::bad_alloc(); + } + std::memcpy(dst, &val, sizeof(T)); + return dst; + } + void ConsoleLog(const Env env, const String message) { const auto consoleObject = env.Global().Get("console").As(); @@ -18,20 +72,20 @@ namespace Utils log.Call(consoleObject, {message}); } - const String JSONStringify(const Env env, const Object object) + String JSONStringify(const Env env, const Object object) { const auto jsonObject = env.Global().Get("JSON").As(); const auto stringify = jsonObject.Get("stringify").As(); return stringify.Call(jsonObject, {object}).As(); } - const Object JSONParse(const Env env, const String json) + Object JSONParse(const Env env, const String json) { const auto jsonObject = env.Global().Get("JSON").As(); const auto parse = jsonObject.Get("parse").As(); return parse.Call(jsonObject, {json}).As(); } - void ThrowOrReturn(Env env, return_value_void *val) + void ThrowOrReturn(const Env env, return_value_void *const val) { const del_void del{val}; @@ -42,7 +96,7 @@ namespace Utils const auto error = std::unique_ptr>(val->error); NAPI_THROW(Error::New(env, String::New(env, error.get()))); } - const Value ThrowOrReturnString(Env env, return_value_string *val) + Value ThrowOrReturnString(const Env env, return_value_string *const val) { const del_string del{val}; @@ -59,7 +113,7 @@ namespace Utils const auto error = std::unique_ptr>(val->error); NAPI_THROW(Error::New(env, String::New(env, error.get()))); } - const Value ThrowOrReturnJson(Env env, return_value_json *val) + Value ThrowOrReturnJson(const Env env, return_value_json *const val) { const del_json del{val}; @@ -76,7 +130,7 @@ namespace Utils const auto error = std::unique_ptr>(val->error); NAPI_THROW(Error::New(env, String::New(env, error.get()))); } - const Value ThrowOrReturnBoolean(Env env, return_value_bool *val) + Value ThrowOrReturnBoolean(const Env env, return_value_bool *const val) { const del_bool del{val}; @@ -87,7 +141,7 @@ namespace Utils const auto error = std::unique_ptr>(val->error); NAPI_THROW(Error::New(env, String::New(env, error.get()))); } - const Value ThrowOrReturnInt32(Env env, return_value_int32 *val) + Value ThrowOrReturnInt32(const Env env, return_value_int32 *const val) { const del_int32 del{val}; @@ -98,7 +152,7 @@ namespace Utils const auto error = std::unique_ptr>(val->error); NAPI_THROW(Error::New(env, String::New(env, error.get()))); } - const Value ThrowOrReturnUInt32(Env env, return_value_uint32 *val) + Value ThrowOrReturnUInt32(const Env env, return_value_uint32 *const val) { const del_uint32 del{val}; @@ -109,7 +163,7 @@ namespace Utils const auto error = std::unique_ptr>(val->error); NAPI_THROW(Error::New(env, String::New(env, error.get()))); } - void *ThrowOrReturnPtr(Env env, return_value_ptr *val) + void *ThrowOrReturnPtr(const Env env, return_value_ptr *const val) { const del_ptr del{val}; diff --git a/src/FetchBannerlordVersion.Native/Bindings.Shared.cs b/src/FetchBannerlordVersion.Native/Bindings.Shared.cs index 1f5f1fb..8d78745 100644 --- a/src/FetchBannerlordVersion.Native/Bindings.Shared.cs +++ b/src/FetchBannerlordVersion.Native/Bindings.Shared.cs @@ -1,21 +1,22 @@ using BUTR.NativeAOT.Shared; using System; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace FetchBannerlordVersion.Native { public static unsafe partial class Bindings { - [UnmanagedCallersOnly(EntryPoint = "alloc")] - public static void* Alloc(nuint size) + [UnmanagedCallersOnly(EntryPoint = "common_alloc", CallConvs = new[] { typeof(CallConvCdecl) }), IsNotConst] + public static void* CommonAlloc(nuint size) { Logger.LogInput(size); try { var result = Allocator.Alloc(size); - Logger.LogOutput(new IntPtr(result).ToString("x16"), nameof(Alloc)); + Logger.LogOutput(new IntPtr(result).ToString("x16"), nameof(CommonAlloc)); return result; } catch (Exception e) @@ -25,10 +26,10 @@ public static unsafe partial class Bindings } } - [UnmanagedCallersOnly(EntryPoint = "dealloc")] - public static void Dealloc(param_ptr* ptr) + [UnmanagedCallersOnly(EntryPoint = "common_dealloc", CallConvs = new[] { typeof(CallConvCdecl) })] + public static void Common_Dealloc([IsConst] param_ptr* ptr) { - Logger.LogInput(new IntPtr(ptr).ToString("x16"), nameof(Dealloc)); + Logger.LogInput(new IntPtr(ptr).ToString("x16"), nameof(Common_Dealloc)); try { Allocator.Free(ptr); @@ -41,13 +42,17 @@ public static void Dealloc(param_ptr* ptr) } } - [UnmanagedCallersOnly(EntryPoint = "alloc_alive_count")] - public static int AllocAliveCount() + [UnmanagedCallersOnly(EntryPoint = "common_alloc_alive_count", CallConvs = new[] { typeof(CallConvCdecl) })] + public static int CommonAllocAliveCount() { Logger.LogInput(); try { +#if TRACK_ALLOCATIONS var result = Allocator.GetCurrentAllocations(); +#else + var result = 0; +#endif Logger.LogOutput(result); return result; diff --git a/src/FetchBannerlordVersion.Native/Bindings.cs b/src/FetchBannerlordVersion.Native/Bindings.cs index 69c4feb..c0e631e 100644 --- a/src/FetchBannerlordVersion.Native/Bindings.cs +++ b/src/FetchBannerlordVersion.Native/Bindings.cs @@ -9,8 +9,8 @@ namespace FetchBannerlordVersion.Native { public static unsafe partial class Bindings { - [UnmanagedCallersOnly(EntryPoint = "bfv_get_change_set", CallConvs = new[] { typeof(CallConvCdecl) })] - public static return_value_uint32* GetChangeSet(param_string* p_game_folder_path, param_string* p_lib_assembly) + [UnmanagedCallersOnly(EntryPoint = "bfv_get_change_set", CallConvs = new[] { typeof(CallConvCdecl) }), IsNotConst] + public static return_value_uint32* GetChangeSet([IsConst] param_string* p_game_folder_path, [IsConst] param_string* p_lib_assembly) { Logger.LogInput(p_game_folder_path, p_lib_assembly); try @@ -26,12 +26,12 @@ public static unsafe partial class Bindings catch (Exception e) { Logger.LogException(e); - return return_value_uint32.AsError(Utils.Copy(e.ToString(), false), false); + return return_value_uint32.AsException(e, false); } } - [UnmanagedCallersOnly(EntryPoint = "bfv_get_version", CallConvs = new[] { typeof(CallConvCdecl) })] - public static return_value_string* GetVersion(param_string* p_game_folder_path, param_string* p_lib_assembly) + [UnmanagedCallersOnly(EntryPoint = "bfv_get_version", CallConvs = new[] { typeof(CallConvCdecl) }), IsNotConst] + public static return_value_string* GetVersion([IsConst] param_string* p_game_folder_path, [IsConst] param_string* p_lib_assembly) { Logger.LogInput(p_game_folder_path, p_lib_assembly); try @@ -41,18 +41,18 @@ public static unsafe partial class Bindings var result = Fetcher.GetVersion(Path.GetFullPath(gameFolderPath), libAssembly); - Logger.LogOutput(result, nameof(GetVersion)); + Logger.LogOutput(result); return return_value_string.AsValue(Utils.Copy(result, false), false); } catch (Exception e) { Logger.LogException(e); - return return_value_string.AsError(Utils.Copy(e.ToString(), false), false); + return return_value_string.AsException(e, false); } } - [UnmanagedCallersOnly(EntryPoint = "bfv_get_version_type", CallConvs = new[] { typeof(CallConvCdecl) })] - public static return_value_uint32* GetVersionType(param_string* p_game_folder_path, param_string* p_lib_assembly) + [UnmanagedCallersOnly(EntryPoint = "bfv_get_version_type", CallConvs = new[] { typeof(CallConvCdecl) }), IsNotConst] + public static return_value_uint32* GetVersionType([IsConst] param_string* p_game_folder_path, [IsConst] param_string* p_lib_assembly) { Logger.LogInput(p_game_folder_path, p_lib_assembly); try @@ -68,7 +68,7 @@ public static unsafe partial class Bindings catch (Exception e) { Logger.LogException(e); - return return_value_uint32.AsError(Utils.Copy(e.ToString(), false), false); + return return_value_uint32.AsException(e, false); } } } diff --git a/src/FetchBannerlordVersion.Native/FetchBannerlordVersion.Native.csproj b/src/FetchBannerlordVersion.Native/FetchBannerlordVersion.Native.csproj index 9edabde..6b12b61 100644 --- a/src/FetchBannerlordVersion.Native/FetchBannerlordVersion.Native.csproj +++ b/src/FetchBannerlordVersion.Native/FetchBannerlordVersion.Native.csproj @@ -35,7 +35,6 @@ Always - @@ -43,12 +42,9 @@ - + + - - - - \ No newline at end of file diff --git a/src/FetchBannerlordVersion.Native/FetchBannerlordVersion.Native.h b/src/FetchBannerlordVersion.Native/FetchBannerlordVersion.Native.h deleted file mode 100644 index d4c841d..0000000 --- a/src/FetchBannerlordVersion.Native/FetchBannerlordVersion.Native.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef SRC_FETCHBLVERSION_BINDINGS_H_ -#define SRC_FETCHBLVERSION_BINDINGS_H_ - -#include "Common.Native.h" - -#define CALL_CONV __cdecl - -#ifdef __cplusplus -using namespace Common; - -namespace Bannerlord::FetchVersion -{ - extern "C" - { -#endif - - // All char16_t* parameters do not transfer ownership to the callee - // All char16_t* returns pass their ownership to the callee - - return_value_uint32 *const CALL_CONV bfv_get_change_set(const param_string * p_game_folder_path, const param_string * p_lib_assembly); - - return_value_string *const CALL_CONV bfv_get_version(const param_string * p_game_folder_path, const param_string * p_lib_assembly); - - return_value_uint32 *const CALL_CONV bfv_get_version_type(const param_string * p_game_folder_path, const param_string * p_lib_assembly); - -#ifdef __cplusplus - } -} -#endif - -#undef CALL_CONV - -#endif \ No newline at end of file diff --git a/test/FetchBannerlordVersion.Native.Tests/Utils2.cs b/test/FetchBannerlordVersion.Native.Tests/Utils2.cs index c53a9c7..a4ebbc9 100644 --- a/test/FetchBannerlordVersion.Native.Tests/Utils2.cs +++ b/test/FetchBannerlordVersion.Native.Tests/Utils2.cs @@ -7,23 +7,21 @@ namespace FetchBannerlordVersion.Native.Tests { internal static partial class Utils2 { +#if DEBUG + public const string DllPath = "../../../../../src/FetchBannerlordVersion.Native/bin/Debug/net7.0/win-x64/native/FetchBannerlordVersion.Native.dll"; +#else public const string DllPath = "../../../../../src/FetchBannerlordVersion.Native/bin/Release/net7.0/win-x64/native/FetchBannerlordVersion.Native.dll"; - - - static unsafe Utils2() - { - Allocator.SetCustom(&alloc, &dealloc); - } +#endif [LibraryImport(DllPath), UnmanagedCallConv(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe partial void* alloc(nuint size); + private static unsafe partial void* common_alloc(nuint size); [LibraryImport(DllPath), UnmanagedCallConv(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe partial void dealloc(void* ptr); + private static unsafe partial void common_dealloc(void* ptr); [LibraryImport(DllPath), UnmanagedCallConv(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe partial int alloc_alive_count(); + private static unsafe partial int common_alloc_alive_count(); - public static unsafe void LibrarySetAllocator() => Allocator.SetCustom(&alloc, &dealloc); - public static int LibraryAliveCount() => alloc_alive_count(); + public static unsafe void LibrarySetAllocator() => Allocator.SetCustom(&common_alloc, &common_dealloc); + public static int LibraryAliveCount() => common_alloc_alive_count(); public static unsafe ReadOnlySpan ToSpan(param_string* value) => new SafeStringMallocHandle((char*) value, false).ToSpan();