diff --git a/.github/workflows/windows-napi.yml b/.github/workflows/windows-napi.yml new file mode 100644 index 0000000..4da5ef3 --- /dev/null +++ b/.github/workflows/windows-napi.yml @@ -0,0 +1,88 @@ +name: windows-napi + +# NOTE: `paths` filters deliberately do NOT accompany the tag trigger — a tag push can have an +# empty changed-file set, and paths+tags together silently skip the run. +on: + push: + tags: + - 'windows-napi-v*' + pull_request: + paths: + - 'windows-napi/**' + - 'runtime/**' + - 'metadata/**' + - '.github/workflows/windows-napi.yml' + workflow_dispatch: + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + settings: + - target: x86_64-pc-windows-msvc + - target: aarch64-pc-windows-msvc + name: build ${{ matrix.settings.target }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.settings.target }} + - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.settings.target }} + - name: Install npm dependencies + working-directory: windows-napi + run: npm ci + - name: Build .node + working-directory: windows-napi + run: npx napi build --platform --release --target ${{ matrix.settings.target }} + - name: Run test suite (x64 only — the runner cannot execute arm64 binaries) + if: matrix.settings.target == 'x86_64-pc-windows-msvc' + working-directory: windows-napi + # Server runner SKUs can lack optional feature packs some suites touch (e.g. Media + # Foundation for the MediaPlayer event test), so failures here warn instead of block; + # the authoritative run is the local one on a client SKU. + continue-on-error: true + run: npm test + - uses: actions/upload-artifact@v4 + with: + name: bindings-${{ matrix.settings.target }} + path: windows-napi/windows.*.node + if-no-files-found: error + + publish: + name: publish to npm + if: startsWith(github.ref, 'refs/tags/windows-napi-v') + needs: build + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + registry-url: https://registry.npmjs.org + - name: Install npm dependencies + working-directory: windows-napi + run: npm ci + - name: Download all binding artifacts + uses: actions/download-artifact@v4 + with: + path: windows-napi/artifacts + - name: Distribute artifacts into npm/ sub-packages + working-directory: windows-napi + run: npx napi artifacts + - name: Publish + working-directory: windows-napi + # `napi prepublish` (prepublishOnly script) publishes each npm/ sub-package, + # then the root package publishes with them as optionalDependencies. + run: npm publish --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index bea82d7..643789f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,15 @@ +# Rust build artifacts (root + nested workspace/package crates) /target +target/ /**/*.rs.bk /Cargo.lock + +# Node +node_modules/ + +# Logs +*.log + .DS_Store .vs diff --git a/Cargo.toml b/Cargo.toml index b18679f..4bbd7dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,8 @@ [workspace] resolver = "2" -members = ["metadata", "playground", "runtime", "runtime-binding-gen", "sbg", "nativescript", "typings-generator", "integration-tests", "runtime-devtools", "metadata-generator","tools/dotnet-tool"] +members = ["metadata", "playground", "runtime", "runtime-binding-gen", "sbg", "nativescript", "typings-generator", "integration-tests", "runtime-devtools", "metadata-generator","tools/dotnet-tool", "windows-napi"] +# Excluded so their C builds / prebuilt-engine links don't run on normal `cargo` invocations. +exclude = ["packages/common", "packages/demo", "packages/windows-quickjs", "packages/windows-hermes", "packages/windows-jsc", "packages/windows-v8"] [workspace.dependencies] windows = "0.62.2" diff --git a/docs/napi-consumption.md b/docs/napi-consumption.md new file mode 100644 index 0000000..f31fb26 --- /dev/null +++ b/docs/napi-consumption.md @@ -0,0 +1,114 @@ +# Consuming `@nativescript/windows` from Node, Bun, and Deno + +The package is a napi-rs native addon (`windows..node`) plus a small JS layer +(`index.js` from napi-rs, and `nswinrt.js` with the WinRT ergonomics: `toPromise`, auto-pump, +`interop.*`). Because it targets the **Node-API** ABI, any runtime that implements Node-API can +load it — the engine underneath differs, but the interop code does not. + +## Loading + +### Node.js (V8) +```js +const { Windows, toPromise, enableAutoPump } = require('@nativescript/windows/nswinrt.js'); +enableAutoPump(); +``` +Or ESM via `createRequire`. No flags needed. This is the primary, fully-tested path. + +### Bun (JavaScriptCore) +Bun implements Node-API and loads `.node` addons through the same `require`/`import`: +```js +import { Windows, toPromise } from '@nativescript/windows/nswinrt.js'; +``` +This is the **JSC-on-Windows** route — no WebKit embedding needed; Bun provides JSC + Node-API. + +### Deno (V8) +Deno implements Node-API behind its Node-compat layer. Import via the `npm:` specifier (or +`createRequire`), and grant the permissions the addon needs: +``` +deno run --allow-ffi --allow-read --allow-env --allow-write app.js +``` +```js +import { Windows, toPromise } from "npm:@nativescript/windows/nswinrt.js"; +``` +`--allow-ffi` is required for native addons; `--allow-read` is needed for winmd discovery +(below). + +> The native `.node` is identical across all three — only the host engine changes. `nswinrt.js` +> is plain CommonJS and uses only `require('./index.js')` + timers, so it runs unmodified on all +> three runtimes. + +## winmd discovery (the important part) + +WinRT type metadata comes from two sources: + +1. **System / OS types** (`Windows.*`) — resolved by the OS via `RoGetMetaDataFile`. **No files + ship with the app**; these always resolve on any Windows machine, in any runtime. Everything + in the test suite (JsonObject, Uri, Calendar, ThreadPool, CryptographicBuffer, …) is system + metadata and needs zero configuration. + +2. **Third-party / app `.winmd`** (WebView2, your own WinRT components) — **not** discoverable by + the OS; they must be registered explicitly. + +### How the napi package finds them + +The rusty_v8 runtime auto-scans for `.winmd` in `Runtime::new` (exe dir + app root). **The napi +path never constructs a `Runtime`** — it drives interop directly on the host's `napi_env` — so +that scan is reproduced on the napi side: + +- **Automatic:** the first `getNamespace(...)` (or any interop call) runs a one-time scan of the + **current working directory** and the **host executable's directory** + (`scan_default_winmd_dirs`). Drop your `.winmd` next to where you launch and it's picked up. +- **Explicit (recommended for apps):** point the runtime at your metadata directly — + ```js + const { interop } = require('@nativescript/windows/nswinrt.js'); + interop.registerWinmd('C:/app/metadata/MyComponent.winmd'); // one file + interop.scanWinmdDir('C:/app/metadata'); // whole folder → count + ``` + Call these **before** touching the corresponding namespaces. + +### Why auto-scan differs from the standalone runtime + +Under the standalone (embedded-V8) runtime, `current_exe` is *your app's* exe, so the exe-dir +scan finds app-bundled winmd automatically. Under Node/Bun/Deno, `current_exe` is +`node.exe`/`bun.exe`/`deno.exe` — so the exe-dir scan covers the runtime's own directory, and the +**cwd scan + explicit `registerWinmd`/`scanWinmdDir`** are how app metadata gets loaded. A CLI +that launches apps should either `chdir` to the metadata location or call `scanWinmdDir` on +startup. (This matches the NativeScript CLI's existing responsibility to deploy the `.winmd`.) + +## The message loop / async + +WinRT async completions (`IAsyncAction`/`IAsyncOperation`) are delivered on the STA thread's +message queue, so that queue must be pumped for a `Promise` to settle. `nswinrt.js` handles this: + +- `enableAutoPump()` — installs a ref-counted pump on the host timer loop; it's ref'd only while + a WinRT `Promise` is outstanding (so the process still exits normally). After this, plain + `await toPromise(op)` just works. +- `awaitWithPump(promise, timeoutMs)` — explicit alternative that pumps inline until settle. + +This is the same on all three runtimes (all expose `setInterval`/`setImmediate`). + +## Natural-syntax extras + +Beyond method/property/event access, the napi backend supports: + +- **Keyed maps (`IMap`/`IMapView`/`IPropertySet`)** — classes whose default interface is a map + (`StringMap`, `PropertySet`, `ValueSet`, `ApplicationDataContainerSettings`, …) and + interface-typed map returns get keyed sugar: `m['key']` → `Lookup`, `m['key'] = v` → `Insert`, + `'key' in m` → `HasKey`, plus `m.length` → `Size`. WinRT member names always win over map + keys (use `m.Lookup('Size')` for a shadowed key). `PropertySet`/`ValueSet` values box on + insert and unbox (`IPropertyValue` primitives) on lookup, so `ps['n'] = 42; ps['n'] === 42`. + Classes that merely *also* implement `IMap` alongside a richer identity (e.g. `JsonObject`) + stay host objects — call `Lookup`/`Insert` explicitly there. +- **Subclassing** — `class Sub extends WinRTClass` works on both object models (host objects + and Proxy-path instances): constructor args flow through `super(...)`, overrides can call + `super.Method()`, instances satisfy `instanceof` for both the subclass and the WinRT class, + and subclass instances marshal as WinRT arguments (identity-cached, so the same JS object + comes back out). +- **Composable (non-sealed) constructors** — the composition (null-outer) ABI is wired; note + every activatable non-sealed WinRT class lives in `Windows.UI.Xaml`, whose activation + requires a XAML-initialized thread. Headless those ctors surface the factory's + `RPC_E_WRONG_THREAD` as a normal catchable JS error (identical to the classic runtime). + `Windows.UI.Composition` object trees (non-sealed bases) work headless — the backend creates + a `DispatcherQueue` for the JS thread at init. +- **`setImmediate`/`clearImmediate`** — provided by the standalone engine hosts' event loop + (Node/Bun/Deno already have their own). diff --git a/dotnet-bridge-tests/ManagedSubclassFixtures.cs b/dotnet-bridge-tests/ManagedSubclassFixtures.cs new file mode 100644 index 0000000..12087f9 --- /dev/null +++ b/dotnet-bridge-tests/ManagedSubclassFixtures.cs @@ -0,0 +1,33 @@ +namespace DotNetBridgeTests; + +// Test-only stand-ins for a real WinRT base class with virtuals JS may or may not override — +// mirrors why MeasureOverrideBase exists (the real target, a WinUI FrameworkElement, needs the +// full WinRT runtime the xunit host doesn't have). +public class CallBaseFallbackBase +{ + public virtual string Describe() + { + return "base-describe"; + } + + public virtual string Greet(string name) + { + return "base-greet:" + name; + } + + public virtual string Text + { + get { return "base-text"; } + set { LastSetText = value; } + } + + public string? LastSetText; +} + +// Test-only stand-in for a WinRT interface (e.g. INotifyPropertyChanged) JS implements directly +// without a real .NET base class — proves AddInterfaceImplementation + dispatch mechanically, +// independent of the CsWinRT CCW question (covered separately by real-app validation). +public interface ITestNotify +{ + string Notify(string message); +} diff --git a/dotnet-bridge-tests/ManagedSubclassMemberFilterTests.cs b/dotnet-bridge-tests/ManagedSubclassMemberFilterTests.cs new file mode 100644 index 0000000..7c2d726 --- /dev/null +++ b/dotnet-bridge-tests/ManagedSubclassMemberFilterTests.cs @@ -0,0 +1,246 @@ +using System; +using System.Buffers; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using NativeScriptBridge; +using Xunit; + +namespace DotNetBridgeTests; + +// Covers the fixes made to the dynamic managed-subclass proxy (Bridge.Proxy.cs): +// 1. Call-base fallback — a base virtual JS doesn't override must run the real base +// implementation, not silently return default(T). +// 2. Member-set-scoped type cache — two differently-configured subclasses of the same +// base type must not contaminate each other's dispatch. +// 3. Property-accessor ergonomics — get_/set_-prefixed member names round-trip correctly. +// 4. Interface implementation — AddInterfaceImplementation + dispatch is mechanically correct. +[Collection("Bridge")] +public sealed class ManagedSubclassMemberFilterTests : IDisposable +{ + private static readonly List<(string Method, object?[] Args)> s_calls = new(); + private static Func? s_handler; + + [UnmanagedCallersOnly(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static unsafe void Invoker(int id, byte* argsPtr, int argsLen, byte** respPtr, int* respLen) + { + var (method, args) = DecodeCall(new ReadOnlySpan(argsPtr, argsLen)); + s_calls.Add((method, args)); + var result = s_handler?.Invoke(method, args); + WriteResponse(result, respPtr, respLen); + } + + public unsafe ManagedSubclassMemberFilterTests() + { + Bridge.ClearCaches(); + s_calls.Clear(); + s_handler = null; + Bridge.s_jsInvoker = &Invoker; + } + + public unsafe void Dispose() + { + Bridge.s_jsInvoker = null; + Bridge.ClearCaches(); + } + + [Fact] + public void CallBaseFallback_UnoverriddenVirtual_RunsRealBaseImplementation() + { + var handle = CreateSubclass( + "DotNetBridgeTests.CallBaseFallbackBase", + interfaceNames: [], + memberNames: ["Describe"], + callbackId: 1); + + s_handler = (method, args) => method == "Describe" ? "js-describe" : null; + + // Overridden: dispatches to JS. + var describeResult = InvokeInstance(handle, "Describe"); + Assert.Equal("js-describe", describeResult.PrimitiveValue()); + Assert.Contains(s_calls, c => c.Method == "Describe"); + + // NOT overridden: must run the real base method, never even asking JS. + var greetResult = InvokeInstance(handle, "Greet", "World"); + Assert.Equal("base-greet:World", greetResult.PrimitiveValue()); + Assert.DoesNotContain(s_calls, c => c.Method == "Greet"); + + Release(handle); + } + + [Fact] + public void DifferentMemberSets_SameBaseType_DoNotContaminateEachOther() + { + var handleA = CreateSubclass( + "DotNetBridgeTests.CallBaseFallbackBase", [], ["Describe"], callbackId: 2); + var handleB = CreateSubclass( + "DotNetBridgeTests.CallBaseFallbackBase", [], ["Greet"], callbackId: 3); + + s_handler = (method, args) => "js:" + method; + + // A overrides Describe only -> Greet falls through to the base on A. + Assert.Equal("js:Describe", InvokeInstance(handleA, "Describe").PrimitiveValue()); + Assert.Equal("base-greet:x", InvokeInstance(handleA, "Greet", "x").PrimitiveValue()); + + // B overrides Greet only -> Describe falls through to the base on B. + Assert.Equal("base-describe", InvokeInstance(handleB, "Describe").PrimitiveValue()); + Assert.Equal("js:Greet", InvokeInstance(handleB, "Greet", "x").PrimitiveValue()); + + Release(handleA); + Release(handleB); + } + + [Fact] + public void PropertyAccessors_GetSetPrefixedMemberNames_RoundTrip() + { + var handle = CreateSubclass( + "DotNetBridgeTests.CallBaseFallbackBase", [], ["get_Text", "set_Text"], callbackId: 4); + + string? stored = null; + s_handler = (method, args) => + { + if (method == "set_Text") { stored = (string?)args[0]; return null; } + if (method == "get_Text") return stored ?? "(unset)"; + return null; + }; + + InvokeInstance(handle, "set_Text", "hello"); + Assert.Contains(s_calls, c => c.Method == "set_Text" && (string?)c.Args[0] == "hello"); + + var getResult = InvokeInstance(handle, "get_Text"); + Assert.Equal("hello", getResult.PrimitiveValue()); + + Release(handle); + } + + [Fact] + public void Interfaces_RequestedInterface_IsImplementedAndDispatches() + { + var handle = CreateSubclass( + "System.Object", ["DotNetBridgeTests.ITestNotify"], ["Notify"], callbackId: 5); + + s_handler = (method, args) => method == "Notify" ? "notified:" + args[0] : null; + + Assert.True(Bridge.s_handles.TryGetValue(handle, out var instance)); + Assert.IsAssignableFrom(instance); + + var result = InvokeInstance(handle, "Notify", "hi"); + Assert.Equal("notified:hi", result.PrimitiveValue()); + + Release(handle); + } + + // ── helpers ───────────────────────────────────────────────────────────── + + private static int CreateSubclass( + string typeName, string[] interfaceNames, string[] memberNames, int callbackId) + { + var pkt = BuildPacket(w => + { + w.WriteByte(0x0A); + w.WriteString16("DotNetBridgeTests"); + w.WriteString16(typeName); + w.WriteI32(interfaceNames.Length); + foreach (var n in interfaceNames) w.WriteString16(n); + w.WriteI32(memberNames.Length); + foreach (var n in memberNames) w.WriteString16(n); + w.WriteI32(callbackId); + }); + var r = new BinReader(pkt.AsSpan()); + var res = Bridge.DispatchBin(ref r); + Assert.Equal(DispatchKind.Handle, res.Kind()); + return res.HandleId(); + } + + private static DispatchResult InvokeInstance(int handle, string method, params object[] args) + { + var pkt = BuildPacket(w => + { + w.WriteByte(0x01); + w.WriteI32(handle); + w.WriteString16(method); + w.WriteByte((byte)args.Length); + foreach (var a in args) + { + if (a is string s) { w.WriteByte(0x05); w.WriteString16(s); } + else if (a is int i) { w.WriteByte(0x03); w.WriteI32(i); } + else throw new NotSupportedException("test helper only supports string/int args"); + } + }); + var r = new BinReader(pkt.AsSpan()); + return Bridge.DispatchBin(ref r); + } + + private static void Release(int handle) + { + var pkt = BuildPacket(w => + { + w.WriteByte(0x04); + w.WriteI32(handle); + }); + var r = new BinReader(pkt.AsSpan()); + Bridge.DispatchBin(ref r); + } + + private static byte[] BuildPacket(Action build) + { + var buf = new ArrayBufferWriter(64); + var w = new BinWriter(buf); + build(w); + return buf.WrittenSpan.ToArray(); + } + + // Decodes a dispatcher call built by Bridge.JsDelegate's WriteCallbackArg: 3 args — + // [HandleRef instance][string32 method][HandleRef argsArray] — resolving the args-array + // handle straight out of Bridge.s_handles rather than re-decoding nested tags by hand. + private static (string Method, object?[] Args) DecodeCall(ReadOnlySpan span) + { + var r = new BinReader(span); + var count = r.ReadByte(); + if (count != 3) + throw new InvalidOperationException($"expected 3 dispatcher args, got {count}"); + + ReadOutgoingHandleTag(ref r); // instance handle — unused by these tests + + var methodTag = r.ReadByte(); + if (methodTag != 0x05) + throw new InvalidOperationException($"expected string tag 0x05 for method name, got 0x{methodTag:X2}"); + var method = r.ReadString32(); + + var argsHandleId = ReadOutgoingHandleTag(ref r); + var argsObj = Bridge.s_handles.TryGetValue(argsHandleId, out var o) ? o as object?[] : null; + return (method, argsObj ?? Array.Empty()); + } + + private static int ReadOutgoingHandleTag(ref BinReader r) + { + var tag = r.ReadByte(); + if (tag != 0x06) + throw new InvalidOperationException($"expected handle tag 0x06, got 0x{tag:X2}"); + var handleId = r.ReadI32(); + _ = r.ReadString16(); // type name — unused + var nativeFlag = r.ReadByte(); + if (nativeFlag == 1) _ = r.ReadI64(); + return handleId; + } + + private static unsafe void WriteResponse(object? result, byte** respPtr, int* respLen) + { + if (result is not string s) + { + *respPtr = null; + *respLen = 0; + return; + } + + var strBytes = Encoding.UTF8.GetBytes(s); + var total = 1 + 4 + strBytes.Length; + var mem = (byte*)Marshal.AllocHGlobal(total); + mem[0] = 0x05; + BinaryPrimitives.WriteUInt32LittleEndian(new Span(mem + 1, 4), (uint)strBytes.Length); + strBytes.CopyTo(new Span(mem + 5, strBytes.Length)); + *respPtr = mem; + *respLen = total; + } +} diff --git a/dotnet-bridge-tests/ProxyMeasureOverrideTests.cs b/dotnet-bridge-tests/ProxyMeasureOverrideTests.cs index 278bc8d..b0c9bf1 100644 --- a/dotnet-bridge-tests/ProxyMeasureOverrideTests.cs +++ b/dotnet-bridge-tests/ProxyMeasureOverrideTests.cs @@ -45,9 +45,13 @@ public void MeasureOverride_CustomOverride_InvokesJsCallback() var pkt = BuildPacket(w => { w.WriteByte(0x0A); // create_js_subclass - // Binary protocol expects: assembly, typeName for opcode 0x0A + // Binary protocol expects: assembly, typeName, interfaceCount+names, + // memberCount+names, callbackId for opcode 0x0A. w.WriteString16("DotNetBridgeTests"); w.WriteString16("DotNetBridgeTests.MeasureOverrideBase"); + w.WriteI32(0); // interfaceCount + w.WriteI32(1); // memberCount + w.WriteString16("MeasureOverride"); w.WriteI32(777); // callbackId }); diff --git a/dotnet-bridge/Bridge.BinaryDispatch.cs b/dotnet-bridge/Bridge.BinaryDispatch.cs index cd1b2e7..7af021e 100644 --- a/dotnet-bridge/Bridge.BinaryDispatch.cs +++ b/dotnet-bridge/Bridge.BinaryDispatch.cs @@ -106,8 +106,17 @@ internal static DispatchResult DispatchBin(ref BinReader r) { var assembly = r.ReadString16(); var typeName = r.ReadString16(); + + var interfaceCount = r.ReadI32(); + var interfaceNames = interfaceCount > 0 ? new string[interfaceCount] : []; + for (int i = 0; i < interfaceCount; i++) interfaceNames[i] = r.ReadString16(); + + var memberCount = r.ReadI32(); + var memberNames = memberCount > 0 ? new string[memberCount] : []; + for (int i = 0; i < memberCount; i++) memberNames[i] = r.ReadString16(); + var callbackId = r.ReadI32(); - return CreateJsSubclass(NullIfEmpty(assembly), typeName, callbackId); + return CreateJsSubclass(NullIfEmpty(assembly), typeName, callbackId, interfaceNames, memberNames); } if (op == 0x0B) // get CLR-only property by raw IInspectable ptr (CLR reflection fallback) diff --git a/dotnet-bridge/Bridge.Proxy.cs b/dotnet-bridge/Bridge.Proxy.cs index bce45ce..1708187 100644 --- a/dotnet-bridge/Bridge.Proxy.cs +++ b/dotnet-bridge/Bridge.Proxy.cs @@ -14,8 +14,12 @@ namespace NativeScriptBridge; public static partial class Bridge { - // Cache for dynamically generated proxy types (dev-only fallback). - private static readonly ConcurrentDictionary s_dynamicProxyCache = new(); + // Cache for dynamically generated proxy types (dev-only fallback). Keyed by base type PLUS + // the exact set of interfaces/members a given JS `overrides` object asked for, so different + // JS subclasses of the same base type (different override sets) get distinct emitted types. + private readonly record struct ProxyTypeKey(Type BaseType, string InterfaceKey, string MemberKey); + private static readonly ConcurrentDictionary s_dynamicProxyCache = new(); + private static int s_dynamicProxyTypeCounter = 0; private static readonly AssemblyBuilder? s_dynamicAssembly = CreateDynamicAssembly(); private static readonly ModuleBuilder? s_dynamicModule = CreateDynamicModule(s_dynamicAssembly); @@ -168,22 +172,35 @@ private static bool DynamicProxiesEnabled() return null; } - private static Type GetOrCreateDynamicProxyType(Type baseType) + private static Type GetOrCreateDynamicProxyType(Type baseType, string[] interfaceNames, string[] memberNames) { - return s_dynamicProxyCache.GetOrAdd(baseType, bt => CreateDynamicProxyType(bt)); + var interfaceKey = string.Join(",", interfaceNames.OrderBy(n => n, StringComparer.Ordinal)); + var memberKey = string.Join(",", memberNames.OrderBy(n => n, StringComparer.Ordinal)); + var key = new ProxyTypeKey(baseType, interfaceKey, memberKey); + return s_dynamicProxyCache.GetOrAdd(key, _ => CreateDynamicProxyType(baseType, interfaceNames, memberNames)); } - private static Type CreateDynamicProxyType(Type baseType) + private static Type CreateDynamicProxyType(Type baseType, string[] interfaceNames, string[] memberNames) { - + if (s_dynamicModule == null) throw new InvalidOperationException("Dynamic proxy generation not available in this environment"); if (baseType.IsSealed) throw new InvalidOperationException($"Cannot derive from sealed type {baseType.FullName}"); + var interfaceTypes = interfaceNames + .Select(n => ResolveType(null, n) ?? throw new TypeLoadException($"Interface type not found: {n}")) + .ToArray(); + + // Members JS actually overrides. Only base virtuals in this set get an IL override + // emitted — anything else is left alone so the real base implementation stays live in + // the vtable (no "call base" IL needed, the base method was simply never touched). + var memberSet = new HashSet(memberNames, StringComparer.Ordinal); + var safeName = (baseType.FullName ?? Guid.NewGuid().ToString()).Replace('.', '_'); - var typeName = $"NSWinRTDynamicProxies.{safeName}_JsProxy"; + var uniqueSuffix = Interlocked.Increment(ref s_dynamicProxyTypeCounter); + var typeName = $"NSWinRTDynamicProxies.{safeName}_JsProxy_{uniqueSuffix}"; var tb = s_dynamicModule.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class, baseType); @@ -265,69 +282,137 @@ private static Type CreateDynamicProxyType(Type baseType) } } - // Override all non-final virtual instance methods (skip ref/out and generic methods) - var methods = baseType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) - .Where(m => m.IsVirtual && !m.IsFinal && !m.IsGenericMethod && !m.IsConstructor) + // Shared by both loops below, keyed by "Name(Param1FullName,Param2FullName,...)" so a + // member that's both an overridden base virtual and a requested interface member (e.g. + // the base class already implements that interface) reuses one emitted body instead of + // tripping a "duplicate member" TypeBuilder error. + var definedSignatures = new Dictionary(StringComparer.Ordinal); + static string SignatureKey(string name, Type[] paramTypes) => + name + "(" + string.Join(",", paramTypes.Select(p => p.FullName)) + ")"; + + // Override only the base virtuals JS actually asked for (memberSet). Anything not in + // that set is simply never touched, so the base implementation stays live in the vtable — + // no "call base" IL needed. (Skip ref/out and generic methods — unsupported.) + var virtualMethods = baseType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + .Where(m => m.IsVirtual && !m.IsFinal && !m.IsGenericMethod && !m.IsConstructor && memberSet.Contains(m.Name)) .ToArray(); - foreach (var mi in methods) + foreach (var mi in virtualMethods) { var parameters = mi.GetParameters(); if (parameters.Any(p => p.ParameterType.IsByRef)) continue; var paramTypes = parameters.Select(p => p.ParameterType).ToArray(); - var mb = tb.DefineMethod(mi.Name, - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, - mi.CallingConvention, mi.ReturnType, paramTypes); - - var ilg = mb.GetILGenerator(); - var argsLocal = ilg.DeclareLocal(typeof(object[])); - ilg.Emit(OpCodes.Ldc_I4, paramTypes.Length); - ilg.Emit(OpCodes.Newarr, typeof(object)); - ilg.Emit(OpCodes.Stloc, argsLocal); - - for (int i = 0; i < paramTypes.Length; i++) + var sigKey = SignatureKey(mi.Name, paramTypes); + if (!definedSignatures.TryGetValue(sigKey, out var mb)) { - ilg.Emit(OpCodes.Ldloc, argsLocal); - ilg.Emit(OpCodes.Ldc_I4, i); - ilg.Emit(OpCodes.Ldarg, i + 1); - if (paramTypes[i].IsValueType) ilg.Emit(OpCodes.Box, paramTypes[i]); - ilg.Emit(OpCodes.Stelem_Ref); + mb = EmitProxyMethodBody(tb, mi.Name, + MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, + mi.CallingConvention, mi.ReturnType, paramTypes, mi.Name); + definedSignatures[sigKey] = mb; } - if (mi.ReturnType == typeof(void)) + tb.DefineMethodOverride(mb, mi); + } + + // Interfaces: every requested interface (plus any interfaces *those* extend, since + // AddInterfaceImplementation only registers the interface named, not its ancestors) must + // have every member implemented — the CLR requires it, unlike base-class virtuals where + // skipping is fine. Members JS doesn't override fall back to default/no-op via the same + // generic dispatcher (ProxyRuntime.InvokeMethodTyped/InvokeVoid already do this). + if (interfaceTypes.Length > 0) + { + var allInterfaceTypes = new List(); + void CollectInterfaces(Type t) { - var invokeVoid = typeof(Bridge).GetNestedType("ProxyRuntime", BindingFlags.Public | BindingFlags.Static)!.GetMethod("InvokeVoid", BindingFlags.Public | BindingFlags.Static)!; - ilg.Emit(OpCodes.Ldarg_0); - ilg.Emit(OpCodes.Ldstr, mi.Name); - ilg.Emit(OpCodes.Ldloc, argsLocal); - ilg.Emit(OpCodes.Call, invokeVoid); - ilg.Emit(OpCodes.Ret); + if (allInterfaceTypes.Contains(t)) return; + allInterfaceTypes.Add(t); + foreach (var parent in t.GetInterfaces()) CollectInterfaces(parent); } - else + foreach (var ifaceType in interfaceTypes) CollectInterfaces(ifaceType); + + foreach (var ifaceType in allInterfaceTypes) tb.AddInterfaceImplementation(ifaceType); + + foreach (var ifaceType in allInterfaceTypes) { - var proxyRuntimeType = typeof(Bridge).GetNestedType("ProxyRuntime", BindingFlags.Public | BindingFlags.Static)!; - var gm = proxyRuntimeType.GetMethod("InvokeMethodTyped", BindingFlags.Public | BindingFlags.Static)!.MakeGenericMethod(mi.ReturnType); - ilg.Emit(OpCodes.Ldarg_0); - ilg.Emit(OpCodes.Ldstr, mi.Name); - ilg.Emit(OpCodes.Ldloc, argsLocal); - ilg.Emit(OpCodes.Call, gm); - ilg.Emit(OpCodes.Ret); - } + foreach (var mi in ifaceType.GetMethods()) + { + var parameters = mi.GetParameters(); + if (parameters.Any(p => p.ParameterType.IsByRef)) continue; - tb.DefineMethodOverride(mb, mi); + var paramTypes = parameters.Select(p => p.ParameterType).ToArray(); + var sigKey = SignatureKey(mi.Name, paramTypes); + if (!definedSignatures.TryGetValue(sigKey, out var mb)) + { + mb = EmitProxyMethodBody(tb, mi.Name, + MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final + | MethodAttributes.HideBySig | MethodAttributes.NewSlot, + mi.CallingConvention, mi.ReturnType, paramTypes, mi.Name); + definedSignatures[sigKey] = mb; + } + + tb.DefineMethodOverride(mb, mi); + } + } } return tb.CreateTypeInfo()!.AsType(); } - private static DispatchResult CreateJsSubclass(string? assemblyName, string typeName, int callbackId) + // Shared IL body for both base-virtual overrides and interface-member implementations: box + // args into an object[], forward to ProxyRuntime.InvokeVoid/InvokeMethodTyped by name. + private static MethodBuilder EmitProxyMethodBody( + TypeBuilder tb, string emittedName, MethodAttributes attrs, CallingConventions callingConvention, + Type returnType, Type[] paramTypes, string dispatchName) + { + var mb = tb.DefineMethod(emittedName, attrs, callingConvention, returnType, paramTypes); + var ilg = mb.GetILGenerator(); + var argsLocal = ilg.DeclareLocal(typeof(object[])); + ilg.Emit(OpCodes.Ldc_I4, paramTypes.Length); + ilg.Emit(OpCodes.Newarr, typeof(object)); + ilg.Emit(OpCodes.Stloc, argsLocal); + + for (int i = 0; i < paramTypes.Length; i++) + { + ilg.Emit(OpCodes.Ldloc, argsLocal); + ilg.Emit(OpCodes.Ldc_I4, i); + ilg.Emit(OpCodes.Ldarg, i + 1); + if (paramTypes[i].IsValueType) ilg.Emit(OpCodes.Box, paramTypes[i]); + ilg.Emit(OpCodes.Stelem_Ref); + } + + if (returnType == typeof(void)) + { + var invokeVoid = typeof(Bridge).GetNestedType("ProxyRuntime", BindingFlags.Public | BindingFlags.Static)!.GetMethod("InvokeVoid", BindingFlags.Public | BindingFlags.Static)!; + ilg.Emit(OpCodes.Ldarg_0); + ilg.Emit(OpCodes.Ldstr, dispatchName); + ilg.Emit(OpCodes.Ldloc, argsLocal); + ilg.Emit(OpCodes.Call, invokeVoid); + ilg.Emit(OpCodes.Ret); + } + else + { + var proxyRuntimeType = typeof(Bridge).GetNestedType("ProxyRuntime", BindingFlags.Public | BindingFlags.Static)!; + var gm = proxyRuntimeType.GetMethod("InvokeMethodTyped", BindingFlags.Public | BindingFlags.Static)!.MakeGenericMethod(returnType); + ilg.Emit(OpCodes.Ldarg_0); + ilg.Emit(OpCodes.Ldstr, dispatchName); + ilg.Emit(OpCodes.Ldloc, argsLocal); + ilg.Emit(OpCodes.Call, gm); + ilg.Emit(OpCodes.Ret); + } + + return mb; + } + + private static DispatchResult CreateJsSubclass( + string? assemblyName, string typeName, int callbackId, string[] interfaceNames, string[] memberNames) { EnsureProxyDispatcherCallbacksRegistered(); s_pendingProxyCallbackId.Value = callbackId; - // Try to find a statically-generated proxy type first. + // Try to find a statically-generated proxy type first (Mechanism A: sbg-compiled into + // the app itself — already has any requested interfaces baked into real C# source). Type? t = FindGeneratedProxyType(typeName); if (t is null) { @@ -342,14 +427,14 @@ private static DispatchResult CreateJsSubclass(string? assemblyName, string type resolveFrom = assemblyName; } - // Resolve the WinRT/base type and optionally emit a dynamic proxy (dev-only). + // Resolve the WinRT/base type and optionally emit a dynamic proxy (Mechanism B fallback). var baseType = ResolveType(null, resolveFrom) ?? ResolveType(assemblyName, typeName) ?? throw new TypeLoadException($"Type not found: {resolveFrom} (proxy: {typeName}, assembly: {assemblyName})"); - + if (baseType.IsClass && !baseType.IsSealed) { - try { t = GetOrCreateDynamicProxyType(baseType); } + try { t = GetOrCreateDynamicProxyType(baseType, interfaceNames, memberNames); } catch (Exception) { t = baseType; } } else @@ -371,6 +456,14 @@ private static DispatchResult CreateJsSubclass(string? assemblyName, string type // the pending callback id when dynamic proxies don't call it. try { ProxyInitializeInstance(instance, typeName); } catch { } + // Force COM CCW vtable creation for any implemented WinRT interfaces now, rather than + // relying on it happening implicitly the first time the instance crosses the ABI boundary. + // Best-effort/reflection-only — no-ops cleanly when CsWinRT isn't loaded (e.g. xunit host). + if (interfaceNames.Length > 0) + { + TryActivateWinRTInterfaces(instance); + } + // Box the instance into a handle to return to the runtime. var result = Box(instance); @@ -392,6 +485,50 @@ private static DispatchResult CreateJsSubclass(string? assemblyName, string type return result; } + // Locates CsWinRT's ComWrappersSupport via reflection (same style as the WinRT.IWinRTObject + // lookup in ObtainNativePtr — no compile-time reference needed, since DotNetBridge.csproj is a + // dependency-free net9.0 library and CsWinRT is only ever loaded into the process by the WinUI + // app itself) and asks it to build a real COM CCW for the instance's implemented WinRT + // interfaces now, via CsWinRT's JIT reflection-fallback vtable path (works for types it never + // saw at compile time — see plan doc for the CsWinRT version/AOT caveats). Best-effort: no-ops + // when CsWinRT isn't loaded, e.g. the xunit test host has no WinUI/CsWinRT at all. + private static void TryActivateWinRTInterfaces(object instance) + { + try + { + Type? supportType = null; + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + try + { + supportType = asm.GetType("WinRT.ComWrappersSupport"); + if (supportType != null) break; + } + catch { } + } + if (supportType == null) return; + + foreach (var name in new[] { "CreateCCWForObject", "GetOrCreateComInterfaceForObject" }) + { + foreach (var candidate in supportType.GetMethods(BindingFlags.Public | BindingFlags.Static) + .Where(m => m.Name == name)) + { + try + { + var target = candidate.IsGenericMethodDefinition + ? candidate.MakeGenericMethod(instance.GetType()) + : candidate; + var ps = target.GetParameters(); + if (ps.Length == 1) { target.Invoke(null, [instance]); return; } + if (ps.Length == 2 && ps[1].ParameterType == typeof(Guid)) { target.Invoke(null, [instance, Guid.Empty]); return; } + } + catch { /* try the next overload/name */ } + } + } + } + catch { /* best-effort only */ } + } + private static void ProxyInitializeInstance(object instance, string typeName) { var cb = s_pendingProxyCallbackId.Value; diff --git a/integration-tests/tests/new_features.rs b/integration-tests/tests/new_features.rs index 88ba1a4..9ba5e3f 100644 --- a/integration-tests/tests/new_features.rs +++ b/integration-tests/tests/new_features.rs @@ -507,6 +507,60 @@ fn dotnet_environment_get_machine_name() { ); } +// Managed-subclass proxy system (NSWinRT.proxy.createManagedSubclass / Bridge.Proxy.cs's dynamic +// dev-only fallback proxy). dotnet-bridge-tests exercises the C# IL-emission side directly via +// Bridge.DispatchBin, bypassing the JS engine entirely — these run the full real path instead: +// JS -> __nsDotNetCreateJsSubclass -> CreateJsSubclass (dynamic proxy emitted, IL overrides only +// the requested members) -> instance call reflects on the real derived type -> virtual dispatch +// hits the emitted override -> callback fires back into this exact JS closure. +#[test] +fn dotnet_managed_subclass_overridden_method_dispatches_to_js() { + if !dotnet_bridge_available() { + return; + } + let mut rt = Runtime::new("."); + assert_js( + &mut rt, + r#" + (function(){ + var called = false; + var obj = NSWinRT.proxy.createManagedSubclass('', 'System.Object', { + ToString: function () { called = true; return 'js-tostring'; } + }); + if (!obj || typeof obj !== 'object' || obj.__handle == null) return false; + var result = obj.ToString(); + return called === true && result === 'js-tostring'; + })() + "#, + "overridden ToString() on a managed subclass should dispatch to the JS override", + ); +} + +#[test] +fn dotnet_managed_subclass_unoverridden_virtual_falls_back_to_base() { + if !dotnet_bridge_available() { + return; + } + let mut rt = Runtime::new("."); + assert_js( + &mut rt, + r#" + (function(){ + var called = false; + // Override GetHashCode only; ToString is left untouched and must run the real + // System.Object implementation, never asking JS. + var obj = NSWinRT.proxy.createManagedSubclass('', 'System.Object', { + GetHashCode: function () { called = true; return 42; } + }); + if (!obj || typeof obj !== 'object' || obj.__handle == null) return false; + var result = obj.ToString(); + return called === false && typeof result === 'string' && result.indexOf('System.Object') !== -1; + })() + "#, + "un-overridden virtual on a managed subclass should run the real base implementation", + ); +} + #[test] fn event_reads_null_before_assignment() { let mut rt = Runtime::new("."); diff --git a/metadata/src/declarations/class_declaration.rs b/metadata/src/declarations/class_declaration.rs index 9c1def1..59fd638 100644 --- a/metadata/src/declarations/class_declaration.rs +++ b/metadata/src/declarations/class_declaration.rs @@ -166,6 +166,21 @@ impl ClassDeclaration { .flatten() } + /// Full name of the default interface, including generic instances (e.g. StringMap's + /// `Windows.Foundation.Collections.IMap`2`) which `default_interface()` + /// cannot return (its downcast only admits plain `InterfaceDeclaration`s). + pub fn default_interface_full_name(&self) -> Option<&str> { + self.default_interface + .get_or_init(|| { + ClassDeclaration::make_default_interface( + self.base.base().metadata(), + self.base.base().token(), + ) + }) + .as_ref() + .map(|f| f.as_declaration().full_name()) + } + pub fn is_instantiable(&self) -> bool { !self.initializers().is_empty() } diff --git a/packages/.gitignore b/packages/.gitignore new file mode 100644 index 0000000..1bf4115 --- /dev/null +++ b/packages/.gitignore @@ -0,0 +1,7 @@ +# Engine-variant frameworks are generated by `template/build.ps1 -Engine `: the shared +# scaffolding is copied from template/framework and the runtime DLL is built in. Build artifacts, +# not source — don't commit them. +windows-*/framework/ + +# Per-package Cargo output (the engine crates are excluded from the workspace, so they build here). +windows-*/target/ diff --git a/packages/README.md b/packages/README.md new file mode 100644 index 0000000..3b0a3a1 --- /dev/null +++ b/packages/README.md @@ -0,0 +1,151 @@ +# NativeScript Windows — engine packages + +Each subdirectory is one **engine variant** of the NativeScript Windows app runtime, published as +`@nativescript/windows-`. A variant is **the same framework** as `@nativescript/windows` +(the WinUI 3 app template, dotnet-bridge, and tools) — only the runtime DLL differs. All of +`runtime/src/napi_engine/*` is engine-neutral and reused verbatim; a package supplies the engine + +its Node-API provider + a thin adapter that exposes the runtime DLL's C ABI over that engine. + +## Interchangeable with `@nativescript/windows` + +`@nativescript/windows` and `@nativescript/windows-` are drop-in replacements: an app swaps +the dependency and rebuilds, and it runs unchanged on the other engine. This works because every +variant ships the **same** framework and a `nativescript.dll` that exposes the **same** C ABI the +WinUI 3 host P/Invokes (`runtime_init` / `runtime_runscript` / `runtime_pump_timers` / …). The +package metadata is uniform too — same `files`, and a `nativescript: { runtime, engine }` block — +so tooling resolves any of them the same way. + +Producing a variant is a **build flag**, not a separate template (see *Building* below): + +```sh +template/build.ps1 # @nativescript/windows (classic V8, default) +template/build.ps1 -Engine quickjs # @nativescript/windows-quickjs +``` + +## Naming (mirrors iOS/Android) +Same convention as `@nativescript/android` / `@nativescript/ios`: +- **`@nativescript/windows`** — the **classic V8** app runtime (the `runtime` crate + rusty_v8, + default features), built via the `nativescript` cdylib. The current/default runtime. +- **`@nativescript/windows-`** — the engine variants in this dir (`-quickjs`, `-hermes`, + `-v8`, `-jsc`), each a napi-backed runtime. Like `@nativescript/android-jsc`. +- **`@nativescript/windows-napi`** — a separate consumption mode (the `.node` in `../windows-napi`): + run WinRT interop from an existing **Node/Bun/Deno** host. Not an app runtime; Windows-specific. + +| Package | npm | Engine binary (Windows) | napi in binary? | +|---|---|---|---| +| `windows-quickjs` | `@nativescript/windows-quickjs` | compiled from source (quickjs-ng + napi-android shim) | shim (compiled) | +| `windows-hermes` | `@nativescript/windows-hermes` | **prebuilt** `hermes.dll` (Microsoft.JavaScript.Hermes NuGet) | ✅ yes (napi+jsr) | +| `windows-v8` | `@nativescript/windows-v8` | **in-tree**: rusty_v8 (V8 14.7, prebuilt static lib + headers) | napi-android v8 shim, ported to V8 14.7 | +| `windows-jsc` | `@nativescript/windows-jsc` | **Playwright's** `webkit-win64` `JavaScriptCore.dll` (current; buildbot is dead) | napi-android JSC shim over the public C API (+ 2 Win fixes) | + +All four supported engines run the full WinRT runtime with no Node. (PrimJS was dropped — its +concurrent GC is hard-coded to POSIX `mmap`/pthreads and it has no Windows build.) + +Prebuilt-availability notes (checked Jul 2026): **V8** engine is already in-tree (rusty_v8). **JSC**: +the WebKit WinCairo buildbot is dead (last Windows build Sept 2024) and the `microsoft.javascript.jsc` +/ `javascriptcore` NuGet ids are 1-byte placeholders — the current source is **Playwright's** +`webkit-win64` build (rebuilt continuously; ships `JavaScriptCore.dll` + ICU). `microsoft.chakracore` +(1.11.x) is a real Windows engine but JSRT, not napi; `openkraken/jsc` is Android/macOS only. + + +## Layout of a package +``` +packages/windows-/ + Cargo.toml # excluded from the workspace (C build / prebuilt link) + build.rs # compile engine + shim, or link the prebuilt + copy DLLs + src/lib.rs # engine bindings + `abi` module (the nativescript.dll C ABI) + src/abi.rs # engine → runtime-DLL adapter (host_dll feature); see below + src/main.rs # standalone host: bring up napi_env → napi_engine → run app + vendor/ # committed engine binaries (android's model: in-repo, no LFS) + package.json # @nativescript/windows- (same contract as classic) + framework/ # generated by the engine build — not committed (see .gitignore) + README.md +``` +Shared host code (native crash reporter, demo harness) is in `packages/common` +(`ns-windows-common`). + +## The engine → runtime-DLL adapter + +The WinUI 3 host loads `framework/libs//nativescript.dll` and P/Invokes its C ABI +(`runtime_init`, `runtime_deinit`, `runtime_runscript`, `runtime_pump_timers`, +`runtime_notify_app_event`, `runtime_set_local_folder`, `runtime_get_last_js_error` / +`runtime_free_js_error`, `runtime_install_ctrlc_handler`, `runtime_has_devtools`). The classic +runtime implements this in the `nativescript` crate over rusty_v8. Each engine variant implements +the **same** ABI in `src/abi.rs`, compiled into the package's cdylib under the `host_dll` feature. + +The engine-neutral work — WinRT init, installing the globals + `Windows` namespace, and one turn of +the event loop — is shared in `runtime::napi_engine::host_abi` (`initialize_runtime` / `pump_once`). An +adapter only wires the three engine-specific pieces on top: create the `napi_env` (the engine's +shim), evaluate a script, and drain microtasks. **`windows-quickjs/src/abi.rs` is the reference +implementation**; the other engines follow the identical shape with their own shim. + +> Build status: all four per-engine `nativescript.dll` cdylibs have been **built and validated** +> here (`cargo build --features host_dll` for each package). Each was loaded by a foreign .NET host +> — a C# program that P/Invokes the runtime C ABI exactly like the WinUI 3 app — where +> `runtime_init` succeeds, `runtime_runscript` runs JS, and a real WinRT round-trip +> (`Windows.Data.Json` → `{"a":7}`) works. This required one Windows-port fix: the napi engine +> DLLs resolve their `napi_*` provider from the loaded module (the `.exe` OR the cdylib) rather +> than always the process `.exe` — see `packages/vendor/napi-sys` (a `[patch.crates-io]` in each +> engine package). The classic runtime uses rusty_v8 (no napi-sys) and never hit this. Building a +> cdylib still needs the engine toolchain + vendored engine binaries (each package is excluded from +> the workspace), so a plain workspace `cargo build` does not compile them. + +## Run an app (standalone-host `.exe`, for dev/bench) +```sh +nativescript-windows path/to/app.js # e.g. packages/test/test-app.js +``` +`packages/test/interop-check.js` exercises the shared `NSWinRT.interop` surface (typed-value/ +`reference` boxing, Pointer/OutParam, buffer + DateTime helpers) and is expected to pass on +all four engines. With a script argument the host runs it and then drives the **standalone event loop** +(`runtime::napi_engine::event_loop`) until the app goes idle: Windows message pump (STA WinRT +async completions, delegate invokes), `setTimeout`/`setInterval` timers +(`napi_engine::timers`, install-if-missing), and the engine's microtask drain. The prelude +(`packages/common/src/prelude.rs`) provides `queueMicrotask` and `NSWinRT.toPromise(op)`; +`toPromise` ref-counts the loop via the `__nsLoopRetain`/`__nsLoopRelease` natives, so awaited +WinRT operations keep the process alive exactly until they settle. Without a script argument the +host runs its staged demo (including an `async event loop` stage) and exits. + +Per-engine loop notes: Hermes is created with `jsr_config_set_explicit_microtasks` (bare hosts +have no `setImmediate` for its RN-style promise scheduling); V8/JSC ship inspector-only inert +`console` objects that the hosts delete so the runtime console installs; microtask drain hooks +are `qjs_execute_pending_jobs` / `js_execute_pending_jobs` / `jsr_drain_microtasks`. + +## Building a framework (the flag) + +The framework is built by `template/build.ps1`; `-Engine` selects the runtime DLL. It's the same +template for every engine — only `framework/libs/` differs. + +```sh +# Classic V8 — stages into template/framework (x64 + arm64, release + devtools). +template/build.ps1 + +# An engine variant — copies the shared scaffolding from template/framework, builds the engine +# cdylib as framework/libs/x64/nativescript.dll, and stages it into packages/windows-/framework. +# (Build classic once first so the shared scaffolding exists to copy. Variants are x64, no devtools.) +template/build.ps1 -Engine quickjs +template/build.ps1 -Engine hermes +template/build.ps1 -Engine jsc # also needs a real JavaScriptCore.lib in windows-jsc/vendor +``` + +Each variant's `package.json` `build` script is just that invocation, so `npm run build` inside a +package produces its framework. Prebuilt engine binaries are committed in each package's `vendor/` +(provenance + refresh in each `vendor/README.md`), the same way napi-android commits its `libs/`. + +## Publishing + +**`@nativescript/windows` + `@nativescript/windows-` — app runtimes:** build the framework +for the engine (above), then `npm publish` the package (each is `os:["win32"], cpu:["x64"]`; the +classic package also ships arm64 + devtools). The CLI picks one, like android's `jsEngine` — and +because the packages are interchangeable, switching is a dependency swap. + +**`@nativescript/windows-napi` — the Node/Bun/Deno `.node`** (`../windows-napi`): +napi-rs flow, **implemented in `.github/workflows/windows-napi.yml`**: a build matrix per triple +(`x86_64-pc-windows-msvc`, `aarch64-pc-windows-msvc`) runs `napi build --platform --release +--target ` → `windows..node` artifacts (the x64 job also runs the 366-check test +suite, non-blocking on server SKUs); pushing a **`windows-napi-v*` tag** triggers the publish job: +`napi artifacts` distributes the .node files into the committed `windows-napi/npm//` +sub-packages, `napi prepublish` (the `prepublishOnly` script) publishes those, then the root +package publishes with them as `optionalDependencies`. Needs the `NPM_TOKEN` repo secret. +`index.js`/`index.d.ts`/`package-lock.json` are generated but committed (the publish job doesn't +build). If arm64 proves unbuildable (rusty_v8/libffi cross), drop the triple from the workflow +matrix, `napi.triples`, `optionalDependencies`, and `npm/win32-arm64-msvc/`. diff --git a/packages/common/Cargo.lock b/packages/common/Cargo.lock new file mode 100644 index 0000000..f05bda5 --- /dev/null +++ b/packages/common/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ns-windows-common" +version = "0.1.0" diff --git a/packages/common/Cargo.toml b/packages/common/Cargo.toml new file mode 100644 index 0000000..62d8557 --- /dev/null +++ b/packages/common/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "ns-windows-common" +version = "0.1.0" +edition = "2021" +description = "Shared JS runtime support for the NativeScript Windows standalone-engine packages (prelude, URL polyfill) — used by the shipped napi addon/cdylib as well as the demo bin" + +[lib] +crate-type = ["rlib"] diff --git a/packages/common/src/lib.rs b/packages/common/src/lib.rs new file mode 100644 index 0000000..543cd6d --- /dev/null +++ b/packages/common/src/lib.rs @@ -0,0 +1,8 @@ +//! Shared runtime support for the NativeScript Windows standalone-engine packages +//! (`windows-quickjs`, `windows-hermes`, …): the JS prelude (queueMicrotask + NSWinRT) and the +//! URL/URLSearchParams polyfill, injected by both the shipped napi addon/cdylib and the +//! `nativescript-windows` demo bin. See `ns-windows-demo` for demo-only, bin-only support +//! (crash reporter, self-test harness) that the shipped addon never touches. + +pub mod prelude; +pub mod url_polyfill; diff --git a/packages/common/src/prelude.rs b/packages/common/src/prelude.rs new file mode 100644 index 0000000..2b2e74f --- /dev/null +++ b/packages/common/src/prelude.rs @@ -0,0 +1,179 @@ +//! JS runtime prelude for the standalone hosts, evaluated after `install_globals` and the URL +//! polyfill. Provides the pieces a bare engine lacks that are pure JS over the napi natives: +//! - `queueMicrotask` (over the engine's own promise queue) when the engine doesn't expose it, +//! - `NSWinRT.toPromise(op)` — converts a WinRT IAsyncOperation/IAsyncAction to a Promise +//! (same idea as nswinrt.js's `toPromise` for the Node package). It holds the event loop +//! open via the `__nsLoopRetain`/`__nsLoopRelease` natives while an operation is +//! outstanding, so `await NSWinRT.toPromise(op)` "just works" under `run_event_loop`. +//! +//! Kept engine-conservative (function expressions, no async/await syntax) so one source runs +//! unchanged on QuickJS, Hermes, V8, and JSC. + +pub const PRELUDE: &str = r#" +(function (g) { + 'use strict'; + + // Node-style `global` alias for `globalThis` — @nativescript/core and webpack `target: 'node'` + // output both reference bare `global` (e.g. `global.foo = ...`). Classic rusty_v8 sets this via + // `init_global` (a read-only own property); defined the same way here so it runs on every napi + // engine. + if (typeof g.global === 'undefined') { + Object.defineProperty(g, 'global', { value: g, writable: false, configurable: true }); + } + + if (typeof g.queueMicrotask !== 'function') { + g.queueMicrotask = function (cb) { + if (typeof cb !== 'function') { throw new TypeError('queueMicrotask expects a function'); } + Promise.resolve().then(cb); + }; + } + + var retain = typeof g.__nsLoopRetain === 'function' ? g.__nsLoopRetain : function () {}; + var release = typeof g.__nsLoopRelease === 'function' ? g.__nsLoopRelease : function () {}; + + function statusEnum() { + try { return g.Windows.Foundation.AsyncStatus; } + catch (e) { return { Started: 0, Completed: 1, Canceled: 2, Error: 3 }; } + } + + function normalizeStatus(status) { + if (status == null) { return NaN; } + if (typeof status === 'number') { return status; } + var n = Number(status); + return isNaN(n) ? NaN : n; + } + + // Convert a WinRT IAsyncOperation/IAsyncAction proxy to a JS Promise via its Completed event, + // Status property, and GetResults() method. Mirrors nswinrt.js (Node package); the pump there + // is a ref-counted Node timer, here it is the standalone event loop's keep-alive counter. + function toPromise(op) { + if (op == null || (typeof op !== 'object' && typeof op !== 'function')) { + return Promise.resolve(op); + } + if (typeof op.then === 'function' && !('Completed' in op)) { return op; } + + var S = statusEnum(); + retain(); + return new Promise(function (resolve, reject) { + var settled = false; + function done(fn, arg) { settled = true; release(); fn(arg); } + function settle(override) { + if (settled) { return; } + try { + var status = normalizeStatus(override !== undefined ? override : op.Status); + if (status === S.Completed || status === 1) { + done(resolve, typeof op.GetResults === 'function' ? op.GetResults() : undefined); + } else if (status === S.Canceled || status === 2) { + done(reject, new Error('WinRT async operation was canceled')); + } else if (status === S.Error || status === 3) { + done(reject, op.ErrorCode || new Error('WinRT async operation failed')); + } + } catch (err) { done(reject, err); } + } + + var initial = normalizeStatus(op.Status); + if (!isNaN(initial) && initial !== 0) { settle(initial); return; } + op.Completed = function (asyncInfo, asyncStatus) { settle(asyncStatus); }; + // Race guard: it may have completed between the status read and handler assignment. + var race = normalizeStatus(op.Status); + if (!isNaN(race) && race !== 0) { settle(race); } + }); + } + + g.NSWinRT = g.NSWinRT || {}; + g.NSWinRT.toPromise = toPromise; +})(globalThis); + +// CommonJS shim: webpack `target: 'node'` bundles (what NativeScript apps are built as) expect +// `require`/`module`/`exports`/`__dirname`/`__filename` as globals — normally supplied by Node's +// own module wrapper. This runtime is not Node, so we supply them here the same way the classic +// rusty_v8 runtime does (`global_fns::HELPER_SOURCE`), backed by the `__nsResolveModulePath` / +// `__nsReadTextFile` / `__nsAppRoot` natives `host_abi::initialize_runtime` installs. Without this, every +// chunk (runtime.js/vendor.js/the app bundle) throws `ReferenceError: require is not defined` on +// evaluation. +(function (g) { + 'use strict'; + + if (typeof g.require === 'function' && typeof g.module !== 'undefined') { + return; + } + if (typeof g.__nsResolveModulePath !== 'function' || typeof g.__nsReadTextFile !== 'function') { + return; + } + + var cjsCache = new Map(); + + function resolveSpecifier(specifier, callerFile) { + if (typeof specifier !== 'string' || specifier.length === 0) { + throw new Error('Cannot find module: ' + String(specifier)); + } + var appRoot = (g.__nsAppRoot || '').replace(/[\\\/]+$/, ''); + + // NativeScript tilde alias: ~/foo -> {appRoot}/app/foo + if (specifier.charAt(0) === '~' && specifier.charAt(1) === '/') { + var abs = appRoot + '\\app\\' + specifier.substring(2).replace(/\//g, '\\'); + return g.__nsResolveModulePath(abs, '', appRoot) || abs; + } + + // Relative (./foo, ../foo) or bare name: use native resolver with caller context. + // Fall back to app/bundle.js as parent so top-level require('./chunk.js') works. + var parent = callerFile || (appRoot + '\\app\\bundle.js'); + return g.__nsResolveModulePath(specifier, parent, appRoot); + } + + function makeRequire(callerFile) { + return function require(specifier) { + var resolved = resolveSpecifier(specifier, callerFile); + if (!resolved) { throw new Error('Cannot find module: ' + specifier); } + + var key = resolved.replace(/\\/g, '/').toLowerCase(); + if (cjsCache.has(key)) { return cjsCache.get(key).exports; } + + var mod = { id: resolved, filename: resolved, exports: {} }; + cjsCache.set(key, mod); // set before eval to break circular deps + + var isJson = key.slice(-5) === '.json'; + var content = g.__nsReadTextFile(resolved); + + if (isJson) { + try { mod.exports = JSON.parse(content || '{}'); } catch (_e) { mod.exports = {}; } + return mod.exports; + } + + var dirName = resolved.replace(/\//g, '\\').replace(/\\[^\\]*$/, ''); + var childRequire = makeRequire(resolved); + + try { + var factory = new Function('module', 'exports', 'require', '__filename', '__dirname', content); + factory(mod, mod.exports, childRequire, resolved, dirName); + } catch (e) { + cjsCache.delete(key); + throw e; + } + cjsCache.set(key, mod); + return mod.exports; + }; + } + + g.require = makeRequire(null); + + // Top-level CJS globals for scripts executed outside a factory wrapper (e.g. when the host + // calls runtime_runscript directly with a CJS file — runtime.js/vendor.js/the app bundle). + if (typeof g.module === 'undefined') { + var _topMod = { id: '
', exports: {} }; + Object.defineProperty(g, 'module', { value: _topMod, writable: true, configurable: true }); + Object.defineProperty(g, 'exports', { value: _topMod.exports, writable: true, configurable: true }); + } + + // Provide __dirname / __filename globals for webpack target:'node' bundles. webpack leaves + // these undefined when building for node (expects Node.js to provide them via its module + // wrapper); this runtime supplies the app directory as a reasonable fallback value. + if (typeof g.__dirname === 'undefined') { + var _appRoot2 = (g.__nsAppRoot || '').replace(/[\\\/]+$/, ''); + var _appDir = _appRoot2 + '\\app'; + Object.defineProperty(g, '__dirname', { value: _appDir, writable: true, configurable: true }); + Object.defineProperty(g, '__filename', { value: _appDir + '\\bundle.js', writable: true, configurable: true }); + } +})(globalThis); +'prelude-ok' +"#; diff --git a/packages/common/src/url_polyfill.rs b/packages/common/src/url_polyfill.rs new file mode 100644 index 0000000..44af55d --- /dev/null +++ b/packages/common/src/url_polyfill.rs @@ -0,0 +1,57 @@ +//! JS `URL` / `URLSearchParams` polyfill for standalone engines that lack them (QuickJS, Hermes, +//! JSC, V8-standalone; Node/Bun/Deno provide their own so it self-skips). It's backed by the native +//! `__urlParse` / `__urlWith` helpers installed by `runtime::napi_engine::globals::install_globals` +//! (WHATWG parsing via the Rust `url` crate). A host runs [`POLYFILL`] once after bring-up. + +/// Evaluate this once (via the host's script runner) to install `URL`/`URLSearchParams`. +pub const POLYFILL: &str = r#"(function(g){ + if (typeof g.URL !== 'undefined') return; + var P = g.__urlParse, W = g.__urlWith; + function enc(s){ return encodeURIComponent(s).replace(/%20/g,'+'); } + function dec(s){ return decodeURIComponent(String(s).replace(/\+/g,' ')); } + function parseQuery(q){ var out=[]; q=String(q||''); if(q.charAt(0)==='?')q=q.slice(1); + if(!q) return out; + q.split('&').forEach(function(p){ if(!p) return; var i=p.indexOf('='); + if(i<0) out.push([dec(p),'']); else out.push([dec(p.slice(0,i)),dec(p.slice(i+1))]); }); + return out; } + function USP(init){ this._p=[]; this._cb=null; + if(init instanceof USP){ this._p=init._p.map(function(x){return [x[0],x[1]];}); } + else if(typeof init==='string'){ this._p=parseQuery(init); } + else if(init && typeof init==='object'){ for(var k in init){ this._p.push([String(k),String(init[k])]); } } } + USP.prototype._sync=function(){ if(this._cb) this._cb(this.toString()); }; + USP.prototype.append=function(k,v){ this._p.push([String(k),String(v)]); this._sync(); }; + USP.prototype.set=function(k,v){ k=String(k); var seen=false; + this._p=this._p.filter(function(x){ if(x[0]===k){ if(!seen){seen=true; x[1]=String(v); return true;} return false; } return true; }); + if(!seen) this._p.push([k,String(v)]); this._sync(); }; + USP.prototype.get=function(k){ k=String(k); for(var i=0;i\t\t" lines for easy parsing. +(function () { + var N = 20000; // timed iterations per op + var WARM = 2000; // warmup iterations (let V8/JSC JIT settle) + var now = (typeof performance !== 'undefined' && performance.now) + ? function () { return performance.now(); } + : function () { return __time(); }; + + // Accumulate results and RETURN them (the script's completion value). Hosts print the returned + // string via Rust stdout — reliable under redirection, unlike napi console.log (WriteConsoleW). + var out = ''; + function bench(name, fn) { + var line; + try { + for (var i = 0; i < WARM; i++) fn(i); + var t0 = now(); + for (var i = 0; i < N; i++) fn(i); + var ms = now() - t0; + var ops = Math.round(N / (ms / 1000)); + line = 'BENCH\t' + name + '\t' + ms.toFixed(2) + '\t' + ops; + } catch (e) { + line = 'BENCH\t' + name + '\tERROR\t' + e; + } + out += line + '\n'; + console.log(line); // for the classic runtime (playground), whose console.log is captured + } + + var JV = Windows.Data.Json.JsonValue; + var JO = Windows.Data.Json.JsonObject; + + // static method call → instance proxy → instance method + number marshaling both ways + bench('static_call_getnumber', function (i) { return JV.CreateNumberValue(i).GetNumber(); }); + // activation (parameterless construction through the activation factory) + bench('construct_jsonobject', function () { return new JO(); }); + // instance method + proxy-as-argument marshaling + property read-back + bench('set_get_named', function (i) { + var o = new JO(); o.SetNamedValue('k', JV.CreateNumberValue(i)); return o.GetNamedNumber('k'); + }); + // string marshaling round-trip (JS string → HSTRING → JS string) + bench('string_roundtrip', function (i) { return JV.CreateStringValue('x' + i).GetString(); }); + // pure member resolution (namespace/ctor get-trap + metadata lookup, no invocation) + bench('member_resolve', function () { return JV.CreateNumberValue; }); + + console.log('BENCH_DONE'); + out += 'BENCH_DONE\n'; + return out; +})(); diff --git a/packages/demo/src/bench.rs b/packages/demo/src/bench.rs new file mode 100644 index 0000000..c62a120 --- /dev/null +++ b/packages/demo/src/bench.rs @@ -0,0 +1,5 @@ +//! The shared WinRT-interop microbenchmark workload (see `../bench.js`), embedded so the napi +//! standalone hosts can run the exact same script the classic runtime runs via `playground`. +//! A host evals [`WORKLOAD`] (when `NSWIN_BENCH` is set) after bring-up; it prints `BENCH\t…` lines. + +pub const WORKLOAD: &str = include_str!("../bench.js"); diff --git a/packages/demo/src/crash.rs b/packages/demo/src/crash.rs new file mode 100644 index 0000000..ff15d99 --- /dev/null +++ b/packages/demo/src/crash.rs @@ -0,0 +1,58 @@ +//! Last-chance native crash reporter. Windows calls the top-level unhandled-exception filter on +//! the *faulting* thread with its stack still intact, so `backtrace::Backtrace::new()` from inside +//! the filter captures the frames that led to the fault, symbolized via the host's PDB (release +//! profile `debug = true`). Same reporter used to root-cause the QuickJS host. + +use std::sync::atomic::{AtomicBool, Ordering}; +use windows::Win32::System::Diagnostics::Debug::EXCEPTION_POINTERS; + +// This windows crate version doesn't generate SetUnhandledExceptionFilter; declare it directly. +type TopLevelFilter = Option i32>; +#[link(name = "kernel32")] +extern "system" { + fn SetUnhandledExceptionFilter(f: TopLevelFilter) -> TopLevelFilter; +} + +static IN_HANDLER: AtomicBool = AtomicBool::new(false); + +unsafe extern "system" fn handler(info: *const EXCEPTION_POINTERS) -> i32 { + if IN_HANDLER.swap(true, Ordering::SeqCst) { + return 1; // EXCEPTION_EXECUTE_HANDLER → terminate + } + let (code, addr, access, data_addr) = if !info.is_null() { + let rec = (*info).ExceptionRecord; + if !rec.is_null() { + let (acc, da) = if (*rec).NumberParameters >= 2 { + ((*rec).ExceptionInformation[0], (*rec).ExceptionInformation[1]) + } else { + (usize::MAX, 0) + }; + ((*rec).ExceptionCode.0 as u32, (*rec).ExceptionAddress as usize, acc, da) + } else { + (0, 0, usize::MAX, 0) + } + } else { + (0, 0, usize::MAX, 0) + }; + let kind = match access { + 0 => "READ", + 1 => "WRITE", + 8 => "DEP/EXEC", + _ => "?", + }; + eprintln!( + "\n=== NATIVE CRASH: code=0x{code:08X} instr=0x{addr:X} {kind} of data_addr=0x{data_addr:X} ===" + ); + let bt = backtrace::Backtrace::new(); + eprintln!("{bt:?}"); + use std::io::Write; + std::io::stderr().flush().ok(); + 1 +} + +/// Install the top-level filter. Call once, early in `main`. +pub fn install() { + unsafe { + SetUnhandledExceptionFilter(Some(handler)); + } +} diff --git a/packages/demo/src/harness.rs b/packages/demo/src/harness.rs new file mode 100644 index 0000000..de2f650 --- /dev/null +++ b/packages/demo/src/harness.rs @@ -0,0 +1,169 @@ +//! Runs a list of labelled JS stages against an engine-supplied `eval` closure and prints a +//! uniform report. Engine-agnostic: each package supplies how to evaluate a script. + +use std::io::Write; + +/// Run each `(label, code)` stage through `eval`, printing `[engine] label => result`. +/// Stops at the first failure. Returns `true` if every stage passed. +pub fn run_stages(engine: &str, stages: &[(&str, &str)], mut eval: F) -> bool +where + F: FnMut(&str) -> Result, +{ + let mut failed = false; + for (label, code) in stages { + print!("[{engine}] {label:24} => "); + std::io::stdout().flush().ok(); // flush before the call so a crash still shows the label + match eval(code) { + Ok(out) => println!("{out}"), + Err(e) => { + println!("THREW: {e}"); + failed = true; + break; + } + } + std::io::stdout().flush().ok(); + } + if failed { + println!("[{engine}] a stage threw (see above)"); + } else { + println!("[{engine}] OK — WinRT running on standalone {engine}"); + } + !failed +} + +/// Self-checking stages for the napi-backend feature set beyond the per-engine basics: IMap +/// keyed sugar, PropertySet boxed-primitive round-trips, native subclassing (`class Sub +/// extends WinRTClass`) on both object models, composable class trees (Windows.UI.Composition), +/// and the composable-ctor path (env-aware: XAML activation is wrong-thread headless — the +/// stage passes when that surfaces as the clean, specific JS error, or when it succeeds in a +/// XAML-capable host). Each stage throws on mismatch so `run_stages` fails loudly. +pub const FEATURE_STAGES: &[(&str, &str)] = &[ + ("IMap keyed sugar", r#"(function () { + var m = new Windows.Foundation.Collections.StringMap(); + m['a'] = '1'; + if (m['a'] !== '1' || !m.HasKey('a') || !('a' in m) || ('zz' in m) || m['zz'] !== undefined) throw new Error('IMap sugar mismatch'); + var v = m.GetView(); + if (v['a'] !== '1' || v.Size !== 1 || !v.HasKey('a')) throw new Error('IMapView mismatch'); + return 'ok'; + })()"#), + ("PropertySet unboxing", r#"(function () { + var ps = new Windows.Foundation.Collections.PropertySet(); + ps['n'] = 42; ps['s'] = 'hi'; ps['b'] = true; + if (ps['n'] !== 42 || ps['s'] !== 'hi' || ps['b'] !== true || ps.Size !== 3) throw new Error('PropertySet round-trip mismatch'); + return 'ok'; + })()"#), + ("subclass (host object)", r#"(function () { + var JO = Windows.Data.Json.JsonObject; + class Sub extends JO { constructor() { super(); this.tag = 7; } custom() { return 'c:' + this.Stringify(); } } + var s = new Sub(); + if (!(s instanceof Sub) || !(s instanceof JO) || s.tag !== 7 || s.custom() !== 'c:{}') throw new Error('host subclass mismatch'); + var plain = new JO(); + if (plain instanceof Sub) throw new Error('plain instance polluted'); + return 'ok'; + })()"#), + ("subclass (proxy path)", r#"(function () { + var SM = Windows.Foundation.Collections.StringMap; + class MSub extends SM { describe() { return 'n=' + this.Size; } } + var t = new MSub(); + t['k'] = 'v'; + if (t.describe() !== 'n=1' || t['k'] !== 'v' || !(t instanceof MSub) || !(t instanceof SM)) throw new Error('proxy subclass mismatch'); + return 'ok'; + })()"#), + ("composition class tree", r#"(function () { + var c = new Windows.UI.Composition.Compositor(); + var v = c.CreateSpriteVisual(); + v.Opacity = 0.5; + if (v.Opacity !== 0.5) throw new Error('Visual.Opacity mismatch'); + v.Brush = c.CreateColorBrush(); + var ch = c.CreateSpriteVisual(); + v.Children.InsertAtTop(ch); + if (v.Children.Count !== 1) throw new Error('Children mismatch'); + return 'ok'; + })()"#), + ("composable ctor (env-aware)", r#"(function () { + try { + var ff = new Windows.UI.Xaml.Media.FontFamily('Segoe UI'); + if (ff.Source !== 'Segoe UI') throw new Error('FontFamily constructed but Source wrong: ' + ff.Source); + return 'constructed'; + } catch (e) { + var msg = String(e && e.message ? e.message : e); + if (/different thread|0x8001010E/i.test(msg)) return 'headless-ok (clean wrong-thread error)'; + throw e; + } + })()"#), +]; + +/// Kickoff for the async/event-loop demo stage: exercises timers (setTimeout, setInterval + +/// clearInterval), setImmediate (+ clearImmediate cancellation, immediate-after-microtask +/// ordering), queueMicrotask ordering, and a real WinRT async operation awaited through +/// `NSWinRT.toPromise` (ThreadPool.RunAsync — the Completed delegate arrives via the message +/// pump). Runs entirely under the standalone event loop; the verdict lands in +/// `globalThis.__nsAsyncDemo`. +pub const ASYNC_DEMO_KICKOFF: &str = r#" +globalThis.__nsAsyncDemo = 'pending'; +(function () { + 'use strict'; + var order = []; + queueMicrotask(function () { order.push('micro'); }); + var immediateArg = ''; + setImmediate(function (a, b) { order.push('immediate'); immediateArg = a + b; }, 'o', 'k'); + var cancelled = setImmediate(function () { order.push('cancelled'); }); + clearImmediate(cancelled); + var ticks = 0; + var iv = setInterval(function () { ticks++; if (ticks >= 3) { clearInterval(iv); } }, 5); + new Promise(function (resolve) { + setTimeout(function () { order.push('timeout'); resolve(); }, 20); + }).then(function () { + return NSWinRT.toPromise(Windows.System.Threading.ThreadPool.RunAsync(function () {})); + }).then(function () { + return new Promise(function (resolve) { + (function waitTicks() { if (ticks >= 3) { resolve(); } else { setTimeout(waitTicks, 5); } })(); + }); + }).then(function () { + globalThis.__nsAsyncDemo = 'micro=' + (order[0] === 'micro') + + ',immediate=' + (order.indexOf('immediate') > 0 && order.indexOf('immediate') < order.indexOf('timeout') && immediateArg === 'ok') + + ',cancelled=' + (order.indexOf('cancelled') < 0) + + ',timeout=' + (order.indexOf('timeout') >= 0) + + ',ticks=' + ticks + ',winrt=ok'; + }).catch(function (e) { + globalThis.__nsAsyncDemo = 'ERROR: ' + (e && e.message ? e.message : e); + }); +})(); +'started' +"#; + +pub const ASYNC_DEMO_EXPECTED: &str = + "micro=true,immediate=true,cancelled=true,timeout=true,ticks=3,winrt=ok"; + +/// Run the async/event-loop demo: evaluate the kickoff, drive the host's event loop until idle +/// (`run_loop`, expected to return `false` on a deadline), then check the recorded verdict. +pub fn run_async_demo(engine: &str, mut eval: E, run_loop: L) -> bool +where + E: FnMut(&str) -> Result, + L: FnOnce() -> bool, +{ + print!("[{engine}] {:24} => ", "async event loop"); + std::io::stdout().flush().ok(); + if let Err(e) = eval(ASYNC_DEMO_KICKOFF) { + println!("KICKOFF THREW: {e}"); + return false; + } + if !run_loop() { + println!("LOOP DEADLINE (work still pending)"); + return false; + } + match eval("globalThis.__nsAsyncDemo") { + Ok(v) if v == ASYNC_DEMO_EXPECTED => { + println!("{v}"); + true + } + Ok(v) => { + println!("MISMATCH: {v} (expected {ASYNC_DEMO_EXPECTED})"); + false + } + Err(e) => { + println!("VERDICT THREW: {e}"); + false + } + } +} diff --git a/packages/demo/src/lib.rs b/packages/demo/src/lib.rs new file mode 100644 index 0000000..42854a4 --- /dev/null +++ b/packages/demo/src/lib.rs @@ -0,0 +1,11 @@ +//! Self-test/demo support for the NativeScript Windows standalone-engine `nativescript-windows` +//! bin targets (`windows-quickjs`, `windows-hermes`, …): a native crash reporter and the small +//! demo harness that runs a list of JS stages against whatever engine the package embeds. +//! +//! This crate is only a dependency of those `[[bin]]` targets, never of the packages' `[lib]` +//! (the cdylib/rlib that ships as the napi addon or `nativescript.dll`) — see `ns-windows-common` +//! for the pieces (prelude, URL polyfill) that both the demo bin and the shipped addon need. + +pub mod bench; +pub mod crash; +pub mod harness; diff --git a/packages/test/interop-check.js b/packages/test/interop-check.js new file mode 100644 index 0000000..f1d038f --- /dev/null +++ b/packages/test/interop-check.js @@ -0,0 +1,65 @@ +// Standalone-engine check for the shared NSWinRT.interop surface (installed by +// install_globals; same source as the Node package's nswinrt.js `interop`): +// nativescript-windows packages/interop-check.js +// Prints "interop-check: N passed, M failed"; throws (nonzero exit) on any failure. +'use strict'; + +var interop = globalThis.NSWinRT && globalThis.NSWinRT.interop; +var pass = 0, fail = 0; +function check(name, ok) { + if (ok) { pass += 1; } + else { fail += 1; console.error('FAIL ' + name); } +} + +check('interop installed', !!interop); +check('global alias', globalThis.interop === interop); + +// Typed concrete values round-trip through a WinRT Object-typed parameter. +var ps = new Windows.Foundation.Collections.PropertySet(); +ps.Insert('d', interop.double(2.5)); +check('double round-trip', ps.Lookup('d') === 2.5); +ps.Insert('i', interop.int(42)); +check('int round-trip', ps.Lookup('i') === 42); +ps.Insert('b', interop.bool(true)); +check('bool round-trip', ps.Lookup('b') === true); +var ref = interop.reference('Double', 1.25); +check('reference shape', ref !== null && typeof ref === 'object'); +ps.Insert('r', ref); +check('reference round-trip', ps.Lookup('r') === 1.25); +check('unknown type null', globalThis.__nsTypedValue('NoSuchType', 1) === null); + +// Pointer / OutParam helpers. +var p = new interop.Pointer(null); +check('Pointer.isNull', p.isNull() === true); +check('isPointer', interop.isPointer(p) === true); +var o = interop.out('Int32', 5); +check('out/isOut', interop.isOut(o) && o.type === 'Int32' && o.value === 5); + +// Buffer helpers + the buffer→pointer natives. +var u8 = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); +check('byteLengthOf', interop.byteLengthOf(u8) === 8); +interop.writeI32(u8, 4, -2); +check('readI32', interop.readI32(u8, 4) === -2); +check('readU8', interop.readU8(u8, 2) === 3); +var bp = interop.pointerFromBuffer(u8); +check('pointerFromBuffer', bp !== null); +var key = interop.pointerKey(bp); +check('pointerKey', typeof key === 'string' && key.indexOf('0x') === 0 && key !== '0x0'); +check('pointerKey(null)', interop.pointerKey(null) === '0x0'); +check('track/resolve', interop.resolveTrackedBuffer(interop.trackBufferSource(u8)) === u8); + +// WinRT DateTime ticks (Number fallback tolerated on engines without BigInt). +var ticks = interop.toWinRTDateTimeTicks(0); +check('epoch ticks', typeof BigInt === 'function' + ? ticks === BigInt('116444736000000000') + : ticks === 116444736000000000); +check('ticks round-trip', + interop.fromWinRTDateTimeTicks(interop.toWinRTDateTimeTicks(1752768000000)).getTime() === 1752768000000); + +// uuid + winmd helpers over the natives. +var u = interop.uuid(); +check('uuid', typeof u === 'string' && u.length === 36); +check('scanWinmdDir missing', interop.scanWinmdDir('C:\\no\\such\\dir') === 0); + +console.log('interop-check: ' + pass + ' passed, ' + fail + ' failed'); +if (fail) { throw new Error('interop-check failed'); } diff --git a/packages/test/test-app.js b/packages/test/test-app.js new file mode 100644 index 0000000..b36fd91 --- /dev/null +++ b/packages/test/test-app.js @@ -0,0 +1,22 @@ +// Shared smoke app for the standalone hosts' script mode: +// nativescript-windows packages/test-app.js +// Exercises WinRT sync calls, timers, and an awaited WinRT async operation; the process must +// print the lines in order and then exit on its own once the event loop goes idle. +'use strict'; + +console.log('app: start'); + +var obj = new Windows.Data.Json.JsonObject(); +obj.SetNamedValue('n', Windows.Data.Json.JsonValue.CreateNumberValue(3)); +console.log('app: json = ' + obj.Stringify()); + +setTimeout(function () { + console.log('app: timeout fired'); + NSWinRT.toPromise(Windows.System.Threading.ThreadPool.RunAsync(function () {})) + .then(function () { + console.log('app: winrt async done'); + }) + .catch(function (e) { + console.error('app: winrt async FAILED: ' + (e && e.message ? e.message : e)); + }); +}, 30); diff --git a/packages/vendor/napi-sys/Cargo.toml b/packages/vendor/napi-sys/Cargo.toml new file mode 100644 index 0000000..dd0e9bd --- /dev/null +++ b/packages/vendor/napi-sys/Cargo.toml @@ -0,0 +1,44 @@ +# Vendored copy of napi-sys 2.4.0 with ONE Windows-port change (see src/functions.rs `load_all`): +# resolve the module that actually CONTAINS the napi provider (the .exe for a standalone host, or +# the cdylib — nativescript.dll — when loaded by a foreign .NET host), instead of always the process +# .exe. Applied via `[patch.crates-io]` in each engine package. Kept at 2.4.0 to satisfy napi-rs. +[package] +name = "napi-sys" +version = "2.4.0" +edition = "2021" +rust-version = "1.65" +authors = ["LongYinan "] +description = "NodeJS N-API raw binding" +readme = "README.md" +keywords = ["NodeJS", "FFI", "NAPI", "n-api"] +license = "MIT" +repository = "https://github.com/napi-rs/napi-rs" +include = ["src/**/*", "Cargo.toml"] + +[package.metadata.workspaces] +independent = true + +[dependencies.libloading] +version = "0.8" +optional = true + +[target."cfg(windows)".dependencies.libloading] +version = "0.8" + +# For the Windows-port `load_all` fix: raw-dylib kernel32 imports via the SAME mechanism libloading +# uses (windows-link), so they merge cleanly instead of colliding with libloading's own imports. +[target."cfg(windows)".dependencies.windows-link] +version = "0.2" + +[features] +dyn-symbols = ["libloading"] +experimental = [] +napi1 = [] +napi2 = ["napi1"] +napi3 = ["napi2"] +napi4 = ["napi3"] +napi5 = ["napi4"] +napi6 = ["napi5"] +napi7 = ["napi6"] +napi8 = ["napi7"] +napi9 = ["napi8"] diff --git a/packages/vendor/napi-sys/README.md b/packages/vendor/napi-sys/README.md new file mode 100644 index 0000000..214d6a0 --- /dev/null +++ b/packages/vendor/napi-sys/README.md @@ -0,0 +1,14 @@ +# napi-sys + +Dynamic loading logic copied from https://github.com/neon-bindings/neon/tree/0.10.0/crates/neon-runtime/src/napi/bindings. + + + + +chat + + +Low-level N-API bindings for Node.js addons written in Rust. + +See the [napi](https://nodejs.org/api/n-api.html) for the high-level API. diff --git a/packages/vendor/napi-sys/src/functions.rs b/packages/vendor/napi-sys/src/functions.rs new file mode 100644 index 0000000..50c8f26 --- /dev/null +++ b/packages/vendor/napi-sys/src/functions.rs @@ -0,0 +1,846 @@ +#![allow(clippy::too_many_arguments)] + +mod napi1 { + use super::super::types::*; + use std::os::raw::{c_char, c_void}; + + generate!( + extern "C" { + fn napi_get_last_error_info( + env: napi_env, + result: *mut *const napi_extended_error_info, + ) -> napi_status; + + fn napi_get_undefined(env: napi_env, result: *mut napi_value) -> napi_status; + fn napi_get_null(env: napi_env, result: *mut napi_value) -> napi_status; + fn napi_get_global(env: napi_env, result: *mut napi_value) -> napi_status; + fn napi_get_boolean(env: napi_env, value: bool, result: *mut napi_value) -> napi_status; + fn napi_create_object(env: napi_env, result: *mut napi_value) -> napi_status; + fn napi_create_array(env: napi_env, result: *mut napi_value) -> napi_status; + fn napi_create_array_with_length( + env: napi_env, + length: usize, + result: *mut napi_value, + ) -> napi_status; + fn napi_create_double(env: napi_env, value: f64, result: *mut napi_value) -> napi_status; + fn napi_create_int32(env: napi_env, value: i32, result: *mut napi_value) -> napi_status; + fn napi_create_uint32(env: napi_env, value: u32, result: *mut napi_value) -> napi_status; + fn napi_create_int64(env: napi_env, value: i64, result: *mut napi_value) -> napi_status; + fn napi_create_string_latin1( + env: napi_env, + str_: *const c_char, + length: usize, + result: *mut napi_value, + ) -> napi_status; + fn napi_create_string_utf8( + env: napi_env, + str_: *const c_char, + length: usize, + result: *mut napi_value, + ) -> napi_status; + fn napi_create_string_utf16( + env: napi_env, + str_: *const u16, + length: usize, + result: *mut napi_value, + ) -> napi_status; + fn napi_create_symbol( + env: napi_env, + description: napi_value, + result: *mut napi_value, + ) -> napi_status; + fn napi_create_function( + env: napi_env, + utf8name: *const c_char, + length: usize, + cb: napi_callback, + data: *mut c_void, + result: *mut napi_value, + ) -> napi_status; + fn napi_create_error( + env: napi_env, + code: napi_value, + msg: napi_value, + result: *mut napi_value, + ) -> napi_status; + fn napi_create_type_error( + env: napi_env, + code: napi_value, + msg: napi_value, + result: *mut napi_value, + ) -> napi_status; + fn napi_create_range_error( + env: napi_env, + code: napi_value, + msg: napi_value, + result: *mut napi_value, + ) -> napi_status; + fn napi_typeof(env: napi_env, value: napi_value, result: *mut napi_valuetype) -> napi_status; + fn napi_get_value_double(env: napi_env, value: napi_value, result: *mut f64) -> napi_status; + fn napi_get_value_int32(env: napi_env, value: napi_value, result: *mut i32) -> napi_status; + fn napi_get_value_uint32(env: napi_env, value: napi_value, result: *mut u32) -> napi_status; + fn napi_get_value_int64(env: napi_env, value: napi_value, result: *mut i64) -> napi_status; + fn napi_get_value_bool(env: napi_env, value: napi_value, result: *mut bool) -> napi_status; + fn napi_get_value_string_latin1( + env: napi_env, + value: napi_value, + buf: *mut c_char, + bufsize: usize, + result: *mut usize, + ) -> napi_status; + fn napi_get_value_string_utf8( + env: napi_env, + value: napi_value, + buf: *mut c_char, + bufsize: usize, + result: *mut usize, + ) -> napi_status; + fn napi_get_value_string_utf16( + env: napi_env, + value: napi_value, + buf: *mut u16, + bufsize: usize, + result: *mut usize, + ) -> napi_status; + fn napi_coerce_to_bool( + env: napi_env, + value: napi_value, + result: *mut napi_value, + ) -> napi_status; + fn napi_coerce_to_number( + env: napi_env, + value: napi_value, + result: *mut napi_value, + ) -> napi_status; + fn napi_coerce_to_object( + env: napi_env, + value: napi_value, + result: *mut napi_value, + ) -> napi_status; + fn napi_coerce_to_string( + env: napi_env, + value: napi_value, + result: *mut napi_value, + ) -> napi_status; + fn napi_get_prototype( + env: napi_env, + object: napi_value, + result: *mut napi_value, + ) -> napi_status; + fn napi_get_property_names( + env: napi_env, + object: napi_value, + result: *mut napi_value, + ) -> napi_status; + fn napi_set_property( + env: napi_env, + object: napi_value, + key: napi_value, + value: napi_value, + ) -> napi_status; + fn napi_has_property( + env: napi_env, + object: napi_value, + key: napi_value, + result: *mut bool, + ) -> napi_status; + fn napi_get_property( + env: napi_env, + object: napi_value, + key: napi_value, + result: *mut napi_value, + ) -> napi_status; + fn napi_delete_property( + env: napi_env, + object: napi_value, + key: napi_value, + result: *mut bool, + ) -> napi_status; + fn napi_has_own_property( + env: napi_env, + object: napi_value, + key: napi_value, + result: *mut bool, + ) -> napi_status; + fn napi_set_named_property( + env: napi_env, + object: napi_value, + utf8name: *const c_char, + value: napi_value, + ) -> napi_status; + fn napi_has_named_property( + env: napi_env, + object: napi_value, + utf8name: *const c_char, + result: *mut bool, + ) -> napi_status; + fn napi_get_named_property( + env: napi_env, + object: napi_value, + utf8name: *const c_char, + result: *mut napi_value, + ) -> napi_status; + fn napi_set_element( + env: napi_env, + object: napi_value, + index: u32, + value: napi_value, + ) -> napi_status; + fn napi_has_element( + env: napi_env, + object: napi_value, + index: u32, + result: *mut bool, + ) -> napi_status; + fn napi_get_element( + env: napi_env, + object: napi_value, + index: u32, + result: *mut napi_value, + ) -> napi_status; + fn napi_delete_element( + env: napi_env, + object: napi_value, + index: u32, + result: *mut bool, + ) -> napi_status; + fn napi_define_properties( + env: napi_env, + object: napi_value, + property_count: usize, + properties: *const napi_property_descriptor, + ) -> napi_status; + fn napi_is_array(env: napi_env, value: napi_value, result: *mut bool) -> napi_status; + fn napi_get_array_length(env: napi_env, value: napi_value, result: *mut u32) -> napi_status; + fn napi_strict_equals( + env: napi_env, + lhs: napi_value, + rhs: napi_value, + result: *mut bool, + ) -> napi_status; + fn napi_call_function( + env: napi_env, + recv: napi_value, + func: napi_value, + argc: usize, + argv: *const napi_value, + result: *mut napi_value, + ) -> napi_status; + fn napi_new_instance( + env: napi_env, + constructor: napi_value, + argc: usize, + argv: *const napi_value, + result: *mut napi_value, + ) -> napi_status; + fn napi_instanceof( + env: napi_env, + object: napi_value, + constructor: napi_value, + result: *mut bool, + ) -> napi_status; + fn napi_get_cb_info( + env: napi_env, + cbinfo: napi_callback_info, + argc: *mut usize, + argv: *mut napi_value, + this_arg: *mut napi_value, + data: *mut *mut c_void, + ) -> napi_status; + fn napi_get_new_target( + env: napi_env, + cbinfo: napi_callback_info, + result: *mut napi_value, + ) -> napi_status; + fn napi_define_class( + env: napi_env, + utf8name: *const c_char, + length: usize, + constructor: napi_callback, + data: *mut c_void, + property_count: usize, + properties: *const napi_property_descriptor, + result: *mut napi_value, + ) -> napi_status; + fn napi_wrap( + env: napi_env, + js_object: napi_value, + native_object: *mut c_void, + finalize_cb: napi_finalize, + finalize_hint: *mut c_void, + result: *mut napi_ref, + ) -> napi_status; + fn napi_unwrap(env: napi_env, js_object: napi_value, result: *mut *mut c_void) + -> napi_status; + fn napi_remove_wrap( + env: napi_env, + js_object: napi_value, + result: *mut *mut c_void, + ) -> napi_status; + fn napi_create_external( + env: napi_env, + data: *mut c_void, + finalize_cb: napi_finalize, + finalize_hint: *mut c_void, + result: *mut napi_value, + ) -> napi_status; + fn napi_get_value_external( + env: napi_env, + value: napi_value, + result: *mut *mut c_void, + ) -> napi_status; + fn napi_create_reference( + env: napi_env, + value: napi_value, + initial_refcount: u32, + result: *mut napi_ref, + ) -> napi_status; + fn napi_delete_reference(env: napi_env, ref_: napi_ref) -> napi_status; + fn napi_reference_ref(env: napi_env, ref_: napi_ref, result: *mut u32) -> napi_status; + fn napi_reference_unref(env: napi_env, ref_: napi_ref, result: *mut u32) -> napi_status; + fn napi_get_reference_value( + env: napi_env, + ref_: napi_ref, + result: *mut napi_value, + ) -> napi_status; + fn napi_open_handle_scope(env: napi_env, result: *mut napi_handle_scope) -> napi_status; + fn napi_close_handle_scope(env: napi_env, scope: napi_handle_scope) -> napi_status; + fn napi_open_escapable_handle_scope( + env: napi_env, + result: *mut napi_escapable_handle_scope, + ) -> napi_status; + fn napi_close_escapable_handle_scope( + env: napi_env, + scope: napi_escapable_handle_scope, + ) -> napi_status; + fn napi_escape_handle( + env: napi_env, + scope: napi_escapable_handle_scope, + escapee: napi_value, + result: *mut napi_value, + ) -> napi_status; + fn napi_throw(env: napi_env, error: napi_value) -> napi_status; + fn napi_throw_error(env: napi_env, code: *const c_char, msg: *const c_char) -> napi_status; + fn napi_throw_type_error( + env: napi_env, + code: *const c_char, + msg: *const c_char, + ) -> napi_status; + fn napi_throw_range_error( + env: napi_env, + code: *const c_char, + msg: *const c_char, + ) -> napi_status; + fn napi_is_error(env: napi_env, value: napi_value, result: *mut bool) -> napi_status; + fn napi_is_exception_pending(env: napi_env, result: *mut bool) -> napi_status; + fn napi_get_and_clear_last_exception(env: napi_env, result: *mut napi_value) -> napi_status; + fn napi_is_arraybuffer(env: napi_env, value: napi_value, result: *mut bool) -> napi_status; + fn napi_create_arraybuffer( + env: napi_env, + byte_length: usize, + data: *mut *mut c_void, + result: *mut napi_value, + ) -> napi_status; + fn napi_create_external_arraybuffer( + env: napi_env, + external_data: *mut c_void, + byte_length: usize, + finalize_cb: napi_finalize, + finalize_hint: *mut c_void, + result: *mut napi_value, + ) -> napi_status; + fn napi_get_arraybuffer_info( + env: napi_env, + arraybuffer: napi_value, + data: *mut *mut c_void, + byte_length: *mut usize, + ) -> napi_status; + fn napi_is_typedarray(env: napi_env, value: napi_value, result: *mut bool) -> napi_status; + fn napi_create_typedarray( + env: napi_env, + type_: napi_typedarray_type, + length: usize, + arraybuffer: napi_value, + byte_offset: usize, + result: *mut napi_value, + ) -> napi_status; + fn napi_get_typedarray_info( + env: napi_env, + typedarray: napi_value, + type_: *mut napi_typedarray_type, + length: *mut usize, + data: *mut *mut c_void, + arraybuffer: *mut napi_value, + byte_offset: *mut usize, + ) -> napi_status; + fn napi_create_dataview( + env: napi_env, + length: usize, + arraybuffer: napi_value, + byte_offset: usize, + result: *mut napi_value, + ) -> napi_status; + fn napi_is_dataview(env: napi_env, value: napi_value, result: *mut bool) -> napi_status; + fn napi_get_dataview_info( + env: napi_env, + dataview: napi_value, + bytelength: *mut usize, + data: *mut *mut c_void, + arraybuffer: *mut napi_value, + byte_offset: *mut usize, + ) -> napi_status; + fn napi_get_version(env: napi_env, result: *mut u32) -> napi_status; + fn napi_create_promise( + env: napi_env, + deferred: *mut napi_deferred, + promise: *mut napi_value, + ) -> napi_status; + fn napi_resolve_deferred( + env: napi_env, + deferred: napi_deferred, + resolution: napi_value, + ) -> napi_status; + fn napi_reject_deferred( + env: napi_env, + deferred: napi_deferred, + rejection: napi_value, + ) -> napi_status; + fn napi_is_promise(env: napi_env, value: napi_value, is_promise: *mut bool) -> napi_status; + fn napi_run_script(env: napi_env, script: napi_value, result: *mut napi_value) + -> napi_status; + fn napi_adjust_external_memory( + env: napi_env, + change_in_bytes: i64, + adjusted_value: *mut i64, + ) -> napi_status; + fn napi_module_register(mod_: *mut napi_module); + fn napi_fatal_error( + location: *const c_char, + location_len: usize, + message: *const c_char, + message_len: usize, + ); + fn napi_async_init( + env: napi_env, + async_resource: napi_value, + async_resource_name: napi_value, + result: *mut napi_async_context, + ) -> napi_status; + fn napi_async_destroy(env: napi_env, async_context: napi_async_context) -> napi_status; + fn napi_make_callback( + env: napi_env, + async_context: napi_async_context, + recv: napi_value, + func: napi_value, + argc: usize, + argv: *const napi_value, + result: *mut napi_value, + ) -> napi_status; + fn napi_create_buffer( + env: napi_env, + length: usize, + data: *mut *mut c_void, + result: *mut napi_value, + ) -> napi_status; + fn napi_create_external_buffer( + env: napi_env, + length: usize, + data: *mut c_void, + finalize_cb: napi_finalize, + finalize_hint: *mut c_void, + result: *mut napi_value, + ) -> napi_status; + fn napi_create_buffer_copy( + env: napi_env, + length: usize, + data: *const c_void, + result_data: *mut *mut c_void, + result: *mut napi_value, + ) -> napi_status; + fn napi_is_buffer(env: napi_env, value: napi_value, result: *mut bool) -> napi_status; + fn napi_get_buffer_info( + env: napi_env, + value: napi_value, + data: *mut *mut c_void, + length: *mut usize, + ) -> napi_status; + fn napi_create_async_work( + env: napi_env, + async_resource: napi_value, + async_resource_name: napi_value, + execute: napi_async_execute_callback, + complete: napi_async_complete_callback, + data: *mut c_void, + result: *mut napi_async_work, + ) -> napi_status; + fn napi_delete_async_work(env: napi_env, work: napi_async_work) -> napi_status; + fn napi_queue_async_work(env: napi_env, work: napi_async_work) -> napi_status; + fn napi_cancel_async_work(env: napi_env, work: napi_async_work) -> napi_status; + fn napi_get_node_version( + env: napi_env, + version: *mut *const napi_node_version, + ) -> napi_status; + } + ); +} + +#[cfg(feature = "napi2")] +mod napi2 { + use super::super::types::*; + use std::os::raw::c_int; + + generate!( + extern "C" { + fn napi_get_uv_event_loop(env: napi_env, loop_: *mut *mut uv_loop_s) -> napi_status; + + fn uv_run(loop_: *mut uv_loop_s, mode: uv_run_mode) -> c_int; + } + ); +} + +#[cfg(feature = "napi3")] +mod napi3 { + use std::os::raw::c_void; + + use super::super::types::*; + + generate!( + extern "C" { + fn napi_fatal_exception(env: napi_env, err: napi_value) -> napi_status; + fn napi_add_env_cleanup_hook( + env: napi_env, + fun: Option, + arg: *mut c_void, + ) -> napi_status; + fn napi_remove_env_cleanup_hook( + env: napi_env, + fun: Option, + arg: *mut c_void, + ) -> napi_status; + fn napi_open_callback_scope( + env: napi_env, + resource_object: napi_value, + context: napi_async_context, + result: *mut napi_callback_scope, + ) -> napi_status; + fn napi_close_callback_scope(env: napi_env, scope: napi_callback_scope) -> napi_status; + } + ); +} + +#[cfg(feature = "napi4")] +mod napi4 { + use super::super::types::*; + use std::os::raw::c_void; + + generate!( + extern "C" { + fn napi_create_threadsafe_function( + env: napi_env, + func: napi_value, + async_resource: napi_value, + async_resource_name: napi_value, + max_queue_size: usize, + initial_thread_count: usize, + thread_finalize_data: *mut c_void, + thread_finalize_cb: napi_finalize, + context: *mut c_void, + call_js_cb: napi_threadsafe_function_call_js, + result: *mut napi_threadsafe_function, + ) -> napi_status; + fn napi_get_threadsafe_function_context( + func: napi_threadsafe_function, + result: *mut *mut c_void, + ) -> napi_status; + fn napi_call_threadsafe_function( + func: napi_threadsafe_function, + data: *mut c_void, + is_blocking: napi_threadsafe_function_call_mode, + ) -> napi_status; + fn napi_acquire_threadsafe_function(func: napi_threadsafe_function) -> napi_status; + fn napi_release_threadsafe_function( + func: napi_threadsafe_function, + mode: napi_threadsafe_function_release_mode, + ) -> napi_status; + fn napi_unref_threadsafe_function( + env: napi_env, + func: napi_threadsafe_function, + ) -> napi_status; + fn napi_ref_threadsafe_function(env: napi_env, func: napi_threadsafe_function) + -> napi_status; + } + ); +} + +#[cfg(feature = "napi5")] +mod napi5 { + use super::super::types::*; + use std::ffi::c_void; + + generate!( + extern "C" { + fn napi_create_date(env: napi_env, time: f64, result: *mut napi_value) -> napi_status; + fn napi_is_date(env: napi_env, value: napi_value, is_date: *mut bool) -> napi_status; + fn napi_get_date_value(env: napi_env, value: napi_value, result: *mut f64) -> napi_status; + fn napi_add_finalizer( + env: napi_env, + js_object: napi_value, + native_object: *mut c_void, + finalize_cb: napi_finalize, + finalize_hint: *mut c_void, + result: *mut napi_ref, + ) -> napi_status; + } + ); +} + +#[cfg(feature = "napi6")] +mod napi6 { + use super::super::types::*; + use std::os::raw::{c_int, c_void}; + + generate!( + extern "C" { + fn napi_create_bigint_int64( + env: napi_env, + value: i64, + result: *mut napi_value, + ) -> napi_status; + fn napi_create_bigint_uint64( + env: napi_env, + value: u64, + result: *mut napi_value, + ) -> napi_status; + fn napi_create_bigint_words( + env: napi_env, + sign_bit: c_int, + word_count: usize, + words: *const u64, + result: *mut napi_value, + ) -> napi_status; + fn napi_get_value_bigint_int64( + env: napi_env, + value: napi_value, + result: *mut i64, + lossless: *mut bool, + ) -> napi_status; + fn napi_get_value_bigint_uint64( + env: napi_env, + value: napi_value, + result: *mut u64, + lossless: *mut bool, + ) -> napi_status; + fn napi_get_value_bigint_words( + env: napi_env, + value: napi_value, + sign_bit: *mut c_int, + word_count: *mut usize, + words: *mut u64, + ) -> napi_status; + fn napi_get_all_property_names( + env: napi_env, + object: napi_value, + key_mode: napi_key_collection_mode, + key_filter: napi_key_filter, + key_conversion: napi_key_conversion, + result: *mut napi_value, + ) -> napi_status; + fn napi_set_instance_data( + env: napi_env, + data: *mut c_void, + finalize_cb: napi_finalize, + finalize_hint: *mut c_void, + ) -> napi_status; + fn napi_get_instance_data(env: napi_env, data: *mut *mut c_void) -> napi_status; + } + ); +} + +#[cfg(feature = "napi7")] +mod napi7 { + use super::super::types::*; + + generate!( + extern "C" { + fn napi_detach_arraybuffer(env: napi_env, arraybuffer: napi_value) -> napi_status; + fn napi_is_detached_arraybuffer( + env: napi_env, + value: napi_value, + result: *mut bool, + ) -> napi_status; + } + ); +} + +#[cfg(feature = "napi8")] +mod napi8 { + use std::os::raw::c_void; + + use super::super::types::*; + + generate!( + extern "C" { + fn napi_add_async_cleanup_hook( + env: napi_env, + hook: napi_async_cleanup_hook, + arg: *mut c_void, + remove_handle: *mut napi_async_cleanup_hook_handle, + ) -> napi_status; + + fn napi_remove_async_cleanup_hook( + remove_handle: napi_async_cleanup_hook_handle, + ) -> napi_status; + + fn napi_object_freeze(env: napi_env, object: napi_value) -> napi_status; + + fn napi_object_seal(env: napi_env, object: napi_value) -> napi_status; + } + ); +} + +#[cfg(feature = "napi9")] +mod napi9 { + use std::os::raw::c_char; + + use super::super::types::*; + + generate!( + extern "C" { + fn node_api_symbol_for( + env: napi_env, + utf8name: *const c_char, + length: usize, + result: *mut napi_value, + ) -> napi_status; + fn node_api_get_module_file_name(env: napi_env, result: *mut *const c_char) -> napi_status; + fn node_api_create_syntax_error( + env: napi_env, + code: napi_value, + msg: napi_value, + result: *mut napi_value, + ) -> napi_status; + fn node_api_throw_syntax_error( + env: napi_env, + code: *const c_char, + msg: *const c_char, + ) -> napi_status; + } + ); +} + +#[cfg(feature = "experimental")] +mod experimental { + use std::os::raw::{c_char, c_void}; + + use super::super::types::*; + + generate!( + extern "C" { + fn node_api_create_external_string_latin1( + env: napi_env, + str_: *const c_char, + length: usize, + napi_finalize: napi_finalize, + finalize_hint: *mut c_void, + result: *mut napi_value, + copied: *mut bool, + ) -> napi_status; + + fn node_api_create_external_string_utf16( + env: napi_env, + str_: *const u16, + length: usize, + napi_finalize: napi_finalize, + finalize_hint: *mut c_void, + result: *mut napi_value, + copied: *mut bool, + ) -> napi_status; + } + ); +} + +#[cfg(feature = "experimental")] +pub use experimental::*; + +pub use napi1::*; +#[cfg(feature = "napi2")] +pub use napi2::*; +#[cfg(feature = "napi3")] +pub use napi3::*; +#[cfg(feature = "napi4")] +pub use napi4::*; +#[cfg(feature = "napi5")] +pub use napi5::*; +#[cfg(feature = "napi6")] +pub use napi6::*; +#[cfg(feature = "napi7")] +pub use napi7::*; +#[cfg(feature = "napi8")] +pub use napi8::*; +#[cfg(feature = "napi9")] +pub use napi9::*; + +#[cfg(any(windows, feature = "dyn-symbols"))] +pub(super) unsafe fn load_all() -> Result { + #[cfg(windows)] + let host = { + use std::os::windows::ffi::OsStringExt; + windows_link::link!("kernel32.dll" "system" fn GetModuleHandleExW(flags: u32, module_name: *const u16, module: *mut isize) -> i32); + windows_link::link!("kernel32.dll" "system" fn GetModuleFileNameW(module: isize, filename: *mut u16, size: u32) -> u32); + windows_link::link!("kernel32.dll" "system" fn GetProcAddress(module: isize, proc_name: *const u8) -> *const core::ffi::c_void); + extern "C" fn anchor() {} + const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: u32 = 0x0000_0004; + const GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT: u32 = 0x0000_0002; + let mut handle: isize = 0; + let ok = GetModuleHandleExW( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + anchor as usize as *const u16, + &mut handle, + ); + let provides_napi = + ok != 0 && handle != 0 && !GetProcAddress(handle, c"napi_create_string_utf8".as_ptr().cast()).is_null(); + // If THIS module exports napi_* (standalone .exe or the nativescript.dll cdylib), load it by + // path via the normal refcounted LoadLibrary so symbols resolve from here. Otherwise (e.g. a + // Node addon that consumes the host's napi) fall back to the process module. + let by_self: Option = if provides_napi { + let mut buf = [0u16; 32768]; + let n = GetModuleFileNameW(handle, buf.as_mut_ptr(), buf.len() as u32) as usize; + if n > 0 && n < buf.len() { + let path = std::ffi::OsString::from_wide(&buf[..n]); + libloading::os::windows::Library::new(path).ok() + } else { + None + } + } else { + None + }; + match by_self { + Some(lib) => lib.into(), + None => libloading::os::windows::Library::this()?.into(), + } + }; + + #[cfg(unix)] + let host = libloading::os::unix::Library::this().into(); + + napi1::load(&host)?; + #[cfg(feature = "napi2")] + napi2::load(&host)?; + #[cfg(feature = "napi3")] + napi3::load(&host)?; + #[cfg(feature = "napi4")] + napi4::load(&host)?; + #[cfg(feature = "napi5")] + napi5::load(&host)?; + #[cfg(feature = "napi6")] + napi6::load(&host)?; + #[cfg(feature = "napi7")] + napi7::load(&host)?; + #[cfg(feature = "napi8")] + napi8::load(&host)?; + #[cfg(feature = "napi9")] + napi9::load(&host)?; + #[cfg(feature = "experimental")] + experimental::load(&host)?; + Ok(host) +} diff --git a/packages/vendor/napi-sys/src/lib.rs b/packages/vendor/napi-sys/src/lib.rs new file mode 100644 index 0000000..5334de4 --- /dev/null +++ b/packages/vendor/napi-sys/src/lib.rs @@ -0,0 +1,101 @@ +// borrowed from https://github.com/neon-bindings/neon/tree/main/crates/neon/src/sys/bindings + +#![allow(ambiguous_glob_reexports)] + +#[cfg(any(windows, feature = "dyn-symbols"))] +macro_rules! generate { + (extern "C" { + $(fn $name:ident($($param:ident: $ptype:ty$(,)?)*)$( -> $rtype:ty)?;)+ + }) => { + struct Napi { + $( + $name: unsafe extern "C" fn( + $($param: $ptype,)* + )$( -> $rtype)*, + )* + } + + #[inline(never)] + fn panic_load() -> T { + panic!("Node-API symbol has not been loaded") + } + + static mut NAPI: Napi = { + $( + unsafe extern "C" fn $name($(_: $ptype,)*)$( -> $rtype)* { + panic_load() + } + )* + + Napi { + $( + $name, + )* + } + }; + + #[allow(clippy::missing_safety_doc)] + pub unsafe fn load( + host: &libloading::Library, + ) -> Result<(), libloading::Error> { + NAPI = Napi { + $( + $name: { + let symbol: Result $rtype)*>, libloading::Error> = host.get(stringify!($name).as_bytes()); + match symbol { + Ok(f) => *f, + Err(e) => { + #[cfg(debug_assertions)] { + eprintln!("Load Node-API [{}] from host runtime failed: {}", stringify!($name), e); + } + NAPI.$name + } + } + }, + )* + }; + + Ok(()) + } + + $( + #[inline] + #[allow(clippy::missing_safety_doc)] + pub unsafe fn $name($($param: $ptype,)*)$( -> $rtype)* { + (NAPI.$name)($($param,)*) + } + )* + }; +} + +#[cfg(not(any(windows, feature = "dyn-symbols")))] +macro_rules! generate { + (extern "C" { + $(fn $name:ident($($param:ident: $ptype:ty$(,)?)*)$( -> $rtype:ty)?;)+ + }) => { + extern "C" { + $( + pub fn $name($($param: $ptype,)*)$( -> $rtype)*; + ) * + } + }; +} + +mod functions; +mod types; + +pub use functions::*; +pub use types::*; + +/// Loads N-API symbols from host process. +/// Must be called at least once before using any functions in bindings or +/// they will panic. +/// Safety: `env` must be a valid `napi_env` for the current thread +#[cfg(any(windows, feature = "dyn-symbols"))] +#[allow(clippy::missing_safety_doc)] +pub unsafe fn setup() -> libloading::Library { + match load_all() { + Err(err) => panic!("{}", err), + Ok(l) => l, + } +} diff --git a/packages/vendor/napi-sys/src/types.rs b/packages/vendor/napi-sys/src/types.rs new file mode 100644 index 0000000..27ea384 --- /dev/null +++ b/packages/vendor/napi-sys/src/types.rs @@ -0,0 +1,303 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(dead_code)] + +use std::os::raw::{c_char, c_int, c_uint, c_void}; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct napi_env__ { + _unused: [u8; 0], +} + +/// Env ptr +pub type napi_env = *mut napi_env__; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct napi_value__ { + _unused: [u8; 0], +} + +/// JsValue ptr +pub type napi_value = *mut napi_value__; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct napi_ref__ { + _unused: [u8; 0], +} +pub type napi_ref = *mut napi_ref__; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct napi_handle_scope__ { + _unused: [u8; 0], +} +pub type napi_handle_scope = *mut napi_handle_scope__; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct napi_escapable_handle_scope__ { + _unused: [u8; 0], +} +pub type napi_escapable_handle_scope = *mut napi_escapable_handle_scope__; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct napi_callback_info__ { + _unused: [u8; 0], +} +pub type napi_callback_info = *mut napi_callback_info__; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct napi_deferred__ { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct uv_loop_s { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub enum uv_run_mode { + UV_RUN_DEFAULT = 0, + UV_RUN_ONCE = 1, + UV_RUN_NOWAIT = 2, +} +pub type napi_deferred = *mut napi_deferred__; + +pub type napi_property_attributes = i32; + +pub mod PropertyAttributes { + use super::napi_property_attributes; + + pub const default: napi_property_attributes = 0; + pub const writable: napi_property_attributes = 1 << 0; + pub const enumerable: napi_property_attributes = 1 << 1; + pub const configurable: napi_property_attributes = 1 << 2; + + // Used with napi_define_class to distinguish static properties + // from instance properties. Ignored by napi_define_properties. + pub const static_: napi_property_attributes = 1 << 10; +} + +pub type napi_valuetype = i32; + +pub mod ValueType { + pub const napi_undefined: i32 = 0; + pub const napi_null: i32 = 1; + pub const napi_boolean: i32 = 2; + pub const napi_number: i32 = 3; + pub const napi_string: i32 = 4; + pub const napi_symbol: i32 = 5; + pub const napi_object: i32 = 6; + pub const napi_function: i32 = 7; + pub const napi_external: i32 = 8; + #[cfg(feature = "napi6")] + pub const napi_bigint: i32 = 9; +} + +pub type napi_typedarray_type = i32; + +pub mod TypedarrayType { + pub const int8_array: i32 = 0; + pub const uint8_array: i32 = 1; + pub const uint8_clamped_array: i32 = 2; + pub const int16_array: i32 = 3; + pub const uint16_array: i32 = 4; + pub const int32_array: i32 = 5; + pub const uint32_array: i32 = 6; + pub const float32_array: i32 = 7; + pub const float64_array: i32 = 8; + #[cfg(feature = "napi6")] + pub const bigint64_array: i32 = 9; + #[cfg(feature = "napi6")] + pub const biguint64_array: i32 = 10; +} + +pub type napi_status = i32; + +pub mod Status { + pub const napi_ok: i32 = 0; + pub const napi_invalid_arg: i32 = 1; + pub const napi_object_expected: i32 = 2; + pub const napi_string_expected: i32 = 3; + pub const napi_name_expected: i32 = 4; + pub const napi_function_expected: i32 = 5; + pub const napi_number_expected: i32 = 6; + pub const napi_boolean_expected: i32 = 7; + pub const napi_array_expected: i32 = 8; + pub const napi_generic_failure: i32 = 9; + pub const napi_pending_exception: i32 = 10; + pub const napi_cancelled: i32 = 11; + pub const napi_escape_called_twice: i32 = 12; + pub const napi_handle_scope_mismatch: i32 = 13; + pub const napi_callback_scope_mismatch: i32 = 14; + pub const napi_queue_full: i32 = 15; + pub const napi_closing: i32 = 16; + pub const napi_bigint_expected: i32 = 17; + pub const napi_date_expected: i32 = 18; + pub const napi_arraybuffer_expected: i32 = 19; + pub const napi_detachable_arraybuffer_expected: i32 = 20; + pub const napi_would_deadlock: i32 = 21; // unused + pub const napi_no_external_buffers_allowed: i32 = 22; +} + +pub type napi_callback = + Option napi_value>; +pub type napi_finalize = Option< + unsafe extern "C" fn(env: napi_env, finalize_data: *mut c_void, finalize_hint: *mut c_void), +>; +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct napi_property_descriptor { + pub utf8name: *const c_char, + pub name: napi_value, + pub method: napi_callback, + pub getter: napi_callback, + pub setter: napi_callback, + pub value: napi_value, + pub attributes: napi_property_attributes, + pub data: *mut c_void, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct napi_extended_error_info { + pub error_message: *const c_char, + pub engine_reserved: *mut c_void, + pub engine_error_code: u32, + pub error_code: napi_status, +} + +#[cfg(feature = "napi6")] +pub type napi_key_collection_mode = i32; + +#[cfg(feature = "napi6")] +pub mod KeyCollectionMode { + pub use super::napi_key_collection_mode; + pub const include_prototypes: napi_key_collection_mode = 0; + pub const own_only: napi_key_collection_mode = 1; +} + +#[cfg(feature = "napi6")] +pub type napi_key_filter = i32; + +#[cfg(feature = "napi6")] +pub mod KeyFilter { + use super::napi_key_filter; + + pub const all_properties: napi_key_filter = 0; + pub const writable: napi_key_filter = 1; + pub const enumerable: napi_key_filter = 1 << 1; + pub const configurable: napi_key_filter = 1 << 2; + pub const skip_strings: napi_key_filter = 1 << 3; + pub const skip_symbols: napi_key_filter = 1 << 4; +} + +#[cfg(feature = "napi6")] +pub type napi_key_conversion = i32; + +#[cfg(feature = "napi6")] +pub mod KeyConversion { + use super::napi_key_conversion; + + pub const keep_numbers: napi_key_conversion = 0; + pub const numbers_to_strings: napi_key_conversion = 1; +} +#[cfg(feature = "napi8")] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct napi_async_cleanup_hook_handle__ { + _unused: [u8; 0], +} +#[cfg(feature = "napi8")] +pub type napi_async_cleanup_hook_handle = *mut napi_async_cleanup_hook_handle__; +#[cfg(feature = "napi8")] +pub type napi_async_cleanup_hook = + Option; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct napi_callback_scope__ { + _unused: [u8; 0], +} +pub type napi_callback_scope = *mut napi_callback_scope__; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct napi_async_context__ { + _unused: [u8; 0], +} +pub type napi_async_context = *mut napi_async_context__; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct napi_async_work__ { + _unused: [u8; 0], +} +pub type napi_async_work = *mut napi_async_work__; + +#[cfg(feature = "napi4")] +#[repr(C)] +#[derive(Copy, Clone)] +pub struct napi_threadsafe_function__ { + _unused: [u8; 0], +} + +#[cfg(feature = "napi4")] +pub type napi_threadsafe_function = *mut napi_threadsafe_function__; + +#[cfg(feature = "napi4")] +pub type napi_threadsafe_function_release_mode = i32; + +#[cfg(feature = "napi4")] +pub mod ThreadsafeFunctionReleaseMode { + use super::napi_threadsafe_function_release_mode; + pub const release: napi_threadsafe_function_release_mode = 0; + pub const abort: napi_threadsafe_function_release_mode = 1; +} + +#[cfg(feature = "napi4")] +pub type napi_threadsafe_function_call_mode = i32; + +#[cfg(feature = "napi4")] +pub mod ThreadsafeFunctionCallMode { + use super::napi_threadsafe_function_call_mode; + + pub const nonblocking: napi_threadsafe_function_call_mode = 0; + pub const blocking: napi_threadsafe_function_call_mode = 1; +} + +pub type napi_async_execute_callback = + Option; +pub type napi_async_complete_callback = + Option; + +#[cfg(feature = "napi4")] +pub type napi_threadsafe_function_call_js = Option< + unsafe extern "C" fn( + env: napi_env, + js_callback: napi_value, + context: *mut c_void, + data: *mut c_void, + ), +>; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct napi_node_version { + pub major: u32, + pub minor: u32, + pub patch: u32, + pub release: *const c_char, +} + +pub type napi_addon_register_func = + Option napi_value>; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct napi_module { + pub nm_version: c_int, + pub nm_flags: c_uint, + pub nm_filename: *const c_char, + pub nm_register_func: napi_addon_register_func, + pub nm_modname: *const c_char, + pub nm_priv: *mut c_void, + pub reserved: [*mut c_void; 4usize], +} diff --git a/packages/windows-hermes/Cargo.lock b/packages/windows-hermes/Cargo.lock new file mode 100644 index 0000000..a00d1e7 --- /dev/null +++ b/packages/windows-hermes/Cargo.lock @@ -0,0 +1,1705 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "serde", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link", +] + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex 1.3.0", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "calendrical_calculations" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5abbd6eeda6885048d357edc66748eea6e0268e3dd11f326fff5bd248d779c26" +dependencies = [ + "core_maths", + "displaydoc", +] + +[[package]] +name = "cc" +version = "1.2.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38" +dependencies = [ + "find-msvc-tools", + "shlex 2.0.1", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core_maths" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" +dependencies = [ + "libm", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "diplomat" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7935649d00000f5c5d735448ad3dc07b9738160727017914cf42138b8e8e6611" +dependencies = [ + "diplomat_core", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "diplomat-runtime" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "970ac38ad677632efcee6d517e783958da9bc78ec206d8d5e35b459ffc5e4864" + +[[package]] +name = "diplomat_core" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf41b94101a4bce993febaf0098092b0bb31deaf0ecaf6e0a2562465f61b383" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "smallvec", + "strck", + "syn", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fslock" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "gzip-header" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86848f4fd157d91041a62c78046fb7b248bcc2dce78376d436a1756e9a038577" +dependencies = [ + "crc32fast", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_calendar" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b2acc6263f494f1df50685b53ff8e57869e47d5c6fe39c23d518ae9a4f3e45" +dependencies = [ + "calendrical_calculations", + "displaydoc", + "icu_calendar_data", + "icu_locale", + "icu_locale_core", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_calendar_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "118577bcf3a0fa7c6ac0a7d6e951814da84ee56b9b1f68fb4d8d10b08cefaf4d" + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5a396343c7208121dc86e35623d3dfe19814a7613cfd14964994cdc9c9a2e26" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_locale_data", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "serde", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locale_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fdcc9ac77c6d74ff5cf6e65ef3181d6af32003b16fce3a77fb451d2f695993" + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "serde", + "stable_deref_trait", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "ixdtf" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ceaf4c6c48465bead8cb6a0b7c4ee0c86ecbb31239032b9c66ab9a08d2f3ee1" + +[[package]] +name = "js-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libffi" +version = "5.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed185dbb87539a100c1b36c219e16e71572c6d4d4fed3ded898140f755adeaaf" +dependencies = [ + "libc", + "libffi-sys", +] + +[[package]] +name = "libffi-sys" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25831b230b6a90bdea9f28339c1d00d59773a1c492e8ca09b1ad80e56394c261" +dependencies = [ + "cc", +] + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libmimalloc-sys" +version = "0.1.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9" +dependencies = [ + "cc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "metadata" +version = "0.1.0" +dependencies = [ + "ahash", + "dyn-clone", + "parking_lot", + "sha1", + "windows", +] + +[[package]] +name = "mimalloc" +version = "0.1.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d4139bb28d14ad1facf21d5eb8825051b326e172d216b39f6d31df53cc97862" +dependencies = [ + "libmimalloc-sys", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "napi" +version = "2.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55740c4ae1d8696773c78fdafd5d0e5fe9bc9f1b071c7ba493ba5c413a9184f3" +dependencies = [ + "bitflags", + "ctor", + "napi-derive", + "napi-sys", + "once_cell", +] + +[[package]] +name = "napi-derive" +version = "2.16.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cbe2585d8ac223f7d34f13701434b9d5f4eb9c332cccce8dee57ea18ab8ab0c" +dependencies = [ + "cfg-if", + "convert_case", + "napi-derive-backend", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "napi-derive-backend" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1639aaa9eeb76e91c6ae66da8ce3e89e921cd3885e99ec85f4abacae72fc91bf" +dependencies = [ + "convert_case", + "once_cell", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "napi-sys" +version = "2.4.0" +dependencies = [ + "libloading", + "windows-link", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "ns-windows-common" +version = "0.1.0" + +[[package]] +name = "ns-windows-demo" +version = "0.1.0" +dependencies = [ + "backtrace", + "windows", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "serde_core", + "writeable", + "zerovec", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0e75113e14dc5acb068cd0786884f214f1312650a3d36d269f5c4f3cdee8a2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f388202e4b80542a0921078cc23b6333bcf1409c1e3f86404cae4766a6131db" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "resb" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22d392791f3c6802a1905a509e9d1a6039cbbcb5e9e00e5a6d3661f7c874f390" +dependencies = [ + "potential_utf", + "serde_core", +] + +[[package]] +name = "runtime" +version = "0.1.0" +dependencies = [ + "ahash", + "anyhow", + "byteorder", + "chrono", + "form_urlencoded", + "libc", + "libffi", + "metadata", + "mimalloc", + "napi", + "parking_lot", + "regex", + "runtime-binding-gen", + "serde", + "serde_json", + "url", + "v8", + "windows", + "windows-collections", + "windows-core", +] + +[[package]] +name = "runtime-binding-gen" +version = "0.1.0" +dependencies = [ + "ahash", + "anyhow", + "metadata", + "regex", + "serde", + "serde_json", + "windows", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha1" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strck" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42316e70da376f3d113a68d138a60d8a9883c604fe97942721ec2068dab13a9f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "temporal_capi" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c534c1ac4165fb410b5ccd12c79040573622865e881bb8caad70981806a141f1" +dependencies = [ + "diplomat", + "diplomat-runtime", + "icu_calendar", + "icu_locale_core", + "num-traits", + "temporal_rs", + "timezone_provider", + "writeable", + "zoneinfo64", +] + +[[package]] +name = "temporal_rs" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1afc06e45b0d63943c777d0233523fa2e23a12431a73c37b1c0366777b31717" +dependencies = [ + "calendrical_calculations", + "core_maths", + "icu_calendar", + "icu_locale_core", + "ixdtf", + "num-traits", + "timezone_provider", + "tinystr", + "writeable", +] + +[[package]] +name = "timezone_provider" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48738555f588bc05b58cb55206843cde9875bb1fde50101dd1a7c50ac6535cd5" +dependencies = [ + "tinystr", + "zerotrie", + "zerovec", + "zoneinfo64", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "serde_core", + "zerovec", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "v8" +version = "147.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2df8fffd507fb18ed000673a83d937f58e60fb07f3306b2274284125b15137cd" +dependencies = [ + "bindgen", + "bitflags", + "fslock", + "gzip-header", + "home", + "miniz_oxide", + "paste", + "temporal_capi", + "which", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "which" +version = "6.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" +dependencies = [ + "either", + "home", + "rustix", + "winsafe", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", +] + +[[package]] +name = "windows-hermes" +version = "0.1.0" +dependencies = [ + "napi", + "ns-windows-common", + "ns-windows-demo", + "runtime", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core", + "windows-link", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "serde", + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zoneinfo64" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6eb2607e906160c457fd573e9297e65029669906b9ac8fb1b5cd5e055f0705" +dependencies = [ + "calendrical_calculations", + "icu_locale_core", + "potential_utf", + "resb", + "serde", +] diff --git a/packages/windows-hermes/Cargo.toml b/packages/windows-hermes/Cargo.toml new file mode 100644 index 0000000..c147b0d --- /dev/null +++ b/packages/windows-hermes/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "windows-hermes" +version = "0.1.0" +edition = "2021" +description = "NativeScript Windows runtime on Microsoft's prebuilt Hermes. Publishes as @nativescript/windows-hermes." + +# `cdylib` so `build.ps1 -Engine hermes` can emit `nativescript.dll` (the WinUI 3 host DLL); +# `rlib` so the standalone `nativescript-windows` bin can link the shared FFI + bring-up. +[lib] +crate-type = ["rlib", "cdylib"] + +[[bin]] +name = "nativescript-windows" +path = "src/main.rs" + +[features] +# `icu` defaults on: the smaller `uwp/x64` build it trades in for has no package identity, so it +# fails to load in the standalone `nativescript-windows` bin (STATUS_DLL_NOT_FOUND — confirmed, not +# hypothetical; see vendor/README.md). Build with `--no-default-features` only for an MSIX-packaged +# `host_dll` target where that's verified to work. +default = ["icu"] +# Compile the `nativescript.dll` C ABI (src/abi.rs) into the cdylib so the WinUI 3 host can load +# Hermes as a drop-in replacement for the classic runtime. Selected by `build.ps1 -Engine hermes`. +# All deps are already unconditional, so this only toggles the abi/host modules on. +host_dll = [] +# On by default: vendors the `win32/x64` Hermes build + bundled `hermes-icu.dll` (~36 MB of ICU +# data), which works everywhere. Disable (`--no-default-features`) to vendor the smaller `uwp/x64` +# build instead, which uses the OS's built-in ICU and ships no separate ICU DLL. +icu = [] + +[dependencies] +runtime = { path = "../../runtime", features = ["napi_engine"] } +napi = { version = "2", default-features = false, features = ["napi8"] } +# Shared JS prelude + URL polyfill — used by both the cdylib (abi.rs) and the demo bin (main.rs). +ns-windows-common = { path = "../common" } +# Crash reporter + self-test harness for the demo bin (main.rs) only. +ns-windows-demo = { path = "../demo" } + +# Windows-port fix so napi_* resolve from THIS cdylib (nativescript.dll) when loaded by the WinUI 3 +# .NET host, not from the host .exe (which has no napi exports). See packages/vendor/napi-sys. +# (Hermes' napi_* live in hermes.dll; the cdylib forward-exports them, so the probe resolves here.) +[patch.crates-io] +napi-sys = { path = "../vendor/napi-sys" } + +# The crash reporter symbolizes native frames from the release build's PDB. +[profile.release] +debug = true diff --git a/packages/windows-hermes/README.md b/packages/windows-hermes/README.md new file mode 100644 index 0000000..9e8943c --- /dev/null +++ b/packages/windows-hermes/README.md @@ -0,0 +1,27 @@ +# @nativescript/windows-hermes + +NativeScript Windows runtime on **Microsoft's prebuilt Hermes** (`hermes.dll`, which exports both +`napi_*` and the JSR C API), with no Node/Bun/Deno host. The engine-neutral +`runtime::napi_engine` WinRT interop runs unchanged over Hermes's `napi_env`. + +## As an app runtime (drop-in for `@nativescript/windows`) +Publishes as `@nativescript/windows-hermes`, the **same** WinUI 3 framework as +`@nativescript/windows` with the Hermes runtime DLL — swap the dependency and an app runs +unchanged. Build the framework with the engine flag: +```sh +pwsh -File ../../template/build.ps1 -Engine hermes # or: npm run build +``` +The engine → runtime-DLL adapter (the C ABI the WinUI 3 host P/Invokes) follows the reference +implementation in `../windows-quickjs/src/abi.rs`. See `../README.md` for the full contract. + +## Standalone host (dev/bench) +```sh +cargo build --release --manifest-path packages/windows-hermes/Cargo.toml +target/release/nativescript-windows.exe # runs the WinRT demo, exit 0 +``` +build.rs links `vendor/x64/hermes.lib`, forward-exports Hermes's `napi_*` from the exe (so napi-sys +resolves them), and copies `hermes.dll`/`hermes-icu.dll` next to the binary. + +## Notes +- Prebuilt engine binaries are committed under `vendor/` — see `vendor/README.md` for provenance + (Microsoft.JavaScript.Hermes NuGet) and the refresh recipe. diff --git a/packages/windows-hermes/build.rs b/packages/windows-hermes/build.rs new file mode 100644 index 0000000..b166d61 --- /dev/null +++ b/packages/windows-hermes/build.rs @@ -0,0 +1,49 @@ +//! Links Microsoft's prebuilt Hermes (vendor/x64//hermes.{dll,lib}) and makes the host +//! exe re-export Hermes's `napi_*` symbols so napi-sys's runtime lookup (GetProcAddress on the +//! exe, the only mode on Windows) resolves them — the same way Node/Bun expose napi to `.node` +//! modules. `jsr_*` are called directly (imported from hermes.lib). Also copies the runtime DLLs +//! next to the exe so it runs without PATH setup. +//! +//! Two vendored variants, picked by the `icu` feature (see vendor/README.md for provenance): +//! - `icu` (default off): the `win32/x64` build + `hermes-icu.dll` (~36 MB of bundled ICU data). +//! - no `icu` (default): the `uwp/x64` build, which uses the OS's built-in ICU and ships no +//! separate ICU DLL — ~36 MB smaller, at the cost of requiring package identity to run. +use std::path::PathBuf; + +fn main() { + let manifest = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); + let vendor = manifest.join("vendor"); + let variant = if cfg!(feature = "icu") { "icu" } else { "no-icu" }; + let libdir = vendor.join("x64").join(variant); + + // Import library for hermes.dll (provides jsr_* + napi_* import stubs). + println!("cargo:rustc-link-search=native={}", libdir.display()); + println!("cargo:rustc-link-lib=dylib=hermes"); + + // Forward-export every napi_* from the exe to hermes.dll, so napi-sys's + // Library::this()+GetProcAddress finds them. napi_symbols.txt was generated from the DLL's + // export table (llvm-objdump -p hermes.dll | grep napi_). + let syms = std::fs::read_to_string(libdir.join("napi_symbols.txt")) + .expect("vendor napi_symbols.txt missing"); + for name in syms.lines().map(str::trim).filter(|l| !l.is_empty()) { + println!("cargo:rustc-link-arg=/EXPORT:{name}=hermes.{name}"); + } + + // Copy the runtime DLL(s) next to the produced exe (target//). + // OUT_DIR = target//build/-/out → three parents up is target/. + let out = PathBuf::from(std::env::var("OUT_DIR").unwrap()); + if let Some(profile_dir) = out.ancestors().nth(3) { + // hermes-icu.dll only exists in the `icu` variant; the uwp/no-icu build has no such file. + let dlls: &[&str] = if cfg!(feature = "icu") { + &["hermes.dll", "hermes-icu.dll"] + } else { + &["hermes.dll"] + }; + for dll in dlls { + let _ = std::fs::copy(libdir.join(dll), profile_dir.join(dll)); + } + } + + println!("cargo:rerun-if-changed=vendor/x64/icu/napi_symbols.txt"); + println!("cargo:rerun-if-changed=vendor/x64/no-icu/napi_symbols.txt"); +} diff --git a/packages/windows-hermes/package.json b/packages/windows-hermes/package.json new file mode 100644 index 0000000..561c91e --- /dev/null +++ b/packages/windows-hermes/package.json @@ -0,0 +1,43 @@ +{ + "name": "@nativescript/windows-hermes", + "version": "0.1.0", + "description": "NativeScript Windows runtime (Hermes engine) with a WinUI 3 app template", + "keywords": [ + "NativeScript", + "Windows", + "WinRT", + "WinUI3", + "windows-app-sdk", + "runtime", + "hermes" + ], + "repository": { + "type": "git", + "url": "https://github.com/NativeScript/windows-runtime", + "directory": "packages/windows-hermes" + }, + "author": { + "name": "NativeScript Team", + "email": "oss@nativescript.org" + }, + "license": "Apache-2.0", + "os": [ + "win32" + ], + "cpu": [ + "x64" + ], + "scripts": { + "build": "pwsh -File ../../template/build.ps1 -Engine hermes" + }, + "files": [ + "framework/**/*", + "!framework/**/bin/**", + "!framework/**/obj/**", + "README.md" + ], + "nativescript": { + "runtime": "windows", + "engine": "hermes" + } +} diff --git a/packages/windows-hermes/src/abi.rs b/packages/windows-hermes/src/abi.rs new file mode 100644 index 0000000..9bb12e1 --- /dev/null +++ b/packages/windows-hermes/src/abi.rs @@ -0,0 +1,172 @@ +//! `nativescript.dll` C ABI for the Hermes engine — the WinUI 3 .NET host P/Invokes exactly this +//! surface (`runtime_init`, `runtime_runscript`, `runtime_pump_timers`, …), identical to the +//! classic V8 runtime's DLL, so an app swaps `@nativescript/windows` for +//! `@nativescript/windows-hermes` with no code change. Built into the cdylib only under the +//! `host_dll` feature (`build.ps1 -Engine hermes`); the default build still produces the standalone +//! `nativescript-windows.exe`. +//! +//! Same shape as the reference (`windows-quickjs/src/abi.rs`): the engine-neutral work (WinRT +//! init, globals, `Windows` namespace, event-loop turn) lives in `runtime::napi_engine::host_abi`; +//! the three engine-specific pieces (create the env, evaluate a script, drain microtasks) come +//! from `crate::host`. + +use std::cell::Cell; +use std::ffi::{c_char, c_int, c_void, CStr, CString}; + +use napi::Env; +use runtime::napi_engine::host_abi; + +use crate::host; + +thread_local! { + /// The Hermes `napi_env` for this thread, captured at `runtime_init`. `runtime_pump_timers` + /// takes no handle (the classic ABI is stateless there), so the env is kept thread-local for + /// the pump to reach it. + static HOST_ENV: Cell<*mut c_void> = const { Cell::new(std::ptr::null_mut()) }; +} + +fn host_env() -> Option<*mut c_void> { + let raw = HOST_ENV.with(|c| c.get()); + (!raw.is_null()).then_some(raw) +} + +/// Create the runtime on Hermes and bring WinRT up. Returns a non-zero handle on success (the +/// classic host treats `0` as failure). `app_root` is accepted for ABI parity. +#[no_mangle] +pub extern "C" fn runtime_init(app_root: *const c_char) -> i64 { + let result = std::panic::catch_unwind(|| unsafe { + // Populate napi-sys's symbol table from Hermes's `napi_*`, which this module forward-exports + // to hermes.dll (build.rs's /EXPORT:napi_*=hermes.napi_* linker args, applied to the cdylib + // as well as the exe). Resolving THIS module rather than the process .exe requires the + // vendored napi-sys patch (packages/vendor/napi-sys): stock napi-sys queries + // GetModuleHandleExW(0, NULL) = the .NET host .exe, which exports no napi_*, so every call + // would abort. The patch's probe follows the forwarders into hermes.dll. Validated by a C# + // P/Invoke harness (LoadLibrary nativescript.dll → runtime_init → real WinRT round-trip). + std::mem::forget(napi::sys::setup()); + + let app_root = if app_root.is_null() { + String::new() + } else { + CStr::from_ptr(app_root).to_string_lossy().into_owned() + }; + + let raw = host::shared_env_ptr(); + if raw.is_null() { + return 0; + } + let env = Env::from_raw(raw as napi::sys::napi_env); + if host_abi::initialize_runtime(&env, &app_root).is_err() { + return 0; + } + // Engine-specific JS setup that needs the engine's own eval: URL polyfill + runtime prelude + // (queueMicrotask + NSWinRT.toPromise over the loop keep-alive natives). + if let Err(e) = host::run_script_checked(raw, ns_windows_common::url_polyfill::POLYFILL) { + runtime::store_last_js_error(format!("[url_polyfill] {e}")); + } + if let Err(e) = host::run_script_checked(raw, ns_windows_common::prelude::PRELUDE) { + runtime::store_last_js_error(format!("[prelude] {e}")); + } + + HOST_ENV.with(|c| c.set(raw)); + // A stable non-zero token; per-instance state is process-global (one leaked runtime), so + // the handle only needs to be truthy and round-trip through the host. + 1 + }); + result.unwrap_or(0) +} + +#[no_mangle] +pub extern "C" fn runtime_deinit(_runtime: i64) { + // The Hermes runtime + env are process-lifetime (leaked, as a real host keeps them); nothing + // per-call to free. Present for ABI parity with the classic runtime. + HOST_ENV.with(|c| c.set(std::ptr::null_mut())); +} + +#[no_mangle] +pub extern "C" fn runtime_runscript( + _runtime: i64, + script: *const c_char, + _filename: *const c_char, +) { + if script.is_null() { + return; + } + let _ = std::panic::catch_unwind(|| unsafe { + if let Some(raw) = host_env() { + let code = CStr::from_ptr(script).to_string_lossy(); + if let Err(e) = host::run_script_checked(raw, &code) { + eprintln!("[NativeScript] script error: {e}"); + runtime::store_last_js_error(e); + } + } + }); +} + +/// Drive one turn of the event loop (timers, WinRT async completions, microtasks). The WinUI 3 +/// host calls this each frame from `CompositionTarget.Rendering`. +#[no_mangle] +pub extern "C" fn runtime_pump_timers() { + let _ = std::panic::catch_unwind(|| unsafe { + if let Some(raw) = host_env() { + let env = Env::from_raw(raw as napi::sys::napi_env); + let mut drain = || host::drain_microtasks(raw); + host_abi::pump_once(&env, &mut drain); + } + }); +} + +/// Forward a host lifecycle event into JS via `globalThis.__nsOnAppEvent(kind, message)`. +#[no_mangle] +pub extern "C" fn runtime_notify_app_event(_runtime: i64, kind: c_int, message: *const c_char) { + let _ = std::panic::catch_unwind(|| unsafe { + if let Some(raw) = host_env() { + let msg = if message.is_null() { + "null".to_string() + } else { + let m = CStr::from_ptr(message).to_string_lossy().replace('`', "\\`"); + format!("`{m}`") + }; + let code = format!( + "typeof __nsOnAppEvent==='function' && __nsOnAppEvent({kind}, {msg})" + ); + let _ = host::run_script_checked(raw, &code); + } + }); +} + +#[no_mangle] +pub extern "C" fn runtime_set_local_folder(path: *const c_char) { + if path.is_null() { + return; + } + let s = unsafe { CStr::from_ptr(path) }.to_string_lossy().into_owned(); + runtime::set_log_dir(s); +} + +#[no_mangle] +pub extern "C" fn runtime_install_ctrlc_handler(_exit_code: i32) { + // No-op on the engine hosts: the WinUI 3 process owns Ctrl+C. Present for ABI parity. +} + +#[no_mangle] +pub extern "C" fn runtime_has_devtools() -> bool { + false +} + +/// Returns the last JS error (message + stack) or NULL. Caller frees with `runtime_free_js_error`. +#[no_mangle] +pub extern "C" fn runtime_get_last_js_error() -> *mut c_char { + match runtime::get_last_js_error() { + Some(s) => CString::new(s) + .map(|c| c.into_raw()) + .unwrap_or(std::ptr::null_mut()), + None => std::ptr::null_mut(), + } +} + +#[no_mangle] +pub extern "C" fn runtime_free_js_error(ptr: *mut c_char) { + if !ptr.is_null() { + drop(unsafe { CString::from_raw(ptr) }); + } +} diff --git a/packages/windows-hermes/src/lib.rs b/packages/windows-hermes/src/lib.rs new file mode 100644 index 0000000..66b692e --- /dev/null +++ b/packages/windows-hermes/src/lib.rs @@ -0,0 +1,150 @@ +//! `@nativescript/windows-hermes` — NativeScript Windows runtime on Microsoft's prebuilt Hermes. +//! +//! Hermes ships no compilable shim (unlike QuickJS/V8/JSC): `hermes.dll` already exports the JSR +//! C API (`jsr_create_runtime`, `jsr_runtime_get_node_api_env`, …) and a full `napi_*` surface. +//! This crate holds the FFI to that API plus the engine bring-up (create runtime + `napi_env`, +//! evaluate a script, drain microtasks), shared by both the standalone host (`main.rs`) and the +//! `nativescript.dll` adapter (`abi.rs`, `host_dll` feature). Keeping env-creation in the lib is +//! what lets the DLL adapter reuse it instead of copy-pasting `main.rs`. + +use std::ffi::{c_char, c_void}; + +use napi::sys::{napi_env, napi_value}; + +// The `nativescript.dll` C ABI (WinUI 3 host DLL), compiled only under the `host_dll` feature. +#[cfg(feature = "host_dll")] +pub mod abi; + +/// Hermes's JSR C API (imported from hermes.lib; see build.rs). All return `napi_status` (i32). +pub mod ffi { + use super::*; + + extern "C" { + pub fn jsr_create_config(config: *mut *mut c_void) -> i32; + pub fn jsr_config_set_explicit_microtasks(config: *mut c_void, value: bool) -> i32; + pub fn jsr_create_runtime(config: *mut c_void, runtime: *mut *mut c_void) -> i32; + pub fn jsr_runtime_get_node_api_env(runtime: *mut c_void, env: *mut napi_env) -> i32; + pub fn jsr_open_napi_env_scope(env: napi_env, scope: *mut *mut c_void) -> i32; + pub fn jsr_close_napi_env_scope(env: napi_env, scope: *mut c_void) -> i32; + pub fn jsr_delete_runtime(runtime: *mut c_void) -> i32; + pub fn jsr_run_script( + env: napi_env, + source: napi_value, + source_url: *const c_char, + result: *mut napi_value, + ) -> i32; + pub fn jsr_drain_microtasks(env: napi_env, max_count_hint: i32, result: *mut bool) -> i32; + } +} + +/// Bring up a Hermes runtime + its `napi_env`, with a napi_env scope open on the calling thread. +/// Returns `(runtime, env, scope)`; the caller owns their lifetime (`jsr_close_napi_env_scope` +/// then `jsr_delete_runtime` to tear down), or leaks them for a process-lifetime host. Returns +/// `None` on failure. +/// +/// Explicit microtasks: without this Hermes schedules promise reactions through a host-provided +/// `setImmediate` (the React Native model), which a bare engine doesn't have — promises would +/// throw on settle. With it, reactions queue as microtasks that [`drain_microtasks`] runs. +/// +/// # Safety +/// Calls into `hermes.dll`; the returned handles must be used only on the thread that created them. +pub unsafe fn create_runtime_env() -> Option<(*mut c_void, napi_env, *mut c_void)> { + let mut config: *mut c_void = std::ptr::null_mut(); + let mut runtime: *mut c_void = std::ptr::null_mut(); + let mut env_raw: napi_env = std::ptr::null_mut(); + if ffi::jsr_create_config(&mut config) != 0 + || ffi::jsr_config_set_explicit_microtasks(config, true) != 0 + || ffi::jsr_create_runtime(config, &mut runtime) != 0 + || ffi::jsr_runtime_get_node_api_env(runtime, &mut env_raw) != 0 + || env_raw.is_null() + { + return None; + } + let mut scope: *mut c_void = std::ptr::null_mut(); + if ffi::jsr_open_napi_env_scope(env_raw, &mut scope) != 0 { + return None; + } + Some((runtime, env_raw, scope)) +} + +/// Evaluate `code` and return the completion value coerced to a string, or the thrown exception's +/// message. Shared by the standalone host and the `nativescript.dll` adapter. +pub fn run_script(env: &napi::Env, code: &str) -> Result { + use napi::{JsUnknown, NapiRaw, NapiValue}; + let source = env.create_string(code).map_err(|e| e.to_string())?; + let url = std::ffi::CString::new("").unwrap(); + let mut result: napi_value = std::ptr::null_mut(); + let status = unsafe { ffi::jsr_run_script(env.raw(), source.raw(), url.as_ptr(), &mut result) }; + if status != napi::sys::Status::napi_ok || result.is_null() { + let mut is_pending = false; + unsafe { napi::sys::napi_is_exception_pending(env.raw(), &mut is_pending) }; + if is_pending { + let mut err: napi_value = std::ptr::null_mut(); + unsafe { napi::sys::napi_get_and_clear_last_exception(env.raw(), &mut err) }; + let msg = unsafe { JsUnknown::from_raw_unchecked(env.raw(), err) } + .coerce_to_string() + .and_then(|s| s.into_utf8()) + .and_then(|s| Ok(s.as_str()?.to_owned())) + .unwrap_or_else(|_| "".into()); + return Err(format!("JS exception: {msg}")); + } + return Err(format!("jsr_run_script status {status}")); + } + let val = unsafe { JsUnknown::from_raw_unchecked(env.raw(), result) }; + val.coerce_to_string() + .and_then(|s| s.into_utf8()) + .and_then(|s| Ok(s.as_str()?.to_owned())) + .map_err(|e| e.to_string()) +} + +/// Run Hermes's microtask queue to exhaustion (promise reactions) — the event loop's drain hook. +pub fn drain_microtasks(env_raw: napi_env) { + unsafe { + let mut more = false; + ffi::jsr_drain_microtasks(env_raw, -1, &mut more); + } +} + +/// The three engine-specific pieces the `nativescript.dll` adapter needs, in the same shape as the +/// QuickJS package's `shim` (`shared_env_ptr` / `run_script_checked` / `drain_microtasks`) so +/// `abi.rs` reads the same across engines. Gated behind `host_dll`. +#[cfg(feature = "host_dll")] +pub mod host { + use std::cell::Cell; + use std::ffi::c_void; + + use napi::Env; + + /// The process-lifetime Hermes `napi_env` as a raw pointer. Brings up the runtime + env + scope + /// on first call and leaks them (as a real host keeps them for the process), caching the env + /// thread-local. Returns null on failure. + pub fn shared_env_ptr() -> *mut c_void { + thread_local! { + static ENV: Cell<*mut c_void> = const { Cell::new(std::ptr::null_mut()) }; + } + ENV.with(|e| { + let cur = e.get(); + if !cur.is_null() { + return cur; + } + // runtime + scope are intentionally leaked (process-lifetime); only env is kept. + let (_runtime, env_raw, _scope) = match unsafe { super::create_runtime_env() } { + Some(t) => t, + None => return std::ptr::null_mut(), + }; + e.set(env_raw as *mut c_void); + env_raw as *mut c_void + }) + } + + /// Evaluate `code`, returning its string coercion or the thrown exception's message. + pub fn run_script_checked(raw: *mut c_void, code: &str) -> Result { + let env = unsafe { Env::from_raw(raw as napi::sys::napi_env) }; + super::run_script(&env, code) + } + + /// Drain Hermes's microtask queue — the event loop's drain hook. + pub fn drain_microtasks(raw: *mut c_void) { + super::drain_microtasks(raw as napi::sys::napi_env); + } +} diff --git a/packages/windows-hermes/src/main.rs b/packages/windows-hermes/src/main.rs new file mode 100644 index 0000000..5b51f59 --- /dev/null +++ b/packages/windows-hermes/src/main.rs @@ -0,0 +1,125 @@ +//! Standalone host — the NativeScript Windows runtime running on **Microsoft's prebuilt +//! Hermes**, with no Node/Bun/Deno. Hermes's `hermes.dll` exports both the JSR C API +//! (`jsr_create_runtime`, `jsr_runtime_get_node_api_env`, ...) and a full `napi_*` surface. So: +//! 1. `napi::sys::setup()` populates napi-sys from the exe's forwarded exports (build.rs +//! re-exports Hermes's `napi_*`), so napi-rs's `Env` works. +//! 2. `jsr_*` brings up a Hermes runtime + napi_env; we open a napi_env scope on this thread. +//! 3. runtime::napi_engine (the engine-neutral WinRT interop) runs unchanged over that env. +//! +//! The FFI + engine bring-up (create runtime/env, run a script, drain microtasks) live in the +//! crate lib (`windows_hermes`) so the `nativescript.dll` adapter (`abi.rs`) reuses them. + +use napi::Env; +use ns_windows_demo::{crash, harness}; +use windows_hermes::{create_runtime_env, drain_microtasks, ffi, run_script}; + +fn main() { + crash::install(); + unsafe { + // 1. Populate napi-sys from the exe's forwarded Hermes napi_* exports. + std::mem::forget(napi::sys::setup()); + + // 2. Bring up a Hermes runtime + its napi_env, with a scope open on this thread. + let (runtime, env_raw, scope) = match create_runtime_env() { + Some(t) => t, + None => { + eprintln!("failed to create Hermes napi_env"); + std::process::exit(1); + } + }; + let env = Env::from_raw(env_raw); + + // 3. Bring up the WinRT runtime over this env — identical calls to the Node/QuickJS hosts. + runtime::napi_engine::invoke::ensure_winrt_initialized(); + if let Err(e) = runtime::napi_engine::globals::install_globals(&env) { + eprintln!("install_globals failed: {e}"); + std::process::exit(1); + } + match runtime::napi_engine::ns_proxy::create_namespace_proxy(&env, "Windows") { + Ok(windows_ns) => { + if let Ok(mut global) = env.get_global() { + let _ = global.set_named_property("Windows", windows_ns); + } + } + Err(e) => { + eprintln!("namespace setup failed: {e}"); + std::process::exit(1); + } + } + + // The full WinRT runtime running on standalone Hermes (no Node/Bun/Deno). + let _ = run_script(&env, ns_windows_common::url_polyfill::POLYFILL); // URL/URLSearchParams + let _ = run_script(&env, ns_windows_common::prelude::PRELUDE); // queueMicrotask + NSWinRT + let drain = || drain_microtasks(env_raw); + + // App mode: `nativescript-windows ` — run the script, then drive the event + // loop (timers, WinRT async completions, microtasks) until the app goes idle. + if let Some(path) = std::env::args().skip(1).find(|a| !a.starts_with('-')) { + let code = match std::fs::read_to_string(&path) { + Ok(c) => c, + Err(e) => { + eprintln!("cannot read {path}: {e}"); + std::process::exit(1); + } + }; + if let Err(e) = run_script(&env, &code) { + eprintln!("{e}"); + std::process::exit(1); + } + runtime::napi_engine::event_loop::run_event_loop(&env, drain, None); + ffi::jsr_close_napi_env_scope(env_raw, scope); + let _ = ffi::jsr_delete_runtime(runtime); + return; + } + + if std::env::var("NSWIN_BENCH").is_ok() { + match run_script(&env, ns_windows_demo::bench::WORKLOAD) { + Ok(v) => print!("{v}"), + Err(e) => eprintln!("[bench] ERROR: {e}"), + } + return; + } + let stages = [ + ("engine", "1 + 1"), + ("runtime globals (performance/__time)", "typeof performance + ',' + typeof __time"), + ("runtime closure call (__time)", "typeof __time()"), + ("Windows namespace", "typeof Windows"), + ("namespace resolution (Windows.Data.Json)", "typeof Windows.Data.Json"), + ("class resolution (JsonObject)", "typeof Windows.Data.Json.JsonObject"), + ("static method resolution", "typeof Windows.Data.Json.JsonValue.CreateNumberValue"), + ("enum resolution", "typeof Windows.Data.Json.JsonValueType.Number"), + ("static method x10", "for (var i=0;i<10;i++) Windows.Data.Json.JsonValue.CreateNumberValue; 'ok'"), + ("WinRT call #1 (round-trip)", "Windows.Data.Json.JsonValue.CreateNumberValue(5).GetNumber()"), + ("WinRT call #2 (round-trip)", "Windows.Data.Json.JsonValue.CreateNumberValue(42).GetNumber()"), + ("WinRT call #3 (string)", "Windows.Data.Json.JsonValue.CreateStringValue('hi').GetString()"), + ("WinRT calls x20 (stress)", "var s=0; for (var i=0;i<20;i++) s+=Windows.Data.Json.JsonValue.CreateNumberValue(i).GetNumber(); s"), + ("JsonObject round-trip", "var o=new Windows.Data.Json.JsonObject(); o.SetNamedValue('a', Windows.Data.Json.JsonValue.CreateNumberValue(7)); o.GetNamedNumber('a')+':'+o.Stringify()"), + ("URL parse components", "var u=new URL('https://us:pw@ex.com:8443/a/b?x=1&y=2#h'); u.host+'|'+u.pathname+'|'+u.hash+'|'+u.origin"), + ("URLSearchParams get/getAll", "var u=new URL('https://e.com/?a=1&a=2&b=3'); u.searchParams.getAll('a').join(',')+'|'+u.searchParams.get('b')"), + ("URL setter syncs href", "var u=new URL('https://e.com/'); u.pathname='/x'; u.searchParams.set('q','hi'); u.href"), + ("URL.canParse", "String(URL.canParse('http://ok/'))+','+String(URL.canParse('nope'))"), + ]; + let ok = harness::run_stages("windows-hermes", &stages, |code| run_script(&env, code)) + && harness::run_stages("windows-hermes", harness::FEATURE_STAGES, |code| { + run_script(&env, code) + }) + && harness::run_async_demo( + "windows-hermes", + |code| run_script(&env, code), + || { + runtime::napi_engine::event_loop::run_event_loop( + &env, + drain, + Some(std::time::Duration::from_secs(15)), + ) + }, + ); + + ffi::jsr_close_napi_env_scope(env_raw, scope); + let _ = ffi::jsr_delete_runtime(runtime); + + if !ok { + std::process::exit(1); + } + } +} diff --git a/packages/windows-hermes/vendor/README.md b/packages/windows-hermes/vendor/README.md new file mode 100644 index 0000000..e4e1350 --- /dev/null +++ b/packages/windows-hermes/vendor/README.md @@ -0,0 +1,98 @@ +# Vendored Hermes engine (prebuilt) + +These are **committed prebuilt binaries** (no git-LFS), mirroring how +[napi-android](https://github.com/NativeScript/napi-android) vendors its engine libs under +`test-app/runtime/src/main/libs///`. Here the layout is `//` (the engine +is the crate). + +## Two vendored variants, selected by the `icu` Cargo feature + +`build.rs` picks `x64/icu/` when built with `--features icu`, otherwise `x64/no-icu/` (the +default). See "Note on size and the `icu` feature" below for why the default is the smaller one +and what that trades off. + +### `x64/icu/` (`--features icu`) — from the NuGet package's `win32/x64` build +| File | Size | Purpose | +|---|---|---| +| `hermes.dll` | ~7 MB | Hermes engine + Node-API (`napi_*`) + JSR C API (`jsr_*`), linked against the OS-independent ICU build | +| `hermes-icu.dll` | ~36 MB | Bundled ICU data that this `hermes.dll` links against | +| `hermes.lib` | ~72 KB | Import library for `hermes.dll` (used at link time) | +| `napi_symbols.txt` | — | `napi_*` export list forwarded by `build.rs` (see below) | + +### `x64/no-icu/` (default) — from the NuGet package's `uwp/x64` build +| File | Size | Purpose | +|---|---|---| +| `hermes.dll` | ~6.7 MB | Hermes engine + Node-API + JSR, built against the OS's built-in ICU (no bundled ICU data) | +| `hermes.lib` | ~72 KB | Import library for `hermes.dll` | +| `napi_symbols.txt` | — | Same export list as the `icu` variant (diffed identical, byte-for-byte after filtering the one regex false-positive below) | + +`include/` (shared by both variants) holds the matching headers (`hermes/js_runtime_api.h`, +`node-api/js_native_api.h`) for reference; the host declares the `jsr_*` FFI directly. + +## Provenance / how to refresh + +Source: NuGet package **`Microsoft.JavaScript.Hermes`** (microsoft/hermes-windows). Both variants +must be refreshed from the **same** package version (confirmed via `hermes.dll`'s embedded +`FileVersion`, e.g. `0.0.2607.6001`, matching the `VER` fetched below). + +```sh +VER=$(curl -s https://api.nuget.org/v3-flatcontainer/microsoft.javascript.hermes/index.json \ + | grep -oE '0\.0\.0-[0-9]+\.[0-9]+-[a-f0-9]+' | tail -1) +curl -sL -o hermes.nupkg \ + "https://api.nuget.org/v3-flatcontainer/microsoft.javascript.hermes/$VER/microsoft.javascript.hermes.$VER.nupkg" + +# icu variant (win32/x64): +unzip -o hermes.nupkg 'build/native/win32/x64/*' 'build/native/include/*' +cp build/native/win32/x64/{hermes.dll,hermes-icu.dll,hermes.lib} x64/icu/ +cp -r build/native/include/{hermes,node-api} include/ +llvm-objdump -p x64/icu/hermes.dll | grep -oE 'napi_[a-z0-9_]+' | sort -u > x64/icu/napi_symbols.txt + +# no-icu variant (uwp/x64): +unzip -o hermes.nupkg 'build/native/uwp/x64/*' +cp build/native/uwp/x64/{hermes.dll,hermes.lib} x64/no-icu/ +llvm-objdump -p x64/no-icu/hermes.dll | grep -oE 'napi_[a-z0-9_]+' | sort -u > x64/no-icu/napi_symbols.txt +``` + +`napi_symbols.txt` is the list of `napi_*` exports that `build.rs` forward-exports from the host exe +so napi-sys's runtime lookup resolves them (Node/Bun do the same to expose napi to `.node` modules). + +> Both DLLs' export tables happen to contain `jsr_close_napi_env_scope` / +> `jsr_open_napi_env_scope` at the identical offset, and the `napi_[a-z0-9_]+` regex matches the +> substring `napi_env_scope` inside those names — a false positive (no such standalone export +> exists in either DLL). Drop that line after regenerating, or the `/EXPORT:` linker arg `build.rs` +> emits for it will fail to resolve. + +## Note on size and the `icu` feature + +The 36 MB `hermes-icu.dll` dominates the `icu` variant. The `uwp/x64` build (`no-icu`, default) +uses the OS's built-in ICU instead and needs no separate ICU DLL, shrinking the vendored payload +from ~41.8 MB to ~6.8 MB (measured: `43,799,566` → `7,145,446` bytes, a ~35 MB / 82% reduction). + +**Verified outcome (2026-07-27): the `no-icu` variant does NOT load in a plain, unpackaged Win32 +process.** Loading `x64/no-icu/hermes.dll` (directly via `LoadLibraryEx`, and via the standalone +`nativescript-windows.exe` host built with default features) fails with `ERROR_MOD_NOT_FOUND` / +`STATUS_DLL_NOT_FOUND` (`0xC0000135`). Root cause, confirmed by diffing the two DLLs' import +tables: the `uwp/x64` `hermes.dll` links `MSVCP140_APP.dll`, `VCRUNTIME140_APP.dll`, and +`VCRUNTIME140_1_APP.dll` — the "Store/UWP" flavor of the VC++ runtime, shipped only inside the +`Microsoft.VCLibs.140.00.UWPDesktop` **framework package**. Those DLLs are resolvable only for a +process that has **package identity** (MSIX/APPX) with a declared dependency on that framework +package — even when the framework package is installed system-wide (it was, on the machine this +was tested on: `Get-AppxPackage Microsoft.VCLibs.140.00.UWPDesktop` lists it), its DLLs live under +an ACL-protected path (`C:\Program Files\WindowsApps\...`) that isn't on the ordinary DLL search +path for an unpackaged `.exe`. The `icu`/`win32` variant has no such dependency (imports only +`KERNEL32`/`ADVAPI32`/`WINMM`/UCRT) and loads and runs standalone without issue — confirmed via the +full `nativescript-windows.exe` staged demo (engine bring-up, `Windows` namespace, WinRT +round-trips, IMap/subclass/composable-ctor suites, async event loop) all passing. + +**Practical consequence:** +- `--features icu` (the `win32/x64` pair): works everywhere, including the standalone + `nativescript-windows.exe` dev/bench host. Use this for local development and for any consumer + that isn't a packaged MSIX app. +- default (no `icu`, the `uwp/x64` single DLL): only usable inside a **packaged (MSIX) host that + declares the `Microsoft.VCLibs.140.00.UWPDesktop` framework package dependency** — i.e. the + `nativescript.dll` adapter (`host_dll` feature) loaded by the WinUI 3 app template, which is + deployed as MSIX. It is **not** usable via the standalone `nativescript-windows.exe` harness + (confirmed failing, above) since that process has no package identity. Whether it actually works + once loaded inside a real packaged WinUI 3 host is a reasonable inference from how Desktop Bridge + framework packages resolve, but has not itself been verified end-to-end (that would require + building and MSIX-deploying the framework, which is outside what was checked here). diff --git a/packages/windows-hermes/vendor/include/hermes/hermes_api.h b/packages/windows-hermes/vendor/include/hermes/hermes_api.h new file mode 100644 index 0000000..6e03b73 --- /dev/null +++ b/packages/windows-hermes/vendor/include/hermes/hermes_api.h @@ -0,0 +1,285 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT license. + */ + +#ifndef HERMES_HERMES_API_H +#define HERMES_HERMES_API_H + +#include "js_runtime_api.h" + +EXTERN_C_START + +typedef struct hermes_local_connection_s *hermes_local_connection; +typedef struct hermes_remote_connection_s *hermes_remote_connection; + +//============================================================================= +// jsr_runtime +//============================================================================= + +JSR_API hermes_dump_crash_data(jsr_runtime runtime, int32_t fd); +JSR_API hermes_sampling_profiler_enable(); +JSR_API hermes_sampling_profiler_disable(); +JSR_API hermes_sampling_profiler_add(jsr_runtime runtime); +JSR_API hermes_sampling_profiler_remove(jsr_runtime runtime); +JSR_API hermes_sampling_profiler_dump_to_file(const char *filename); + +//============================================================================= +// jsr_config +//============================================================================= + +JSR_API hermes_config_enable_default_crash_handler( + jsr_config config, + bool value); + +/// Set the Intl provider mode for a runtime. +/// mode values: 0 = Default (global resolution), +/// 1 = ForceWinGlob (always use NLS APIs), +/// 2 = CustomVtable (use the provided vtable). +/// vtable: ICU vtable pointer (only used when mode == 2, else pass NULL). +struct hermes_icu_vtable; +JSR_API hermes_config_set_intl_provider( + jsr_config config, + uint8_t mode, + const struct hermes_icu_vtable *vtable); + +//============================================================================= +// Setting inspector singleton +//============================================================================= + +typedef int32_t(NAPI_CDECL *hermes_inspector_add_page_cb)( + const char *title, + const char *vm, + void *connectFunc); + +typedef void(NAPI_CDECL *hermes_inspector_remove_page_cb)(int32_t page_id); + +JSR_API hermes_set_inspector( + hermes_inspector_add_page_cb add_page_cb, + hermes_inspector_remove_page_cb remove_page_cb); + +//============================================================================= +// Local and remote inspector connections. +// Local is defined in Hermes VM, Remote is defined by inspector outside of VM. +//============================================================================= + +typedef void(NAPI_CDECL *hermes_remote_connection_send_message_cb)( + hermes_remote_connection remote_connection, + const char *message); + +typedef void(NAPI_CDECL *hermes_remote_connection_disconnect_cb)( + hermes_remote_connection remote_connection); + +JSR_API hermes_create_local_connection( + void *connect_func, + hermes_remote_connection remote_connection, + hermes_remote_connection_send_message_cb on_send_message_cb, + hermes_remote_connection_disconnect_cb on_disconnect_cb, + jsr_data_delete_cb on_delete_cb, + void *deleter_data, + hermes_local_connection *local_connection); + +JSR_API hermes_delete_local_connection( + hermes_local_connection local_connection); + +JSR_API hermes_local_connection_send_message( + hermes_local_connection local_connection, + const char *message); + +JSR_API hermes_local_connection_disconnect( + hermes_local_connection local_connection); + +//============================================================================= +// Modern inspector API implementation +//============================================================================= + +typedef struct hermes_runtime_s *hermes_runtime; +typedef struct hermes_cdp_debug_api_s *hermes_cdp_debug_api; +typedef struct hermes_cdp_agent_s *hermes_cdp_agent; +typedef struct hermes_cdp_state_s *hermes_cdp_state; +typedef struct hermes_stack_trace_s *hermes_stack_trace; +typedef struct hermes_sampling_profile_s *hermes_sampling_profile; + +typedef enum { + hermes_status_ok = 0, + hermes_status_error = 1, +} hermes_status; + +typedef enum { + hermes_console_api_type_log, + hermes_console_api_type_debug, + hermes_console_api_type_info, + hermes_console_api_type_error, + hermes_console_api_type_warning, + hermes_console_api_type_dir, + hermes_console_api_type_dir_xml, + hermes_console_api_type_table, + hermes_console_api_type_trace, + hermes_console_api_type_start_group, + hermes_console_api_type_start_group_collapsed, + hermes_console_api_type_end_group, + hermes_console_api_type_clear, + hermes_console_api_type_assert, + hermes_console_api_type_time_end, + hermes_console_api_type_count, +} hermes_console_api_type; + +typedef enum { + hermes_call_stack_frame_kind_js_function, + hermes_call_stack_frame_kind_native_function, + hermes_call_stack_frame_kind_host_function, + hermes_call_stack_frame_kind_gc, +} hermes_call_stack_frame_kind; + +typedef void(NAPI_CDECL *hermes_release_callback)(void *data_to_release); + +typedef void(NAPI_CDECL *hermes_run_runtime_task_callback)( + void *cb_data, + hermes_runtime runtime); + +typedef struct { + void *data; + hermes_run_runtime_task_callback invoke; + hermes_release_callback release; +} hermes_run_runtime_task_functor; + +typedef void(NAPI_CDECL *hermes_enqueue_runtime_task_callback)( + void *cb_data, + hermes_run_runtime_task_functor runtime_task); + +typedef struct { + void *data; + hermes_enqueue_runtime_task_callback invoke; + hermes_release_callback release; +} hermes_enqueue_runtime_task_functor; + +typedef void(NAPI_CDECL *hermes_enqueue_frontend_message_callback)( + void *cb_data, + const char *json_utf8, + size_t json_size); + +typedef struct { + void *data; + hermes_enqueue_frontend_message_callback invoke; + hermes_release_callback release; +} hermes_enqueue_frontend_message_functor; + +typedef void(NAPI_CDECL *hermes_on_sampling_profile_info_callback)( + void *cb_data, + size_t sample_count); + +typedef void(NAPI_CDECL *hermes_on_sampling_profile_sample_callback)( + void *cb_data, + uint64_t timestamp, + uint64_t thread_id, + size_t frame_count); + +typedef void(NAPI_CDECL *hermes_on_sampling_profile_frame_callback)( + void *cb_data, + hermes_call_stack_frame_kind kind, + uint32_t script_id, + const char *function_name, + size_t function_name_size, + const char *script_url, + size_t script_url_size, + uint32_t line_number, + uint32_t column_number); + +typedef hermes_status(NAPI_CDECL *hermes_create_cdp_debug_api)( + hermes_runtime runtime, + hermes_cdp_debug_api *result); +typedef hermes_status(NAPI_CDECL *hermes_release_cdp_debug_api)( + hermes_cdp_debug_api cdp_debug_api); + +typedef hermes_status(NAPI_CDECL *hermes_cdp_debug_api_add_console_message)( + hermes_cdp_debug_api cdp_debug_api, + double timestamp, + hermes_console_api_type type, + const char *args_property_name, + hermes_stack_trace stack_trace); + +typedef hermes_status(NAPI_CDECL *hermes_create_cdp_agent)( + hermes_cdp_debug_api cdp_debug_api, + int32_t execution_context_id, + hermes_enqueue_runtime_task_functor enqueue_runtime_task_callback, + hermes_enqueue_frontend_message_functor enqueue_frontend_message_callback, + hermes_cdp_state cdp_state, + hermes_cdp_agent *result); +typedef hermes_status(NAPI_CDECL *hermes_release_cdp_agent)( + hermes_cdp_agent cdp_agent); + +typedef hermes_status(NAPI_CDECL *hermes_cdp_agent_get_state)( + hermes_cdp_agent cdp_agent, + hermes_cdp_state *result); +typedef hermes_status(NAPI_CDECL *hermes_release_cdp_state)( + hermes_cdp_state cdp_state); + +typedef hermes_status(NAPI_CDECL *hermes_cdp_agent_handle_command)( + hermes_cdp_agent cdp_agent, + const char *json_utf8, + size_t json_size); +typedef hermes_status(NAPI_CDECL *hermes_cdp_agent_enable_runtime_domain)( + hermes_cdp_agent cdp_agent); +typedef hermes_status(NAPI_CDECL *hermes_cdp_agent_enable_debugger_domain)( + hermes_cdp_agent cdp_agent); + +typedef hermes_status(NAPI_CDECL *hermes_capture_stack_trace)( + hermes_runtime runtime, + hermes_stack_trace *result); +typedef hermes_status(NAPI_CDECL *hermes_release_stack_trace)( + hermes_stack_trace stack_trace); + +typedef hermes_status(NAPI_CDECL *hermes_enable_sampling_profiler)( + hermes_runtime runtime); +typedef hermes_status(NAPI_CDECL *hermes_disable_sampling_profiler)( + hermes_runtime runtime); + +typedef hermes_status(NAPI_CDECL *hermes_collect_sampling_profile)( + hermes_runtime runtime, + void *cb_data, + hermes_on_sampling_profile_info_callback on_info_callback, + hermes_on_sampling_profile_sample_callback on_sample_callback, + hermes_on_sampling_profile_frame_callback on_frame_callback, + hermes_sampling_profile *result); +typedef hermes_status(NAPI_CDECL *hermes_release_sampling_profile)( + hermes_sampling_profile profile); + +typedef struct { + void *reserved0; + void *reserved1; + void *reserved2; + + hermes_create_cdp_debug_api create_cdp_debug_api; + hermes_release_cdp_debug_api release_cdp_debug_api; + + hermes_cdp_debug_api_add_console_message add_console_message; + + hermes_create_cdp_agent create_cdp_agent; + hermes_release_cdp_agent release_cdp_agent; + + hermes_cdp_agent_get_state cdp_agent_get_state; + hermes_release_cdp_state release_cdp_state; + + hermes_cdp_agent_handle_command cdp_agent_handle_command; + hermes_cdp_agent_enable_runtime_domain cdp_agent_enable_runtime_domain; + hermes_cdp_agent_enable_debugger_domain cdp_agent_enable_debugger_domain; + + hermes_capture_stack_trace capture_stack_trace; + hermes_release_stack_trace release_stack_trace; + + hermes_enable_sampling_profiler enable_sampling_profiler; + hermes_disable_sampling_profiler disable_sampling_profiler; + hermes_collect_sampling_profile collect_sampling_profile; + hermes_release_sampling_profile release_sampling_profile; +} hermes_inspector_vtable; + +JSR_API hermes_get_inspector_vtable(const hermes_inspector_vtable **vtable); + +EXTERN_C_END + +#endif // !HERMES_HERMES_API_H diff --git a/packages/windows-hermes/vendor/include/hermes/hermes_icu.h b/packages/windows-hermes/vendor/include/hermes/hermes_icu.h new file mode 100644 index 0000000..95aa338 --- /dev/null +++ b/packages/windows-hermes/vendor/include/hermes/hermes_icu.h @@ -0,0 +1,1355 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +/** + * \file hermes_icu.h + * \brief C-compatible ICU vtable v2 for runtime ICU provider selection. + * + * Pure C header - no C++ dependencies. + * + * v2 design: every function pointer uses the exact ICU C API signature. + * No custom wrapper types - real ICU types (UCollator*, UErrorCode*, etc.) + * are used throughout, enabling direct GetProcAddress population for + * system ICU providers without wrapper functions. + */ + +#ifndef HERMES_ICU_H +#define HERMES_ICU_H + +#include "icu_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* --- Calling convention (explicit for x86 ABI stability) --- */ +#ifndef HERMES_ICU_CDECL +#ifdef _WIN32 +#define HERMES_ICU_CDECL __cdecl +#else +#define HERMES_ICU_CDECL +#endif +#endif + +/* --- DLL export/import for hermes_icu C API functions --- + * When building hermes.dll, these default to dllexport. + * When consuming hermes.dll (linking against hermes.lib), define + * HERMES_ICU_API as __declspec(dllimport) before including this header. + * Follows the NAPI_EXTERN pattern from js_native_api.h. */ +#ifndef HERMES_ICU_API +#ifdef _WIN32 +#define HERMES_ICU_API __declspec(dllexport) +#else +#define HERMES_ICU_API __attribute__((visibility("default"))) +#endif +#endif + +/** + * Version of the vtable layout. Providers must match this version. + * Bumped to 100 to clearly distinguish from v1 (which was version 6). + */ +#define HERMES_ICU_VTABLE_VERSION 100 + +/** + * C-compatible struct of ICU function pointers. + * + * Design principles (v2): + * - Every function pointer uses the exact ICU C API signature + * - Error handling via UErrorCode* parameter (standard ICU convention) + * - Real ICU opaque types (UCollator*, UDateFormat*, etc.) + * - HERMES_ICU_CDECL calling convention on all function pointers + * - Never reorder or remove existing pointers — only append + * - Bump HERMES_ICU_VTABLE_VERSION when the struct grows + * - No custom (non-ICU) function entries + * - Entries for future Intl objects are included from the start; + * providers populate them when available, callers check for NULL + */ +typedef struct hermes_icu_vtable { + /* --------------------------------------------------------------- + * Metadata + * --------------------------------------------------------------- */ + + /** Vtable ABI version — must equal HERMES_ICU_VTABLE_VERSION. */ + uint32_t version; + /** ICU version (e.g. 78 for ICU 78.2). 0 = unknown (system-managed). */ + uint32_t icu_version; + /** Provider name (UTF-8, null-terminated). + * Suggested: "bundled", "windows", "custom". NULL = unknown. */ + const char *provider_name; + /** Number of populated function pointers (for forward compat). */ + uint32_t function_count; + + /* =============================================================== + * 2.3.1 Locale (uloc_*) — 27 functions + * =============================================================== */ + + int32_t(HERMES_ICU_CDECL *uloc_forLanguageTag)( + const char *langtag, + char *localeID, + int32_t localeIDCapacity, + int32_t *parsedLength, + UErrorCode *err); + int32_t(HERMES_ICU_CDECL *uloc_toLanguageTag)( + const char *localeID, + char *langtag, + int32_t langtagCapacity, + UBool strict, + UErrorCode *err); + int32_t(HERMES_ICU_CDECL *uloc_canonicalize)( + const char *localeID, + char *name, + int32_t nameCapacity, + UErrorCode *err); + + /* Component extraction */ + int32_t(HERMES_ICU_CDECL *uloc_getLanguage)( + const char *localeID, + char *language, + int32_t languageCapacity, + UErrorCode *err); + int32_t(HERMES_ICU_CDECL *uloc_getScript)( + const char *localeID, + char *script, + int32_t scriptCapacity, + UErrorCode *err); + int32_t(HERMES_ICU_CDECL *uloc_getCountry)( + const char *localeID, + char *country, + int32_t countryCapacity, + UErrorCode *err); + int32_t(HERMES_ICU_CDECL *uloc_getVariant)( + const char *localeID, + char *variant, + int32_t variantCapacity, + UErrorCode *err); + int32_t(HERMES_ICU_CDECL *uloc_getBaseName)( + const char *localeID, + char *name, + int32_t nameCapacity, + UErrorCode *err); + int32_t(HERMES_ICU_CDECL *uloc_getName)( + const char *localeID, + char *name, + int32_t nameCapacity, + UErrorCode *err); + int32_t(HERMES_ICU_CDECL *uloc_getParent)( + const char *localeID, + char *parent, + int32_t parentCapacity, + UErrorCode *err); + + /* Keyword operations */ + int32_t(HERMES_ICU_CDECL *uloc_getKeywordValue)( + const char *localeID, + const char *keywordName, + char *buffer, + int32_t bufferCapacity, + UErrorCode *err); + int32_t(HERMES_ICU_CDECL *uloc_setKeywordValue)( + const char *keywordName, + const char *keywordValue, + char *buffer, + int32_t bufferCapacity, + UErrorCode *err); + UEnumeration *(HERMES_ICU_CDECL *uloc_openKeywords)( + const char *localeID, + UErrorCode *err); + + /* Likely subtags */ + int32_t(HERMES_ICU_CDECL *uloc_addLikelySubtags)( + const char *localeID, + char *maximizedLocaleID, + int32_t maximizedLocaleIDCapacity, + UErrorCode *err); + int32_t(HERMES_ICU_CDECL *uloc_minimizeSubtags)( + const char *localeID, + char *minimizedLocaleID, + int32_t minimizedLocaleIDCapacity, + UErrorCode *err); + + /* Available locales */ + int32_t(HERMES_ICU_CDECL *uloc_countAvailable)(void); + const char *(HERMES_ICU_CDECL *uloc_getAvailable)(int32_t n); + const char *(HERMES_ICU_CDECL *uloc_getDefault)(void); + UEnumeration *(HERMES_ICU_CDECL *uloc_openAvailableByType)( + int32_t type, + UErrorCode *err); + + /* Display names */ + int32_t(HERMES_ICU_CDECL *uloc_getDisplayLanguage)( + const char *locale, + const char *displayLocale, + UChar *language, + int32_t languageCapacity, + UErrorCode *err); + int32_t(HERMES_ICU_CDECL *uloc_getDisplayScript)( + const char *locale, + const char *displayLocale, + UChar *script, + int32_t scriptCapacity, + UErrorCode *err); + int32_t(HERMES_ICU_CDECL *uloc_getDisplayCountry)( + const char *locale, + const char *displayLocale, + UChar *country, + int32_t countryCapacity, + UErrorCode *err); + int32_t(HERMES_ICU_CDECL *uloc_getDisplayName)( + const char *localeID, + const char *inLocaleID, + UChar *result, + int32_t maxResultSize, + UErrorCode *err); + + /* Locale matching */ + int32_t(HERMES_ICU_CDECL *uloc_acceptLanguage)( + char *result, + int32_t resultAvailable, + UAcceptResult *outResult, + const char **acceptList, + int32_t acceptListCount, + UEnumeration *availableLocales, + UErrorCode *err); + + /* Unicode locale key/type conversion */ + const char *(HERMES_ICU_CDECL *uloc_toUnicodeLocaleKey)(const char *keyword); + const char *(HERMES_ICU_CDECL *uloc_toUnicodeLocaleType)( + const char *keyword, + const char *value); + const char *(HERMES_ICU_CDECL *uloc_toLegacyKey)(const char *keyword); + const char *(HERMES_ICU_CDECL *uloc_toLegacyType)( + const char *keyword, + const char *value); + + /* Script direction */ + UBool(HERMES_ICU_CDECL *uloc_isRightToLeft)(const char *locale); + + /* =============================================================== + * 2.3.2 Collator (ucol_*) — 15 functions + * =============================================================== */ + + UCollator *(HERMES_ICU_CDECL *ucol_open)( + const char *loc, + UErrorCode *status); + void(HERMES_ICU_CDECL *ucol_close)(UCollator *coll); + UCollationResult(HERMES_ICU_CDECL *ucol_strcoll)( + const UCollator *coll, + const UChar *source, + int32_t sourceLength, + const UChar *target, + int32_t targetLength); + UCollationResult(HERMES_ICU_CDECL *ucol_strcollUTF8)( + const UCollator *coll, + const char *source, + int32_t sourceLength, + const char *target, + int32_t targetLength, + UErrorCode *status); + void(HERMES_ICU_CDECL *ucol_setAttribute)( + UCollator *coll, + UColAttribute attr, + UColAttributeValue value, + UErrorCode *status); + UColAttributeValue(HERMES_ICU_CDECL *ucol_getAttribute)( + const UCollator *coll, + UColAttribute attr, + UErrorCode *status); + void(HERMES_ICU_CDECL *ucol_setStrength)( + UCollator *coll, + UCollationStrength strength); + const char *(HERMES_ICU_CDECL *ucol_getLocaleByType)( + const UCollator *coll, + ULocDataLocaleType type, + UErrorCode *status); + UEnumeration *(HERMES_ICU_CDECL *ucol_openAvailableLocales)( + UErrorCode *status); + UEnumeration *(HERMES_ICU_CDECL *ucol_getKeywordValuesForLocale)( + const char *key, + const char *locale, + UBool commonlyUsed, + UErrorCode *status); + UEnumeration *(HERMES_ICU_CDECL *ucol_getKeywordValues)( + const char *keyword, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *ucol_getReorderCodes)( + const UCollator *coll, + int32_t *dest, + int32_t destCapacity, + UErrorCode *status); + const UChar *(HERMES_ICU_CDECL *ucol_getRules)( + const UCollator *coll, + int32_t *length); + USet *(HERMES_ICU_CDECL *ucol_getTailoredSet)( + const UCollator *coll, + UErrorCode *status); + UCollator *(HERMES_ICU_CDECL *ucol_clone)( + const UCollator *coll, + UErrorCode *status); + + /* =============================================================== + * 2.3.3 NumberFormatter v2 (unumf_*) — 13 functions + * =============================================================== */ + + UNumberFormatter *(HERMES_ICU_CDECL *unumf_openForSkeletonAndLocale)( + const UChar *skeleton, + int32_t skeletonLen, + const char *locale, + UErrorCode *ec); + UNumberFormatter *( + HERMES_ICU_CDECL *unumf_openForSkeletonAndLocaleWithError)( + const UChar *skeleton, + int32_t skeletonLen, + const char *locale, + UParseError *perror, + UErrorCode *ec); + UFormattedNumber *(HERMES_ICU_CDECL *unumf_openResult)(UErrorCode *ec); + void(HERMES_ICU_CDECL *unumf_formatDouble)( + const UNumberFormatter *uformatter, + double value, + UFormattedNumber *uresult, + UErrorCode *ec); + void(HERMES_ICU_CDECL *unumf_formatInt)( + const UNumberFormatter *uformatter, + int64_t value, + UFormattedNumber *uresult, + UErrorCode *ec); + void(HERMES_ICU_CDECL *unumf_formatDecimal)( + const UNumberFormatter *uformatter, + const char *value, + int32_t valueLen, + UFormattedNumber *uresult, + UErrorCode *ec); + int32_t(HERMES_ICU_CDECL *unumf_resultToString)( + const UFormattedNumber *uresult, + UChar *buffer, + int32_t bufferCapacity, + UErrorCode *ec); + int32_t(HERMES_ICU_CDECL *unumf_resultToDecimalNumber)( + const UFormattedNumber *uresult, + char *dest, + int32_t destCapacity, + UErrorCode *ec); + const UFormattedValue *(HERMES_ICU_CDECL *unumf_resultAsValue)( + const UFormattedNumber *uresult, + UErrorCode *ec); + void(HERMES_ICU_CDECL *unumf_resultGetAllFieldPositions)( + const UFormattedNumber *uresult, + UFieldPositionIterator *fpositer, + UErrorCode *ec); + UBool(HERMES_ICU_CDECL *unumf_resultNextFieldPosition)( + const UFormattedNumber *uresult, + UFieldPosition *ufpos, + UErrorCode *ec); + void(HERMES_ICU_CDECL *unumf_close)(UNumberFormatter *uformatter); + void(HERMES_ICU_CDECL *unumf_closeResult)(UFormattedNumber *uresult); + + /* =============================================================== + * 2.3.4 NumberRangeFormatter (unumrf_*) — 7 functions + * =============================================================== */ + + UNumberRangeFormatter *( + HERMES_ICU_CDECL + *unumrf_openForSkeletonWithCollapseAndIdentityFallback)( + const UChar *skeleton, + int32_t skeletonLen, + UNumberRangeCollapse collapse, + UNumberRangeIdentityFallback identityFallback, + const char *locale, + UParseError *perror, + UErrorCode *ec); + UFormattedNumberRange *(HERMES_ICU_CDECL *unumrf_openResult)( + UErrorCode *ec); + void(HERMES_ICU_CDECL *unumrf_formatDoubleRange)( + const UNumberRangeFormatter *uformatter, + double first, + double second, + UFormattedNumberRange *uresult, + UErrorCode *ec); + void(HERMES_ICU_CDECL *unumrf_formatDecimalRange)( + const UNumberRangeFormatter *uformatter, + const char *first, + int32_t firstLen, + const char *second, + int32_t secondLen, + UFormattedNumberRange *uresult, + UErrorCode *ec); + const UFormattedValue *(HERMES_ICU_CDECL *unumrf_resultAsValue)( + const UFormattedNumberRange *uresult, + UErrorCode *ec); + void(HERMES_ICU_CDECL *unumrf_close)(UNumberRangeFormatter *uformatter); + void(HERMES_ICU_CDECL *unumrf_closeResult)( + UFormattedNumberRange *uresult); + + /* =============================================================== + * 2.3.5 Legacy NumberFormat (unum_*) — 6 functions + * =============================================================== */ + + UNumberFormat *(HERMES_ICU_CDECL *unum_open)( + UNumberFormatStyle style, + const UChar *pattern, + int32_t patternLength, + const char *locale, + UParseError *parseErr, + UErrorCode *status); + void(HERMES_ICU_CDECL *unum_close)(UNumberFormat *fmt); + int32_t(HERMES_ICU_CDECL *unum_formatDouble)( + const UNumberFormat *fmt, + double number, + UChar *result, + int32_t resultLength, + UFieldPosition *pos, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *unum_format)( + const UNumberFormat *fmt, + int32_t number, + UChar *result, + int32_t resultLength, + UFieldPosition *pos, + UErrorCode *status); + void(HERMES_ICU_CDECL *unum_setAttribute)( + UNumberFormat *fmt, + UNumberFormatAttribute attr, + int32_t newValue); + int32_t(HERMES_ICU_CDECL *unum_getAttribute)( + const UNumberFormat *fmt, + UNumberFormatAttribute attr); + void(HERMES_ICU_CDECL *unum_setTextAttribute)( + UNumberFormat *fmt, + UNumberFormatTextAttribute tag, + const UChar *newValue, + int32_t newValueLength, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *unum_formatDoubleForFields)( + const UNumberFormat *fmt, + double number, + UChar *result, + int32_t resultLength, + UFieldPositionIterator *fpositer, + UErrorCode *status); + + /* =============================================================== + * 2.3.6 DateFormat (udat_*) — 18 functions + * =============================================================== */ + + UDateFormat *(HERMES_ICU_CDECL *udat_open)( + UDateFormatStyle timeStyle, + UDateFormatStyle dateStyle, + const char *locale, + const UChar *tzID, + int32_t tzIDLength, + const UChar *pattern, + int32_t patternLength, + UErrorCode *status); + void(HERMES_ICU_CDECL *udat_close)(UDateFormat *format); + int32_t(HERMES_ICU_CDECL *udat_format)( + const UDateFormat *format, + UDate dateToFormat, + UChar *result, + int32_t resultLength, + UFieldPosition *position, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *udat_formatForFields)( + const UDateFormat *format, + UDate dateToFormat, + UChar *result, + int32_t resultLength, + UFieldPositionIterator *fpositer, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *udat_formatCalendarForFields)( + const UDateFormat *format, + UCalendar *calendar, + UChar *result, + int32_t capacity, + UFieldPositionIterator *fpositer, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *udat_toPattern)( + const UDateFormat *fmt, + UBool localized, + UChar *result, + int32_t resultLength, + UErrorCode *status); + void(HERMES_ICU_CDECL *udat_applyPattern)( + UDateFormat *format, + UBool localized, + const UChar *pattern, + int32_t patternLength); + const UCalendar *(HERMES_ICU_CDECL *udat_getCalendar)( + const UDateFormat *fmt); + void(HERMES_ICU_CDECL *udat_setCalendar)( + UDateFormat *fmt, + const UCalendar *calendarToSet); + const UNumberFormat *(HERMES_ICU_CDECL *udat_getNumberFormat)( + const UDateFormat *fmt); + void(HERMES_ICU_CDECL *udat_adoptNumberFormat)( + UDateFormat *fmt, + UNumberFormat *numberFormatToAdopt); + int32_t(HERMES_ICU_CDECL *udat_getSymbols)( + const UDateFormat *fmt, + UDateFormatSymbolType type, + int32_t symbolIndex, + UChar *result, + int32_t resultLength, + UErrorCode *status); + const char *(HERMES_ICU_CDECL *udat_getLocaleByType)( + const UDateFormat *fmt, + ULocDataLocaleType type, + UErrorCode *status); + UBool(HERMES_ICU_CDECL *udat_getBooleanAttribute)( + const UDateFormat *fmt, + UDateFormatBooleanAttribute attr, + UErrorCode *status); + void(HERMES_ICU_CDECL *udat_setBooleanAttribute)( + UDateFormat *fmt, + UDateFormatBooleanAttribute attr, + UBool newValue, + UErrorCode *status); + void(HERMES_ICU_CDECL *udat_setContext)( + UDateFormat *fmt, + UDisplayContext value, + UErrorCode *status); + UDisplayContext(HERMES_ICU_CDECL *udat_getContext)( + const UDateFormat *fmt, + UDisplayContextType type, + UErrorCode *status); + UDateFormat *(HERMES_ICU_CDECL *udat_clone)( + const UDateFormat *fmt, + UErrorCode *status); + + /* =============================================================== + * 2.3.7 DateTimePatternGenerator (udatpg_*) — 10 functions + * =============================================================== */ + + UDateTimePatternGenerator *(HERMES_ICU_CDECL *udatpg_open)( + const char *locale, + UErrorCode *pErrorCode); + void(HERMES_ICU_CDECL *udatpg_close)(UDateTimePatternGenerator *dtpg); + int32_t(HERMES_ICU_CDECL *udatpg_getBestPattern)( + UDateTimePatternGenerator *dtpg, + const UChar *skeleton, + int32_t length, + UChar *bestPattern, + int32_t capacity, + UErrorCode *pErrorCode); + int32_t(HERMES_ICU_CDECL *udatpg_getBestPatternWithOptions)( + UDateTimePatternGenerator *dtpg, + const UChar *skeleton, + int32_t length, + UDateTimePatternMatchOptions options, + UChar *bestPattern, + int32_t capacity, + UErrorCode *pErrorCode); + UDateFormatHourCycle(HERMES_ICU_CDECL *udatpg_getDefaultHourCycle)( + const UDateTimePatternGenerator *dtpg, + UErrorCode *pErrorCode); + int32_t(HERMES_ICU_CDECL *udatpg_getSkeleton)( + UDateTimePatternGenerator *unusedDtpg, + const UChar *pattern, + int32_t length, + UChar *skeleton, + int32_t capacity, + UErrorCode *pErrorCode); + int32_t(HERMES_ICU_CDECL *udatpg_getBaseSkeleton)( + UDateTimePatternGenerator *unusedDtpg, + const UChar *pattern, + int32_t length, + UChar *baseSkeleton, + int32_t capacity, + UErrorCode *pErrorCode); + const UChar *(HERMES_ICU_CDECL *udatpg_getPatternForSkeleton)( + const UDateTimePatternGenerator *dtpg, + const UChar *skeleton, + int32_t skeletonLength, + int32_t *pLength); + int32_t(HERMES_ICU_CDECL *udatpg_getFieldDisplayName)( + const UDateTimePatternGenerator *dtpg, + UDateTimePatternField field, + UDateTimePGDisplayWidth width, + UChar *fieldName, + int32_t capacity, + UErrorCode *pErrorCode); + UDateTimePatternGenerator *(HERMES_ICU_CDECL *udatpg_clone)( + const UDateTimePatternGenerator *dtpg, + UErrorCode *pErrorCode); + + /* =============================================================== + * 2.3.8 DateIntervalFormat (udtitvfmt_*) — 7 functions + * =============================================================== */ + + UDateIntervalFormat *(HERMES_ICU_CDECL *udtitvfmt_open)( + const char *locale, + const UChar *skeleton, + int32_t skeletonLength, + const UChar *tzID, + int32_t tzIDLength, + UErrorCode *status); + void(HERMES_ICU_CDECL *udtitvfmt_close)(UDateIntervalFormat *formatter); + UFormattedDateInterval *(HERMES_ICU_CDECL *udtitvfmt_openResult)( + UErrorCode *ec); + void(HERMES_ICU_CDECL *udtitvfmt_closeResult)( + UFormattedDateInterval *uresult); + void(HERMES_ICU_CDECL *udtitvfmt_formatToResult)( + const UDateIntervalFormat *formatter, + UDate fromDate, + UDate toDate, + UFormattedDateInterval *result, + UErrorCode *status); + const UFormattedValue *(HERMES_ICU_CDECL *udtitvfmt_resultAsValue)( + const UFormattedDateInterval *uresult, + UErrorCode *ec); + int32_t(HERMES_ICU_CDECL *udtitvfmt_format)( + const UDateIntervalFormat *formatter, + UDate fromDate, + UDate toDate, + UChar *result, + int32_t resultCapacity, + UFieldPosition *position, + UErrorCode *status); + + /* =============================================================== + * 2.3.9 Calendar/Timezone (ucal_*) — 35 functions + * =============================================================== */ + + UCalendar *(HERMES_ICU_CDECL *ucal_open)( + const UChar *zoneID, + int32_t len, + const char *locale, + UCalendarType type, + UErrorCode *status); + void(HERMES_ICU_CDECL *ucal_close)(UCalendar *cal); + UCalendar *(HERMES_ICU_CDECL *ucal_clone)( + const UCalendar *cal, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *ucal_get)( + const UCalendar *cal, + UCalendarDateFields field, + UErrorCode *status); + void(HERMES_ICU_CDECL *ucal_set)( + UCalendar *cal, + UCalendarDateFields field, + int32_t value); + UDate(HERMES_ICU_CDECL *ucal_getMillis)( + const UCalendar *cal, + UErrorCode *status); + void(HERMES_ICU_CDECL *ucal_setMillis)( + UCalendar *cal, + UDate dateTime, + UErrorCode *status); + void(HERMES_ICU_CDECL *ucal_setAttribute)( + UCalendar *cal, + UCalendarAttribute attr, + int32_t newValue); + int32_t(HERMES_ICU_CDECL *ucal_getAttribute)( + const UCalendar *cal, + UCalendarAttribute attr); + + /* Timezone operations */ + int32_t(HERMES_ICU_CDECL *ucal_getDefaultTimeZone)( + UChar *result, + int32_t resultCapacity, + UErrorCode *ec); + int32_t(HERMES_ICU_CDECL *ucal_getCanonicalTimeZoneID)( + const UChar *id, + int32_t len, + UChar *result, + int32_t resultCapacity, + UBool *isSystemID, + UErrorCode *ec); + int32_t(HERMES_ICU_CDECL *ucal_getTimeZoneDisplayName)( + const UCalendar *cal, + UCalendarDisplayNameType type, + const char *locale, + UChar *result, + int32_t resultLength, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *ucal_getTimeZoneID)( + const UCalendar *cal, + UChar *result, + int32_t resultLength, + UErrorCode *status); + void(HERMES_ICU_CDECL *ucal_setTimeZone)( + UCalendar *cal, + const UChar *zoneID, + int32_t len, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *ucal_getTimeZoneIDForWindowsID)( + const UChar *winid, + int32_t len, + const char *region, + UChar *id, + int32_t idCapacity, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *ucal_getWindowsTimeZoneID)( + const UChar *id, + int32_t len, + UChar *winid, + int32_t winidCapacity, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *ucal_getHostTimeZone)( + UChar *result, + int32_t resultCapacity, + UErrorCode *ec); + UBool(HERMES_ICU_CDECL *ucal_getTimeZoneTransitionDate)( + const UCalendar *cal, + UTimeZoneTransitionType type, + UDate *transition, + UErrorCode *status); + void(HERMES_ICU_CDECL *ucal_getTimeZoneOffsetFromLocal)( + const UCalendar *cal, + UTimeZoneLocalOption nonExistingTimeOpt, + UTimeZoneLocalOption duplicatedTimeOpt, + int32_t *rawOffset, + int32_t *dstOffset, + UErrorCode *status); + + /* Enumerations */ + UEnumeration *(HERMES_ICU_CDECL *ucal_openTimeZones)(UErrorCode *ec); + UEnumeration *(HERMES_ICU_CDECL *ucal_openTimeZoneIDEnumeration)( + USystemTimeZoneType zoneType, + const char *region, + const int32_t *rawOffset, + UErrorCode *ec); + UEnumeration *(HERMES_ICU_CDECL *ucal_openCountryTimeZones)( + const char *country, + UErrorCode *ec); + UEnumeration *(HERMES_ICU_CDECL *ucal_getKeywordValuesForLocale)( + const char *key, + const char *locale, + UBool commonlyUsed, + UErrorCode *status); + + /* Calendar properties */ + int32_t(HERMES_ICU_CDECL *ucal_countAvailable)(void); + const char *(HERMES_ICU_CDECL *ucal_getAvailable)(int32_t localeIndex); + const char *(HERMES_ICU_CDECL *ucal_getType)( + const UCalendar *cal, + UErrorCode *status); + UCalendarWeekdayType(HERMES_ICU_CDECL *ucal_getDayOfWeekType)( + const UCalendar *cal, + UCalendarDaysOfWeek dayOfWeek, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *ucal_getWeekendTransition)( + const UCalendar *cal, + UCalendarDaysOfWeek dayOfWeek, + UErrorCode *status); + UBool(HERMES_ICU_CDECL *ucal_isWeekend)( + const UCalendar *cal, + UDate date, + UErrorCode *status); + UBool(HERMES_ICU_CDECL *ucal_inDaylightTime)( + const UCalendar *cal, + UErrorCode *status); + UDate(HERMES_ICU_CDECL *ucal_getNow)(void); + int32_t(HERMES_ICU_CDECL *ucal_getFieldDifference)( + UCalendar *cal, + UDate target, + UCalendarDateFields field, + UErrorCode *status); + void(HERMES_ICU_CDECL *ucal_setGregorianChange)( + UCalendar *cal, + UDate date, + UErrorCode *pErrorCode); + UDate(HERMES_ICU_CDECL *ucal_getGregorianChange)( + const UCalendar *cal, + UErrorCode *pErrorCode); + void(HERMES_ICU_CDECL *ucal_setDefaultTimeZone)( + const UChar *zoneID, + UErrorCode *ec); + + /* =============================================================== + * 2.3.10 PluralRules (uplrules_*) — 7 functions + * =============================================================== */ + + UPluralRules *(HERMES_ICU_CDECL *uplrules_open)( + const char *locale, + UErrorCode *status); + UPluralRules *(HERMES_ICU_CDECL *uplrules_openForType)( + const char *locale, + UPluralType type, + UErrorCode *status); + void(HERMES_ICU_CDECL *uplrules_close)(UPluralRules *uplrules); + int32_t(HERMES_ICU_CDECL *uplrules_select)( + const UPluralRules *uplrules, + double number, + UChar *keyword, + int32_t capacity, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *uplrules_selectFormatted)( + const UPluralRules *uplrules, + const UFormattedNumber *number, + UChar *keyword, + int32_t capacity, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *uplrules_selectForRange)( + const UPluralRules *uplrules, + const UFormattedNumberRange *urange, + UChar *keyword, + int32_t capacity, + UErrorCode *status); + UEnumeration *(HERMES_ICU_CDECL *uplrules_getKeywords)( + const UPluralRules *uplrules, + UErrorCode *status); + + /* =============================================================== + * 2.3.11 ListFormatter (ulistfmt_*) — 8 functions + * =============================================================== */ + + UListFormatter *(HERMES_ICU_CDECL *ulistfmt_open)( + const char *locale, + UErrorCode *status); + UListFormatter *(HERMES_ICU_CDECL *ulistfmt_openForType)( + const char *locale, + UListFormatterType type, + UListFormatterWidth width, + UErrorCode *status); + void(HERMES_ICU_CDECL *ulistfmt_close)(UListFormatter *listfmt); + UFormattedList *(HERMES_ICU_CDECL *ulistfmt_openResult)(UErrorCode *ec); + void(HERMES_ICU_CDECL *ulistfmt_closeResult)(UFormattedList *uresult); + int32_t(HERMES_ICU_CDECL *ulistfmt_format)( + const UListFormatter *listfmt, + const UChar *const strings[], + const int32_t *stringLengths, + int32_t stringCount, + UChar *result, + int32_t resultCapacity, + UErrorCode *status); + void(HERMES_ICU_CDECL *ulistfmt_formatStringsToResult)( + const UListFormatter *listfmt, + const UChar *const strings[], + const int32_t *stringLengths, + int32_t stringCount, + UFormattedList *uresult, + UErrorCode *status); + const UFormattedValue *(HERMES_ICU_CDECL *ulistfmt_resultAsValue)( + const UFormattedList *uresult, + UErrorCode *ec); + + /* =============================================================== + * 2.3.12 BreakIterator (ubrk_*) — 22 functions + * =============================================================== */ + + UBreakIterator *(HERMES_ICU_CDECL *ubrk_open)( + UBreakIteratorType type, + const char *locale, + const UChar *text, + int32_t textLength, + UErrorCode *status); + void(HERMES_ICU_CDECL *ubrk_close)(UBreakIterator *bi); + UBreakIterator *(HERMES_ICU_CDECL *ubrk_clone)( + const UBreakIterator *bi, + UErrorCode *status); + void(HERMES_ICU_CDECL *ubrk_setText)( + UBreakIterator *bi, + const UChar *text, + int32_t textLength, + UErrorCode *status); + void(HERMES_ICU_CDECL *ubrk_setUText)( + UBreakIterator *bi, + UText *text, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *ubrk_current)(const UBreakIterator *bi); + int32_t(HERMES_ICU_CDECL *ubrk_next)(UBreakIterator *bi); + int32_t(HERMES_ICU_CDECL *ubrk_previous)(UBreakIterator *bi); + int32_t(HERMES_ICU_CDECL *ubrk_first)(UBreakIterator *bi); + int32_t(HERMES_ICU_CDECL *ubrk_last)(UBreakIterator *bi); + int32_t(HERMES_ICU_CDECL *ubrk_preceding)( + UBreakIterator *bi, + int32_t offset); + int32_t(HERMES_ICU_CDECL *ubrk_following)( + UBreakIterator *bi, + int32_t offset); + UBool(HERMES_ICU_CDECL *ubrk_isBoundary)( + UBreakIterator *bi, + int32_t offset); + int32_t(HERMES_ICU_CDECL *ubrk_getRuleStatus)(UBreakIterator *bi); + int32_t(HERMES_ICU_CDECL *ubrk_getRuleStatusVec)( + UBreakIterator *bi, + int32_t *fillInVec, + int32_t capacity, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *ubrk_countAvailable)(void); + const char *(HERMES_ICU_CDECL *ubrk_getAvailable)(int32_t index); + const char *(HERMES_ICU_CDECL *ubrk_getLocaleByType)( + const UBreakIterator *bi, + ULocDataLocaleType type, + UErrorCode *status); + UBreakIterator *(HERMES_ICU_CDECL *ubrk_openRules)( + const UChar *rules, + int32_t rulesLength, + const UChar *text, + int32_t textLength, + UParseError *parseErr, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *ubrk_getBinaryRules)( + UBreakIterator *bi, + uint8_t *binaryRules, + int32_t rulesCapacity, + UErrorCode *status); + UBreakIterator *(HERMES_ICU_CDECL *ubrk_openBinaryRules)( + const uint8_t *binaryRules, + int32_t rulesLength, + const UChar *text, + int32_t textLength, + UErrorCode *status); + void(HERMES_ICU_CDECL *ubrk_refreshUText)( + UBreakIterator *bi, + UText *text, + UErrorCode *status); + + /* =============================================================== + * 2.3.13 RelativeDateTimeFormatter (ureldatefmt_*) — 10 functions + * =============================================================== */ + + URelativeDateTimeFormatter *(HERMES_ICU_CDECL *ureldatefmt_open)( + const char *locale, + UNumberFormat *nfToAdopt, + UDateRelativeDateTimeFormatterStyle width, + UDisplayContext capitalizationContext, + UErrorCode *status); + void(HERMES_ICU_CDECL *ureldatefmt_close)( + URelativeDateTimeFormatter *reldatefmt); + UFormattedRelativeDateTime *(HERMES_ICU_CDECL *ureldatefmt_openResult)( + UErrorCode *ec); + void(HERMES_ICU_CDECL *ureldatefmt_closeResult)( + UFormattedRelativeDateTime *ufrdt); + int32_t(HERMES_ICU_CDECL *ureldatefmt_format)( + const URelativeDateTimeFormatter *reldatefmt, + double offset, + URelativeDateTimeUnit unit, + UChar *result, + int32_t resultCapacity, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *ureldatefmt_formatNumeric)( + const URelativeDateTimeFormatter *reldatefmt, + double offset, + URelativeDateTimeUnit unit, + UChar *result, + int32_t resultCapacity, + UErrorCode *status); + void(HERMES_ICU_CDECL *ureldatefmt_formatToResult)( + const URelativeDateTimeFormatter *reldatefmt, + double offset, + URelativeDateTimeUnit unit, + UFormattedRelativeDateTime *result, + UErrorCode *status); + void(HERMES_ICU_CDECL *ureldatefmt_formatNumericToResult)( + const URelativeDateTimeFormatter *reldatefmt, + double offset, + URelativeDateTimeUnit unit, + UFormattedRelativeDateTime *result, + UErrorCode *status); + const UFormattedValue *(HERMES_ICU_CDECL *ureldatefmt_resultAsValue)( + const UFormattedRelativeDateTime *ufrdt, + UErrorCode *ec); + int32_t(HERMES_ICU_CDECL *ureldatefmt_combineDateAndTime)( + const URelativeDateTimeFormatter *reldatefmt, + const UChar *relativeDateString, + int32_t relativeDateStringLen, + const UChar *timeString, + int32_t timeStringLen, + UChar *result, + int32_t resultCapacity, + UErrorCode *status); + + /* =============================================================== + * 2.3.14 DisplayNames (uldn_*) — 10 functions + * =============================================================== */ + + ULocaleDisplayNames *(HERMES_ICU_CDECL *uldn_open)( + const char *locale, + UDialectHandling dialectHandling, + UErrorCode *pErrorCode); + ULocaleDisplayNames *(HERMES_ICU_CDECL *uldn_openForContext)( + const char *locale, + UDisplayContext *contexts, + int32_t length, + UErrorCode *pErrorCode); + void(HERMES_ICU_CDECL *uldn_close)(ULocaleDisplayNames *ldn); + const char *(HERMES_ICU_CDECL *uldn_getLocale)( + const ULocaleDisplayNames *ldn); + UDisplayContext(HERMES_ICU_CDECL *uldn_getContext)( + const ULocaleDisplayNames *ldn, + UDisplayContextType type, + UErrorCode *pErrorCode); + int32_t(HERMES_ICU_CDECL *uldn_localeDisplayName)( + const ULocaleDisplayNames *ldn, + const char *locale, + UChar *result, + int32_t maxResultSize, + UErrorCode *pErrorCode); + int32_t(HERMES_ICU_CDECL *uldn_languageDisplayName)( + const ULocaleDisplayNames *ldn, + const char *lang, + UChar *result, + int32_t maxResultSize, + UErrorCode *pErrorCode); + int32_t(HERMES_ICU_CDECL *uldn_regionDisplayName)( + const ULocaleDisplayNames *ldn, + const char *region, + UChar *result, + int32_t maxResultSize, + UErrorCode *pErrorCode); + int32_t(HERMES_ICU_CDECL *uldn_scriptDisplayName)( + const ULocaleDisplayNames *ldn, + const char *script, + UChar *result, + int32_t maxResultSize, + UErrorCode *pErrorCode); + int32_t(HERMES_ICU_CDECL *uldn_keyValueDisplayName)( + const ULocaleDisplayNames *ldn, + const char *key, + const char *value, + UChar *result, + int32_t maxResultSize, + UErrorCode *pErrorCode); + + /* =============================================================== + * 2.3.15 NumberingSystem (unumsys_*) — 8 functions + * =============================================================== */ + + UNumberingSystem *(HERMES_ICU_CDECL *unumsys_open)( + const char *locale, + UErrorCode *status); + UNumberingSystem *(HERMES_ICU_CDECL *unumsys_openByName)( + const char *name, + UErrorCode *status); + void(HERMES_ICU_CDECL *unumsys_close)(UNumberingSystem *unumsys); + const char *(HERMES_ICU_CDECL *unumsys_getName)( + const UNumberingSystem *unumsys); + int32_t(HERMES_ICU_CDECL *unumsys_getDescription)( + const UNumberingSystem *unumsys, + UChar *result, + int32_t resultLength, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *unumsys_getRadix)( + const UNumberingSystem *unumsys); + UBool(HERMES_ICU_CDECL *unumsys_isAlgorithmic)( + const UNumberingSystem *unumsys); + UEnumeration *(HERMES_ICU_CDECL *unumsys_openAvailableNames)( + UErrorCode *status); + + /* =============================================================== + * 2.3.16 Currency (ucurr_*) — 4 functions + * =============================================================== */ + + int32_t(HERMES_ICU_CDECL *ucurr_forLocale)( + const char *locale, + UChar *buff, + int32_t buffCapacity, + UErrorCode *ec); + int32_t(HERMES_ICU_CDECL *ucurr_getDefaultFractionDigits)( + const UChar *currency, + UErrorCode *ec); + const UChar *(HERMES_ICU_CDECL *ucurr_getName)( + const UChar *currency, + const char *locale, + UCurrNameStyle nameStyle, + UBool *isChoiceFormat, + int32_t *len, + UErrorCode *ec); + UEnumeration *(HERMES_ICU_CDECL *ucurr_openISOCurrencies)( + uint32_t currType, + UErrorCode *ec); + + /* =============================================================== + * 2.3.17 FormattedValue / ConstrainedFieldPosition — 14 functions + * =============================================================== */ + + UConstrainedFieldPosition *(HERMES_ICU_CDECL *ucfpos_open)(UErrorCode *ec); + void(HERMES_ICU_CDECL *ucfpos_close)(UConstrainedFieldPosition *ucfpos); + void(HERMES_ICU_CDECL *ucfpos_reset)( + UConstrainedFieldPosition *ucfpos, + UErrorCode *ec); + void(HERMES_ICU_CDECL *ucfpos_constrainCategory)( + UConstrainedFieldPosition *ucfpos, + int32_t category, + UErrorCode *ec); + void(HERMES_ICU_CDECL *ucfpos_constrainField)( + UConstrainedFieldPosition *ucfpos, + int32_t category, + int32_t field, + UErrorCode *ec); + int32_t(HERMES_ICU_CDECL *ucfpos_getCategory)( + const UConstrainedFieldPosition *ucfpos, + UErrorCode *ec); + int32_t(HERMES_ICU_CDECL *ucfpos_getField)( + const UConstrainedFieldPosition *ucfpos, + UErrorCode *ec); + void(HERMES_ICU_CDECL *ucfpos_getIndexes)( + const UConstrainedFieldPosition *ucfpos, + int32_t *pStart, + int32_t *pLimit, + UErrorCode *ec); + int64_t(HERMES_ICU_CDECL *ucfpos_getInt64IterationContext)( + const UConstrainedFieldPosition *ucfpos, + UErrorCode *ec); + void(HERMES_ICU_CDECL *ucfpos_setInt64IterationContext)( + UConstrainedFieldPosition *ucfpos, + int64_t context, + UErrorCode *ec); + UBool(HERMES_ICU_CDECL *ucfpos_matchesField)( + const UConstrainedFieldPosition *ucfpos, + int32_t category, + int32_t field, + UErrorCode *ec); + void(HERMES_ICU_CDECL *ucfpos_setState)( + UConstrainedFieldPosition *ucfpos, + int32_t category, + int32_t field, + int32_t start, + int32_t limit, + UErrorCode *ec); + + const UChar *(HERMES_ICU_CDECL *ufmtval_getString)( + const UFormattedValue *ufmtval, + int32_t *pLength, + UErrorCode *ec); + UBool(HERMES_ICU_CDECL *ufmtval_nextPosition)( + const UFormattedValue *ufmtval, + UConstrainedFieldPosition *ucfpos, + UErrorCode *ec); + + /* =============================================================== + * 2.3.18 Legacy FieldPositionIterator — 3 functions + * =============================================================== */ + + UFieldPositionIterator *(HERMES_ICU_CDECL *ufieldpositer_open)( + UErrorCode *status); + void(HERMES_ICU_CDECL *ufieldpositer_close)( + UFieldPositionIterator *fpositer); + int32_t(HERMES_ICU_CDECL *ufieldpositer_next)( + UFieldPositionIterator *fpositer, + int32_t *beginIndex, + int32_t *endIndex); + + /* =============================================================== + * 2.3.19 Enumeration (uenum_*) — 4 functions + * =============================================================== */ + + void(HERMES_ICU_CDECL *uenum_close)(UEnumeration *en); + const UChar *(HERMES_ICU_CDECL *uenum_unext)( + UEnumeration *en, + int32_t *resultLength, + UErrorCode *status); + const char *(HERMES_ICU_CDECL *uenum_next)( + UEnumeration *en, + int32_t *resultLength, + UErrorCode *status); + int32_t(HERMES_ICU_CDECL *uenum_count)( + UEnumeration *en, + UErrorCode *status); + + /* =============================================================== + * 2.3.20 String Utilities — 9 functions + * =============================================================== */ + + int32_t(HERMES_ICU_CDECL *u_strToLower)( + UChar *dest, + int32_t destCapacity, + const UChar *src, + int32_t srcLength, + const char *locale, + UErrorCode *pErrorCode); + int32_t(HERMES_ICU_CDECL *u_strToUpper)( + UChar *dest, + int32_t destCapacity, + const UChar *src, + int32_t srcLength, + const char *locale, + UErrorCode *pErrorCode); + int32_t(HERMES_ICU_CDECL *u_strToTitle)( + UChar *dest, + int32_t destCapacity, + const UChar *src, + int32_t srcLength, + UBreakIterator *titleIter, + const char *locale, + UErrorCode *pErrorCode); + int32_t(HERMES_ICU_CDECL *u_strFoldCase)( + UChar *dest, + int32_t destCapacity, + const UChar *src, + int32_t srcLength, + uint32_t options, + UErrorCode *pErrorCode); + int32_t(HERMES_ICU_CDECL *u_strcmp)(const UChar *s1, const UChar *s2); + void(HERMES_ICU_CDECL *u_getVersion)(UVersionInfo versionArray); + const char *(HERMES_ICU_CDECL *u_errorName)(UErrorCode code); + void(HERMES_ICU_CDECL *u_init)(UErrorCode *status); + void(HERMES_ICU_CDECL *u_cleanup)(void); + + /* =============================================================== + * 2.3.21 Normalization (unorm2_*) — 10 functions + * =============================================================== */ + + const UNormalizer2 *(HERMES_ICU_CDECL *unorm2_getInstance)( + const char *packageName, + const char *name, + UNormalization2Mode mode, + UErrorCode *pErrorCode); + const UNormalizer2 *(HERMES_ICU_CDECL *unorm2_getNFCInstance)( + UErrorCode *pErrorCode); + const UNormalizer2 *(HERMES_ICU_CDECL *unorm2_getNFDInstance)( + UErrorCode *pErrorCode); + const UNormalizer2 *(HERMES_ICU_CDECL *unorm2_getNFKCInstance)( + UErrorCode *pErrorCode); + const UNormalizer2 *(HERMES_ICU_CDECL *unorm2_getNFKDInstance)( + UErrorCode *pErrorCode); + int32_t(HERMES_ICU_CDECL *unorm2_normalize)( + const UNormalizer2 *norm2, + const UChar *src, + int32_t length, + UChar *dest, + int32_t capacity, + UErrorCode *pErrorCode); + int32_t(HERMES_ICU_CDECL *unorm2_normalizeSecondAndAppend)( + const UNormalizer2 *norm2, + UChar *first, + int32_t firstLength, + int32_t firstCapacity, + const UChar *second, + int32_t secondLength, + UErrorCode *pErrorCode); + UBool(HERMES_ICU_CDECL *unorm2_isNormalized)( + const UNormalizer2 *norm2, + const UChar *s, + int32_t length, + UErrorCode *pErrorCode); + UNormalizationCheckResult(HERMES_ICU_CDECL *unorm2_quickCheck)( + const UNormalizer2 *norm2, + const UChar *s, + int32_t length, + UErrorCode *pErrorCode); + int32_t(HERMES_ICU_CDECL *unorm2_spanQuickCheckYes)( + const UNormalizer2 *norm2, + const UChar *s, + int32_t length, + UErrorCode *pErrorCode); + + /* =============================================================== + * 2.3.22 Resource Bundle (ures_*) — 3 functions + * =============================================================== */ + + UResourceBundle *(HERMES_ICU_CDECL *ures_open)( + const char *packageName, + const char *locale, + UErrorCode *status); + void(HERMES_ICU_CDECL *ures_close)(UResourceBundle *resourceBundle); + UResourceBundle *(HERMES_ICU_CDECL *ures_getByKey)( + const UResourceBundle *resourceBundle, + const char *key, + UResourceBundle *fillIn, + UErrorCode *status); + + /* =============================================================== + * 2.3.23 USet — 5 functions + * =============================================================== */ + + USet *(HERMES_ICU_CDECL *uset_openEmpty)(void); + void(HERMES_ICU_CDECL *uset_close)(USet *set); + UBool(HERMES_ICU_CDECL *uset_contains)(const USet *set, UChar32 c); + int32_t(HERMES_ICU_CDECL *uset_getItem)( + const USet *set, + int32_t itemIndex, + UChar32 *start, + UChar32 *end, + UChar *str, + int32_t strCapacity, + UErrorCode *ec); + int32_t(HERMES_ICU_CDECL *uset_getItemCount)(const USet *set); + + /* =============================================================== + * 2.3.24 Custom shims — functions that require ICU C++ internals + * + * ICU's C API uloc_canonicalize() only performs basic locale ID + * canonicalization (a small static lookup table). Full CLDR alias + * resolution (languageAlias, scriptAlias, territoryAlias, + * subdivisionAlias, variantAlias, transformed-extension aliases) + * requires ICU C++ Locale::canonicalize() which uses AliasReplacer + * to read CLDR metadata resource bundles. These shims expose that + * C++ functionality through C function pointers. + * + * Providers that only have C API access (system-icu, dynamic) + * should set these to NULL; the caller will fall back to the + * 3-step C pipeline (uloc_forLanguageTag + uloc_canonicalize + + * uloc_toLanguageTag) which handles a subset of aliases. + * =============================================================== */ + + /** + * Full CLDR canonicalization of a BCP47 language tag. + * + * Equivalent to: + * Locale loc = Locale::forLanguageTag(langtag, err); + * loc.canonicalize(err); + * loc.toLanguageTag(result, err); + * + * @param langtag Input BCP47 language tag (UTF-8, null-terminated). + * @param result Output buffer for the canonicalized BCP47 tag. + * @param resultCapacity Size of the output buffer. + * @param err ICU error code (in/out). + * @return Length of the canonicalized tag (excluding null terminator), + * or required capacity if U_BUFFER_OVERFLOW_ERROR. + * + * May be NULL — callers must check before use. + */ + int32_t(HERMES_ICU_CDECL *canonicalize_locale_tag)( + const char *langtag, + char *result, + int32_t resultCapacity, + UErrorCode *err); +} hermes_icu_vtable; + +/** + * Function pointer type for the hermes-icu.dll entry point. + * Exported by hermes-icu.dll — returns the vtable struct. + */ +typedef const hermes_icu_vtable *( + HERMES_ICU_CDECL *hermes_icu_get_vtable_fn)(void); + +/** + * Set a host-provided ICU vtable. Must be called before any Hermes runtime + * is created. Hermes does NOT take ownership — the host must ensure the + * vtable remains valid for the lifetime of the process. + * + * Pass NULL to reset to the default (auto-detect) behavior. + */ +HERMES_ICU_API void HERMES_ICU_CDECL +hermes_icu_set_vtable(const hermes_icu_vtable *vt); + +/** + * Get the currently active ICU vtable (for inspection/testing). + * Returns NULL if no provider is active yet (lazy init hasn't happened). + */ +HERMES_ICU_API const hermes_icu_vtable *HERMES_ICU_CDECL +hermes_icu_get_active_vtable(void); + +#ifdef _WIN32 +/** + * Load ICU from unicode.org DLL files at the specified paths. + * Resolves versioned symbol names (e.g. "uloc_forLanguageTag_78"). + * If icu_version is 0, resolves unversioned names (for builds with + * U_DISABLE_RENAMING=1 or bundled hermes-icu.dll). + * + * Sets the loaded vtable as the active provider (calls + * hermes_icu_set_vtable internally). Must be called before any + * Hermes runtime is created. + * + * @param icu_common_dll_path Full path to icuucNN.dll (required). + * @param icu_i18n_dll_path Full path to icuinNN.dll (may be NULL if + * all needed functions are in the common DLL). + * @param icu_version ICU major version (e.g. 78), or 0 for + * unversioned names. + * @return 0 on success, non-zero on failure. + */ +HERMES_ICU_API int32_t HERMES_ICU_CDECL hermes_icu_load_from_path( + const wchar_t *icu_common_dll_path, + const wchar_t *icu_i18n_dll_path, + uint32_t icu_version); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* HERMES_ICU_H */ diff --git a/packages/windows-hermes/vendor/include/hermes/js_runtime_api.h b/packages/windows-hermes/vendor/include/hermes/js_runtime_api.h new file mode 100644 index 0000000..e2c8f4e --- /dev/null +++ b/packages/windows-hermes/vendor/include/hermes/js_runtime_api.h @@ -0,0 +1,232 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#ifndef SRC_JS_RUNTIME_API_H_ +#define SRC_JS_RUNTIME_API_H_ + +#include "node_api.h" + +// +// Node-API extensions required for JavaScript engine hosting. +// +// It is a very early version of the APIs which we consider to be experimental. +// These APIs are not stable yet and are subject to change while we continue +// their development. After some time we will stabilize the APIs and make them +// "officially stable". +// + +#define JSR_API NAPI_EXTERN napi_status NAPI_CDECL + +EXTERN_C_START + +typedef struct jsr_runtime_s *jsr_runtime; +typedef struct jsr_config_s *jsr_config; +typedef struct jsr_prepared_script_s *jsr_prepared_script; +typedef struct jsr_napi_env_scope_s *jsr_napi_env_scope; + +typedef void(NAPI_CDECL *jsr_data_delete_cb)(void *data, void *deleter_data); + +//============================================================================= +// jsr_runtime +//============================================================================= + +JSR_API jsr_create_runtime(jsr_config config, jsr_runtime *runtime); +JSR_API jsr_delete_runtime(jsr_runtime runtime); +JSR_API jsr_runtime_get_node_api_env(jsr_runtime runtime, napi_env *env); + +//============================================================================= +// jsr_config +//============================================================================= + +JSR_API jsr_create_config(jsr_config *config); +JSR_API jsr_delete_config(jsr_config config); + +JSR_API jsr_config_enable_inspector(jsr_config config, bool value); +JSR_API jsr_config_set_inspector_runtime_name( + jsr_config config, + const char *name); +JSR_API jsr_config_set_inspector_port(jsr_config config, uint16_t port); +JSR_API jsr_config_set_inspector_break_on_start(jsr_config config, bool value); + +JSR_API jsr_config_enable_gc_api(jsr_config config, bool value); + +JSR_API jsr_config_set_explicit_microtasks(jsr_config config, bool value); + +// A callback to process unhandled JS error +typedef void(NAPI_CDECL *jsr_unhandled_error_cb)( + void *cb_data, + napi_env env, + napi_value error); + +JSR_API jsr_config_on_unhandled_error( + jsr_config config, + void *cb_data, + jsr_unhandled_error_cb unhandled_error_cb); + +//============================================================================= +// jsr_config task runner +//============================================================================= + +// A callback to run task +typedef void(NAPI_CDECL *jsr_task_run_cb)(void *task_data); + +// A callback to post task to the task runner +typedef void(NAPI_CDECL *jsr_task_runner_post_task_cb)( + void *task_runner_data, + void *task_data, + jsr_task_run_cb task_run_cb, + jsr_data_delete_cb task_data_delete_cb, + void *deleter_data); + +JSR_API jsr_config_set_task_runner( + jsr_config config, + void *task_runner_data, + jsr_task_runner_post_task_cb task_runner_post_task_cb, + jsr_data_delete_cb task_runner_data_delete_cb, + void *deleter_data); + +//============================================================================= +// jsr_config script cache +//============================================================================= + +typedef void(NAPI_CDECL *jsr_script_cache_load_cb)( + void *script_cache_data, + const char *source_url, + uint64_t source_hash, + const char *runtime_name, + uint64_t runtime_version, + const char *cache_tag, + const uint8_t **buffer, + size_t *buffer_size, + jsr_data_delete_cb *buffer_delete_cb, + void **deleter_data); + +typedef void(NAPI_CDECL *jsr_script_cache_store_cb)( + void *script_cache_data, + const char *source_url, + uint64_t source_hash, + const char *runtime_name, + uint64_t runtime_version, + const char *cache_tag, + const uint8_t *buffer, + size_t buffer_size, + jsr_data_delete_cb buffer_delete_cb, + void *deleter_data); + +JSR_API jsr_config_set_script_cache( + jsr_config config, + void *script_cache_data, + jsr_script_cache_load_cb script_cache_load_cb, + jsr_script_cache_store_cb script_cache_store_cb, + jsr_data_delete_cb script_cache_data_delete_cb, + void *deleter_data); + +//============================================================================= +// napi_env scope +//============================================================================= + +// Opens the napi_env scope in the current thread. +// Calling Node-API functions without the opened scope may cause a failure. +// The scope must be closed by the jsr_close_napi_env_scope call. +JSR_API jsr_open_napi_env_scope(napi_env env, jsr_napi_env_scope *scope); + +// Closes the napi_env scope in the current thread. It must match to the +// jsr_open_napi_env_scope call. +JSR_API jsr_close_napi_env_scope(napi_env env, jsr_napi_env_scope scope); + +//============================================================================= +// Additional functions to implement JSI +//============================================================================= + +// To implement JSI description() +JSR_API jsr_get_description(napi_env env, const char **result); + +// To implement JSI queueMicrotask() +JSR_API jsr_queue_microtask(napi_env env, napi_value callback); + +// To implement JSI drainMicrotasks() +JSR_API +jsr_drain_microtasks(napi_env env, int32_t max_count_hint, bool *result); + +// To implement JSI isInspectable() +JSR_API jsr_is_inspectable(napi_env env, bool *result); + +//============================================================================= +// Script preparing and running. +// +// Script is usually converted to byte code, or in other words - prepared - for +// execution. Then, we can run the prepared script. +//============================================================================= + +// Run script with source URL. +JSR_API jsr_run_script( + napi_env env, + napi_value source, + const char *source_url, + napi_value *result); + +// Run script buffer. +JSR_API jsr_run_script_buffer( + napi_env env, + const uint8_t *script_data, + size_t script_length, + jsr_data_delete_cb script_delete_cb, + void *deleter_data, + const char *source_url, + napi_value *result); + +// Prepare the script for running. +JSR_API jsr_create_prepared_script( + napi_env env, + const uint8_t *script_data, + size_t script_length, + jsr_data_delete_cb script_delete_cb, + void *deleter_data, + const char *source_url, + jsr_prepared_script *result); + +// Delete the prepared script. +JSR_API jsr_delete_prepared_script( + napi_env env, + jsr_prepared_script prepared_script); + +// Run the prepared script. +JSR_API jsr_prepared_script_run( + napi_env env, + jsr_prepared_script prepared_script, + napi_value *result); + +//============================================================================= +// Functions to support unit tests. +//============================================================================= + +// Provides a hint to run garbage collection. +// It is typically used for unit tests. +// It requires enabling GC by calling jsr_config_enable_gc_api. +JSR_API jsr_collect_garbage(napi_env env); + +// Checks if the environment has an unhandled promise rejection. +JSR_API jsr_has_unhandled_promise_rejection(napi_env env, bool *result); + +// Gets and clears the last unhandled promise rejection. +JSR_API jsr_get_and_clear_last_unhandled_promise_rejection( + napi_env env, + napi_value *result); + +// Create new napi_env for the runtime. +JSR_API +jsr_create_node_api_env(napi_env root_env, int32_t api_version, napi_env *env); + +// Run task in the environment context. +JSR_API jsr_run_task(napi_env env, jsr_task_run_cb task_cb, void *data); + +// Initializes native module. +JSR_API jsr_initialize_native_module( + napi_env env, + napi_addon_register_func register_module, + int32_t api_version, + napi_value *exports); + +EXTERN_C_END + +#endif // !SRC_JS_RUNTIME_API_H_ diff --git a/packages/windows-hermes/vendor/include/node-api/js_native_api.h b/packages/windows-hermes/vendor/include/node-api/js_native_api.h new file mode 100644 index 0000000..84c91db --- /dev/null +++ b/packages/windows-hermes/vendor/include/node-api/js_native_api.h @@ -0,0 +1,627 @@ +#ifndef SRC_JS_NATIVE_API_H_ +#define SRC_JS_NATIVE_API_H_ + +// This file needs to be compatible with C compilers. +#include // NOLINT(modernize-deprecated-headers) +#include // NOLINT(modernize-deprecated-headers) + +// Use INT_MAX, this should only be consumed by the pre-processor anyway. +#define NAPI_VERSION_EXPERIMENTAL 2147483647 +#ifndef NAPI_VERSION +#ifdef NAPI_EXPERIMENTAL +#define NAPI_VERSION NAPI_VERSION_EXPERIMENTAL +#else +// The baseline version for N-API. +// The NAPI_VERSION controls which version will be used by default when +// compiling a native addon. If the addon developer specifically wants to use +// functions available in a new version of N-API that is not yet ported in all +// LTS versions, they can set NAPI_VERSION knowing that they have specifically +// depended on that version. +#define NAPI_VERSION 8 +#endif +#endif + +#if defined(NAPI_EXPERIMENTAL) && \ + !defined(NODE_API_EXPERIMENTAL_NO_WARNING) && \ + !defined(NODE_WANT_INTERNALS) +#ifdef _MSC_VER +#pragma message("NAPI_EXPERIMENTAL is enabled. " \ + "Experimental features may be unstable.") +#else +#warning "NAPI_EXPERIMENTAL is enabled. " \ + "Experimental features may be unstable." +#endif +#endif + +#include "js_native_api_types.h" + +// If you need __declspec(dllimport), either include instead, or +// define NAPI_EXTERN as __declspec(dllimport) on the compiler's command line. +#ifndef NAPI_EXTERN +#ifdef _WIN32 +#define NAPI_EXTERN __declspec(dllexport) +#elif defined(__wasm__) +#define NAPI_EXTERN \ + __attribute__((visibility("default"))) \ + __attribute__((__import_module__("napi"))) +#else +#define NAPI_EXTERN __attribute__((visibility("default"))) +#endif +#endif + +#define NAPI_AUTO_LENGTH SIZE_MAX + +#ifdef __cplusplus +#define EXTERN_C_START extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_START +#define EXTERN_C_END +#endif + +EXTERN_C_START + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_last_error_info( + node_api_basic_env env, const napi_extended_error_info** result); + +// Getters for defined singletons +NAPI_EXTERN napi_status NAPI_CDECL napi_get_undefined(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_null(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_global(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_boolean(napi_env env, + bool value, + napi_value* result); + +// Methods to create Primitive types/Objects +NAPI_EXTERN napi_status NAPI_CDECL napi_create_object(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_array(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_array_with_length(napi_env env, size_t length, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_double(napi_env env, + double value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_int32(napi_env env, + int32_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_uint32(napi_env env, + uint32_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_int64(napi_env env, + int64_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_latin1( + napi_env env, const char* str, size_t length, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_utf8(napi_env env, + const char* str, + size_t length, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_utf16(napi_env env, + const char16_t* str, + size_t length, + napi_value* result); +#if NAPI_VERSION >= 10 +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_external_string_latin1( + napi_env env, + char* str, + size_t length, + node_api_basic_finalize finalize_callback, + void* finalize_hint, + napi_value* result, + bool* copied); +NAPI_EXTERN napi_status NAPI_CDECL +node_api_create_external_string_utf16(napi_env env, + char16_t* str, + size_t length, + node_api_basic_finalize finalize_callback, + void* finalize_hint, + napi_value* result, + bool* copied); + +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_latin1( + napi_env env, const char* str, size_t length, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_utf8( + napi_env env, const char* str, size_t length, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_utf16( + napi_env env, const char16_t* str, size_t length, napi_value* result); +#endif // NAPI_VERSION >= 10 + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_symbol(napi_env env, + napi_value description, + napi_value* result); +#if NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL +node_api_symbol_for(napi_env env, + const char* utf8description, + size_t length, + napi_value* result); +#endif // NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL napi_create_function(napi_env env, + const char* utf8name, + size_t length, + napi_callback cb, + void* data, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_error(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_type_error(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_range_error(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); +#if NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_syntax_error( + napi_env env, napi_value code, napi_value msg, napi_value* result); +#endif // NAPI_VERSION >= 9 + +// Methods to get the native napi_value from Primitive type +NAPI_EXTERN napi_status NAPI_CDECL napi_typeof(napi_env env, + napi_value value, + napi_valuetype* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_double(napi_env env, + napi_value value, + double* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int32(napi_env env, + napi_value value, + int32_t* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_uint32(napi_env env, + napi_value value, + uint32_t* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int64(napi_env env, + napi_value value, + int64_t* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bool(napi_env env, + napi_value value, + bool* result); + +// Copies LATIN-1 encoded bytes from a string into a buffer. +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_latin1( + napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result); + +// Copies UTF-8 encoded bytes from a string into a buffer. +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_utf8( + napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result); + +// Copies UTF-16 encoded bytes from a string into a buffer. +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_utf16(napi_env env, + napi_value value, + char16_t* buf, + size_t bufsize, + size_t* result); + +// Methods to coerce values +// These APIs may execute user scripts +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_bool(napi_env env, + napi_value value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_number(napi_env env, + napi_value value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_object(napi_env env, + napi_value value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_string(napi_env env, + napi_value value, + napi_value* result); + +// Methods to work with Objects +NAPI_EXTERN napi_status NAPI_CDECL napi_get_prototype(napi_env env, + napi_value object, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_property_names(napi_env env, + napi_value object, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_set_property(napi_env env, + napi_value object, + napi_value key, + napi_value value); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_property(napi_env env, + napi_value object, + napi_value key, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_property(napi_env env, + napi_value object, + napi_value key, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_property(napi_env env, + napi_value object, + napi_value key, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_own_property(napi_env env, + napi_value object, + napi_value key, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_set_named_property(napi_env env, + napi_value object, + const char* utf8name, + napi_value value); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_named_property(napi_env env, + napi_value object, + const char* utf8name, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_named_property(napi_env env, + napi_value object, + const char* utf8name, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_set_element(napi_env env, + napi_value object, + uint32_t index, + napi_value value); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_element(napi_env env, + napi_value object, + uint32_t index, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_element(napi_env env, + napi_value object, + uint32_t index, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_element(napi_env env, + napi_value object, + uint32_t index, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_define_properties(napi_env env, + napi_value object, + size_t property_count, + const napi_property_descriptor* properties); + +// Methods to work with Arrays +NAPI_EXTERN napi_status NAPI_CDECL napi_is_array(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_array_length(napi_env env, + napi_value value, + uint32_t* result); + +// Methods to compare values +NAPI_EXTERN napi_status NAPI_CDECL napi_strict_equals(napi_env env, + napi_value lhs, + napi_value rhs, + bool* result); + +// Methods to work with Functions +NAPI_EXTERN napi_status NAPI_CDECL napi_call_function(napi_env env, + napi_value recv, + napi_value func, + size_t argc, + const napi_value* argv, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_new_instance(napi_env env, + napi_value constructor, + size_t argc, + const napi_value* argv, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_instanceof(napi_env env, + napi_value object, + napi_value constructor, + bool* result); + +// Methods to work with napi_callbacks + +// Gets all callback info in a single call. (Ugly, but faster.) +NAPI_EXTERN napi_status NAPI_CDECL napi_get_cb_info( + napi_env env, // [in] Node-API environment handle + napi_callback_info cbinfo, // [in] Opaque callback-info handle + size_t* argc, // [in-out] Specifies the size of the provided argv array + // and receives the actual count of args. + napi_value* argv, // [out] Array of values + napi_value* this_arg, // [out] Receives the JS 'this' arg for the call + void** data); // [out] Receives the data pointer for the callback. + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_new_target( + napi_env env, napi_callback_info cbinfo, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_define_class(napi_env env, + const char* utf8name, + size_t length, + napi_callback constructor, + void* data, + size_t property_count, + const napi_property_descriptor* properties, + napi_value* result); + +// Methods to work with external data objects +NAPI_EXTERN napi_status NAPI_CDECL +napi_wrap(napi_env env, + napi_value js_object, + void* native_object, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_ref* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_unwrap(napi_env env, + napi_value js_object, + void** result); +NAPI_EXTERN napi_status NAPI_CDECL napi_remove_wrap(napi_env env, + napi_value js_object, + void** result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_external(napi_env env, + void* data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_external(napi_env env, + napi_value value, + void** result); + +// Methods to control object lifespan + +// Set initial_refcount to 0 for a weak reference, >0 for a strong reference. +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_reference(napi_env env, + napi_value value, + uint32_t initial_refcount, + napi_ref* result); + +// Deletes a reference. The referenced value is released, and may +// be GC'd unless there are other references to it. +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_reference(napi_env env, + napi_ref ref); + +// Increments the reference count, optionally returning the resulting count. +// After this call the reference will be a strong reference because its +// refcount is >0, and the referenced object is effectively "pinned". +// Calling this when the refcount is 0 and the object is unavailable +// results in an error. +NAPI_EXTERN napi_status NAPI_CDECL napi_reference_ref(napi_env env, + napi_ref ref, + uint32_t* result); + +// Decrements the reference count, optionally returning the resulting count. +// If the result is 0 the reference is now weak and the object may be GC'd +// at any time if there are no other references. Calling this when the +// refcount is already 0 results in an error. +NAPI_EXTERN napi_status NAPI_CDECL napi_reference_unref(napi_env env, + napi_ref ref, + uint32_t* result); + +// Attempts to get a referenced value. If the reference is weak, +// the value might no longer be available, in that case the call +// is still successful but the result is NULL. +NAPI_EXTERN napi_status NAPI_CDECL napi_get_reference_value(napi_env env, + napi_ref ref, + napi_value* result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_open_handle_scope(napi_env env, napi_handle_scope* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_close_handle_scope(napi_env env, napi_handle_scope scope); +NAPI_EXTERN napi_status NAPI_CDECL napi_open_escapable_handle_scope( + napi_env env, napi_escapable_handle_scope* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_close_escapable_handle_scope( + napi_env env, napi_escapable_handle_scope scope); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_escape_handle(napi_env env, + napi_escapable_handle_scope scope, + napi_value escapee, + napi_value* result); + +// Methods to support error handling +NAPI_EXTERN napi_status NAPI_CDECL napi_throw(napi_env env, napi_value error); +NAPI_EXTERN napi_status NAPI_CDECL napi_throw_error(napi_env env, + const char* code, + const char* msg); +NAPI_EXTERN napi_status NAPI_CDECL napi_throw_type_error(napi_env env, + const char* code, + const char* msg); +NAPI_EXTERN napi_status NAPI_CDECL napi_throw_range_error(napi_env env, + const char* code, + const char* msg); +#if NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL node_api_throw_syntax_error(napi_env env, + const char* code, + const char* msg); +#endif // NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL napi_is_error(napi_env env, + napi_value value, + bool* result); + +// Methods to support catching exceptions +NAPI_EXTERN napi_status NAPI_CDECL napi_is_exception_pending(napi_env env, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_and_clear_last_exception(napi_env env, napi_value* result); + +// Methods to work with array buffers and typed arrays +NAPI_EXTERN napi_status NAPI_CDECL napi_is_arraybuffer(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_arraybuffer(napi_env env, + size_t byte_length, + void** data, + napi_value* result); +#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_external_arraybuffer(napi_env env, + void* external_data, + size_t byte_length, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result); +#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED +NAPI_EXTERN napi_status NAPI_CDECL napi_get_arraybuffer_info( + napi_env env, napi_value arraybuffer, void** data, size_t* byte_length); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_typedarray(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_typedarray(napi_env env, + napi_typedarray_type type, + size_t length, + napi_value arraybuffer, + size_t byte_offset, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_typedarray_info(napi_env env, + napi_value typedarray, + napi_typedarray_type* type, + size_t* length, + void** data, + napi_value* arraybuffer, + size_t* byte_offset); + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_dataview(napi_env env, + size_t length, + napi_value arraybuffer, + size_t byte_offset, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_dataview(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_dataview_info(napi_env env, + napi_value dataview, + size_t* bytelength, + void** data, + napi_value* arraybuffer, + size_t* byte_offset); + +// version management +NAPI_EXTERN napi_status NAPI_CDECL napi_get_version(node_api_basic_env env, + uint32_t* result); + +// Promises +NAPI_EXTERN napi_status NAPI_CDECL napi_create_promise(napi_env env, + napi_deferred* deferred, + napi_value* promise); +NAPI_EXTERN napi_status NAPI_CDECL napi_resolve_deferred(napi_env env, + napi_deferred deferred, + napi_value resolution); +NAPI_EXTERN napi_status NAPI_CDECL napi_reject_deferred(napi_env env, + napi_deferred deferred, + napi_value rejection); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_promise(napi_env env, + napi_value value, + bool* is_promise); + +// Running a script +NAPI_EXTERN napi_status NAPI_CDECL napi_run_script(napi_env env, + napi_value script, + napi_value* result); + +// Memory management +NAPI_EXTERN napi_status NAPI_CDECL napi_adjust_external_memory( + node_api_basic_env env, int64_t change_in_bytes, int64_t* adjusted_value); + +#if NAPI_VERSION >= 5 + +// Dates +NAPI_EXTERN napi_status NAPI_CDECL napi_create_date(napi_env env, + double time, + napi_value* result); + +NAPI_EXTERN napi_status NAPI_CDECL napi_is_date(napi_env env, + napi_value value, + bool* is_date); + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_date_value(napi_env env, + napi_value value, + double* result); + +// Add finalizer for pointer +NAPI_EXTERN napi_status NAPI_CDECL +napi_add_finalizer(napi_env env, + napi_value js_object, + void* finalize_data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_ref* result); + +#endif // NAPI_VERSION >= 5 + +#ifdef NAPI_EXPERIMENTAL +#define NODE_API_EXPERIMENTAL_HAS_POST_FINALIZER + +NAPI_EXTERN napi_status NAPI_CDECL +node_api_post_finalizer(node_api_basic_env env, + napi_finalize finalize_cb, + void* finalize_data, + void* finalize_hint); + +#endif // NAPI_EXPERIMENTAL + +#if NAPI_VERSION >= 6 + +// BigInt +NAPI_EXTERN napi_status NAPI_CDECL napi_create_bigint_int64(napi_env env, + int64_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_bigint_uint64(napi_env env, uint64_t value, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_bigint_words(napi_env env, + int sign_bit, + size_t word_count, + const uint64_t* words, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_int64(napi_env env, + napi_value value, + int64_t* result, + bool* lossless); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_uint64( + napi_env env, napi_value value, uint64_t* result, bool* lossless); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_value_bigint_words(napi_env env, + napi_value value, + int* sign_bit, + size_t* word_count, + uint64_t* words); + +// Object +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_all_property_names(napi_env env, + napi_value object, + napi_key_collection_mode key_mode, + napi_key_filter key_filter, + napi_key_conversion key_conversion, + napi_value* result); + +// Instance data +NAPI_EXTERN napi_status NAPI_CDECL +napi_set_instance_data(node_api_basic_env env, + void* data, + napi_finalize finalize_cb, + void* finalize_hint); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_instance_data(node_api_basic_env env, void** data); +#endif // NAPI_VERSION >= 6 + +#if NAPI_VERSION >= 7 +// ArrayBuffer detaching +NAPI_EXTERN napi_status NAPI_CDECL +napi_detach_arraybuffer(napi_env env, napi_value arraybuffer); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_is_detached_arraybuffer(napi_env env, napi_value value, bool* result); +#endif // NAPI_VERSION >= 7 + +#if NAPI_VERSION >= 8 +// Type tagging +NAPI_EXTERN napi_status NAPI_CDECL napi_type_tag_object( + napi_env env, napi_value value, const napi_type_tag* type_tag); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_check_object_type_tag(napi_env env, + napi_value value, + const napi_type_tag* type_tag, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_object_freeze(napi_env env, + napi_value object); +NAPI_EXTERN napi_status NAPI_CDECL napi_object_seal(napi_env env, + napi_value object); +#endif // NAPI_VERSION >= 8 + +EXTERN_C_END + +#endif // SRC_JS_NATIVE_API_H_ diff --git a/packages/windows-hermes/vendor/include/node-api/js_native_api_types.h b/packages/windows-hermes/vendor/include/node-api/js_native_api_types.h new file mode 100644 index 0000000..43e7bb7 --- /dev/null +++ b/packages/windows-hermes/vendor/include/node-api/js_native_api_types.h @@ -0,0 +1,211 @@ +#ifndef SRC_JS_NATIVE_API_TYPES_H_ +#define SRC_JS_NATIVE_API_TYPES_H_ + +// This file needs to be compatible with C compilers. +// This is a public include file, and these includes have essentially +// became part of it's API. +#include // NOLINT(modernize-deprecated-headers) +#include // NOLINT(modernize-deprecated-headers) + +#if !defined __cplusplus || (defined(_MSC_VER) && _MSC_VER < 1900) +typedef uint16_t char16_t; +#endif + +#ifndef NAPI_CDECL +#ifdef _WIN32 +#define NAPI_CDECL __cdecl +#else +#define NAPI_CDECL +#endif +#endif + +// JSVM API types are all opaque pointers for ABI stability +// typedef undefined structs instead of void* for compile time type safety +typedef struct napi_env__* napi_env; + +// We need to mark APIs which can be called during garbage collection (GC), +// meaning that they do not affect the state of the JS engine, and can +// therefore be called synchronously from a finalizer that itself runs +// synchronously during GC. Such APIs can receive either a `napi_env` or a +// `node_api_basic_env` as their first parameter, because we should be able to +// also call them during normal, non-garbage-collecting operations, whereas +// APIs that affect the state of the JS engine can only receive a `napi_env` as +// their first parameter, because we must not call them during GC. In lieu of +// inheritance, we use the properties of the const qualifier to accomplish +// this, because both a const and a non-const value can be passed to an API +// expecting a const value, but only a non-const value can be passed to an API +// expecting a non-const value. +// +// In conjunction with appropriate CFLAGS to warn us if we're passing a const +// (basic) environment into an API that expects a non-const environment, and +// the definition of basic finalizer function pointer types below, which +// receive a basic environment as their first parameter, and can thus only call +// basic APIs (unless the user explicitly casts the environment), we achieve +// the ability to ensure at compile time that we do not call APIs that affect +// the state of the JS engine from a synchronous (basic) finalizer. +#if !defined(NAPI_EXPERIMENTAL) || \ + (defined(NAPI_EXPERIMENTAL) && \ + (defined(NODE_API_EXPERIMENTAL_NOGC_ENV_OPT_OUT) || \ + defined(NODE_API_EXPERIMENTAL_BASIC_ENV_OPT_OUT))) +typedef struct napi_env__* node_api_nogc_env; +#else +typedef const struct napi_env__* node_api_nogc_env; +#endif +typedef node_api_nogc_env node_api_basic_env; + +typedef struct napi_value__* napi_value; +typedef struct napi_ref__* napi_ref; +typedef struct napi_handle_scope__* napi_handle_scope; +typedef struct napi_escapable_handle_scope__* napi_escapable_handle_scope; +typedef struct napi_callback_info__* napi_callback_info; +typedef struct napi_deferred__* napi_deferred; + +typedef enum { + napi_default = 0, + napi_writable = 1 << 0, + napi_enumerable = 1 << 1, + napi_configurable = 1 << 2, + + // Used with napi_define_class to distinguish static properties + // from instance properties. Ignored by napi_define_properties. + napi_static = 1 << 10, + +#if NAPI_VERSION >= 8 + // Default for class methods. + napi_default_method = napi_writable | napi_configurable, + + // Default for object properties, like in JS obj[prop]. + napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable, +#endif // NAPI_VERSION >= 8 +} napi_property_attributes; + +typedef enum { + // ES6 types (corresponds to typeof) + napi_undefined, + napi_null, + napi_boolean, + napi_number, + napi_string, + napi_symbol, + napi_object, + napi_function, + napi_external, + napi_bigint, +} napi_valuetype; + +typedef enum { + napi_int8_array, + napi_uint8_array, + napi_uint8_clamped_array, + napi_int16_array, + napi_uint16_array, + napi_int32_array, + napi_uint32_array, + napi_float32_array, + napi_float64_array, + napi_bigint64_array, + napi_biguint64_array, +} napi_typedarray_type; + +typedef enum { + napi_ok, + napi_invalid_arg, + napi_object_expected, + napi_string_expected, + napi_name_expected, + napi_function_expected, + napi_number_expected, + napi_boolean_expected, + napi_array_expected, + napi_generic_failure, + napi_pending_exception, + napi_cancelled, + napi_escape_called_twice, + napi_handle_scope_mismatch, + napi_callback_scope_mismatch, + napi_queue_full, + napi_closing, + napi_bigint_expected, + napi_date_expected, + napi_arraybuffer_expected, + napi_detachable_arraybuffer_expected, + napi_would_deadlock, // unused + napi_no_external_buffers_allowed, + napi_cannot_run_js, +} napi_status; +// Note: when adding a new enum value to `napi_status`, please also update +// * `const int last_status` in the definition of `napi_get_last_error_info()' +// in file js_native_api_v8.cc. +// * `const char* error_messages[]` in file js_native_api_v8.cc with a brief +// message explaining the error. +// * the definition of `napi_status` in doc/api/n-api.md to reflect the newly +// added value(s). + +typedef napi_value(NAPI_CDECL* napi_callback)(napi_env env, + napi_callback_info info); +typedef void(NAPI_CDECL* napi_finalize)(napi_env env, + void* finalize_data, + void* finalize_hint); + +#if !defined(NAPI_EXPERIMENTAL) || \ + (defined(NAPI_EXPERIMENTAL) && \ + (defined(NODE_API_EXPERIMENTAL_NOGC_ENV_OPT_OUT) || \ + defined(NODE_API_EXPERIMENTAL_BASIC_ENV_OPT_OUT))) +typedef napi_finalize node_api_nogc_finalize; +#else +typedef void(NAPI_CDECL* node_api_nogc_finalize)(node_api_nogc_env env, + void* finalize_data, + void* finalize_hint); +#endif +typedef node_api_nogc_finalize node_api_basic_finalize; + +typedef struct { + // One of utf8name or name should be NULL. + const char* utf8name; + napi_value name; + + napi_callback method; + napi_callback getter; + napi_callback setter; + napi_value value; + + napi_property_attributes attributes; + void* data; +} napi_property_descriptor; + +typedef struct { + const char* error_message; + void* engine_reserved; + uint32_t engine_error_code; + napi_status error_code; +} napi_extended_error_info; + +#if NAPI_VERSION >= 6 +typedef enum { + napi_key_include_prototypes, + napi_key_own_only +} napi_key_collection_mode; + +typedef enum { + napi_key_all_properties = 0, + napi_key_writable = 1, + napi_key_enumerable = 1 << 1, + napi_key_configurable = 1 << 2, + napi_key_skip_strings = 1 << 3, + napi_key_skip_symbols = 1 << 4 +} napi_key_filter; + +typedef enum { + napi_key_keep_numbers, + napi_key_numbers_to_strings +} napi_key_conversion; +#endif // NAPI_VERSION >= 6 + +#if NAPI_VERSION >= 8 +typedef struct { + uint64_t lower; + uint64_t upper; +} napi_type_tag; +#endif // NAPI_VERSION >= 8 + +#endif // SRC_JS_NATIVE_API_TYPES_H_ diff --git a/packages/windows-hermes/vendor/include/node-api/node_api.h b/packages/windows-hermes/vendor/include/node-api/node_api.h new file mode 100644 index 0000000..35e5c3e --- /dev/null +++ b/packages/windows-hermes/vendor/include/node-api/node_api.h @@ -0,0 +1,269 @@ +#ifndef SRC_NODE_API_H_ +#define SRC_NODE_API_H_ + +#if defined(BUILDING_NODE_EXTENSION) && !defined(NAPI_EXTERN) +#ifdef _WIN32 +// Building native addon against node +#define NAPI_EXTERN __declspec(dllimport) +#elif defined(__wasm__) +#define NAPI_EXTERN __attribute__((__import_module__("napi"))) +#endif +#endif +#include "js_native_api.h" +#include "node_api_types.h" + +struct uv_loop_s; // Forward declaration. + +#ifdef _WIN32 +#define NAPI_MODULE_EXPORT __declspec(dllexport) +#else +#ifdef __EMSCRIPTEN__ +#define NAPI_MODULE_EXPORT \ + __attribute__((visibility("default"))) __attribute__((used)) +#else +#define NAPI_MODULE_EXPORT __attribute__((visibility("default"))) +#endif +#endif + +#if defined(__GNUC__) +#define NAPI_NO_RETURN __attribute__((noreturn)) +#elif defined(_WIN32) +#define NAPI_NO_RETURN __declspec(noreturn) +#else +#define NAPI_NO_RETURN +#endif + +typedef napi_value(NAPI_CDECL* napi_addon_register_func)(napi_env env, + napi_value exports); +typedef int32_t(NAPI_CDECL* node_api_addon_get_api_version_func)(void); + +// Used by deprecated registration method napi_module_register. +typedef struct napi_module { + int nm_version; + unsigned int nm_flags; + const char* nm_filename; + napi_addon_register_func nm_register_func; + const char* nm_modname; + void* nm_priv; + void* reserved[4]; +} napi_module; + +#define NAPI_MODULE_VERSION 1 + +#define NAPI_MODULE_INITIALIZER_X(base, version) \ + NAPI_MODULE_INITIALIZER_X_HELPER(base, version) +#define NAPI_MODULE_INITIALIZER_X_HELPER(base, version) base##version + +#ifdef __wasm__ +#define NAPI_MODULE_INITIALIZER_BASE napi_register_wasm_v +#else +#define NAPI_MODULE_INITIALIZER_BASE napi_register_module_v +#endif + +#define NODE_API_MODULE_GET_API_VERSION_BASE node_api_module_get_api_version_v + +#define NAPI_MODULE_INITIALIZER \ + NAPI_MODULE_INITIALIZER_X(NAPI_MODULE_INITIALIZER_BASE, NAPI_MODULE_VERSION) + +#define NODE_API_MODULE_GET_API_VERSION \ + NAPI_MODULE_INITIALIZER_X(NODE_API_MODULE_GET_API_VERSION_BASE, \ + NAPI_MODULE_VERSION) + +#define NAPI_MODULE_INIT() \ + EXTERN_C_START \ + NAPI_MODULE_EXPORT int32_t NODE_API_MODULE_GET_API_VERSION(void) { \ + return NAPI_VERSION; \ + } \ + NAPI_MODULE_EXPORT napi_value NAPI_MODULE_INITIALIZER(napi_env env, \ + napi_value exports); \ + EXTERN_C_END \ + napi_value NAPI_MODULE_INITIALIZER(napi_env env, napi_value exports) + +#define NAPI_MODULE(modname, regfunc) \ + NAPI_MODULE_INIT() { return regfunc(env, exports); } + +// Deprecated. Use NAPI_MODULE. +#define NAPI_MODULE_X(modname, regfunc, priv, flags) \ + NAPI_MODULE(modname, regfunc) + +EXTERN_C_START + +// Deprecated. Replaced by symbol-based registration defined by NAPI_MODULE +// and NAPI_MODULE_INIT macros. +NAPI_EXTERN void NAPI_CDECL +napi_module_register(napi_module* mod); + +NAPI_EXTERN NAPI_NO_RETURN void NAPI_CDECL +napi_fatal_error(const char* location, + size_t location_len, + const char* message, + size_t message_len); + +// Methods for custom handling of async operations +NAPI_EXTERN napi_status NAPI_CDECL +napi_async_init(napi_env env, + napi_value async_resource, + napi_value async_resource_name, + napi_async_context* result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_async_destroy(napi_env env, napi_async_context async_context); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_make_callback(napi_env env, + napi_async_context async_context, + napi_value recv, + napi_value func, + size_t argc, + const napi_value* argv, + napi_value* result); + +// Methods to provide node::Buffer functionality with napi types +NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer(napi_env env, + size_t length, + void** data, + napi_value* result); +#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_external_buffer(napi_env env, + size_t length, + void* data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result); +#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED + +#if NAPI_VERSION >= 10 + +NAPI_EXTERN napi_status NAPI_CDECL +node_api_create_buffer_from_arraybuffer(napi_env env, + napi_value arraybuffer, + size_t byte_offset, + size_t byte_length, + napi_value* result); +#endif // NAPI_VERSION >= 10 + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer_copy(napi_env env, + size_t length, + const void* data, + void** result_data, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_buffer(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_buffer_info(napi_env env, + napi_value value, + void** data, + size_t* length); + +// Methods to manage simple async operations +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_async_work(napi_env env, + napi_value async_resource, + napi_value async_resource_name, + napi_async_execute_callback execute, + napi_async_complete_callback complete, + void* data, + napi_async_work* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_async_work(napi_env env, + napi_async_work work); +NAPI_EXTERN napi_status NAPI_CDECL napi_queue_async_work(node_api_basic_env env, + napi_async_work work); +NAPI_EXTERN napi_status NAPI_CDECL +napi_cancel_async_work(node_api_basic_env env, napi_async_work work); + +// version management +NAPI_EXTERN napi_status NAPI_CDECL napi_get_node_version( + node_api_basic_env env, const napi_node_version** version); + +#if NAPI_VERSION >= 2 + +// Return the current libuv event loop for a given environment +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_uv_event_loop(node_api_basic_env env, struct uv_loop_s** loop); + +#endif // NAPI_VERSION >= 2 + +#if NAPI_VERSION >= 3 + +NAPI_EXTERN napi_status NAPI_CDECL napi_fatal_exception(napi_env env, + napi_value err); + +NAPI_EXTERN napi_status NAPI_CDECL napi_add_env_cleanup_hook( + node_api_basic_env env, napi_cleanup_hook fun, void* arg); + +NAPI_EXTERN napi_status NAPI_CDECL napi_remove_env_cleanup_hook( + node_api_basic_env env, napi_cleanup_hook fun, void* arg); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_open_callback_scope(napi_env env, + napi_value resource_object, + napi_async_context context, + napi_callback_scope* result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_close_callback_scope(napi_env env, napi_callback_scope scope); + +#endif // NAPI_VERSION >= 3 + +#if NAPI_VERSION >= 4 + +// Calling into JS from other threads +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_threadsafe_function(napi_env env, + napi_value func, + napi_value async_resource, + napi_value async_resource_name, + size_t max_queue_size, + size_t initial_thread_count, + void* thread_finalize_data, + napi_finalize thread_finalize_cb, + void* context, + napi_threadsafe_function_call_js call_js_cb, + napi_threadsafe_function* result); + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_threadsafe_function_context( + napi_threadsafe_function func, void** result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_call_threadsafe_function(napi_threadsafe_function func, + void* data, + napi_threadsafe_function_call_mode is_blocking); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_acquire_threadsafe_function(napi_threadsafe_function func); + +NAPI_EXTERN napi_status NAPI_CDECL napi_release_threadsafe_function( + napi_threadsafe_function func, napi_threadsafe_function_release_mode mode); + +NAPI_EXTERN napi_status NAPI_CDECL napi_unref_threadsafe_function( + node_api_basic_env env, napi_threadsafe_function func); + +NAPI_EXTERN napi_status NAPI_CDECL napi_ref_threadsafe_function( + node_api_basic_env env, napi_threadsafe_function func); + +#endif // NAPI_VERSION >= 4 + +#if NAPI_VERSION >= 8 + +NAPI_EXTERN napi_status NAPI_CDECL +napi_add_async_cleanup_hook(node_api_basic_env env, + napi_async_cleanup_hook hook, + void* arg, + napi_async_cleanup_hook_handle* remove_handle); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_remove_async_cleanup_hook(napi_async_cleanup_hook_handle remove_handle); + +#endif // NAPI_VERSION >= 8 + +#if NAPI_VERSION >= 9 + +NAPI_EXTERN napi_status NAPI_CDECL +node_api_get_module_file_name(node_api_basic_env env, const char** result); + +#endif // NAPI_VERSION >= 9 + +EXTERN_C_END + +#endif // SRC_NODE_API_H_ diff --git a/packages/windows-hermes/vendor/include/node-api/node_api_types.h b/packages/windows-hermes/vendor/include/node-api/node_api_types.h new file mode 100644 index 0000000..9c2f03f --- /dev/null +++ b/packages/windows-hermes/vendor/include/node-api/node_api_types.h @@ -0,0 +1,52 @@ +#ifndef SRC_NODE_API_TYPES_H_ +#define SRC_NODE_API_TYPES_H_ + +#include "js_native_api_types.h" + +typedef struct napi_callback_scope__* napi_callback_scope; +typedef struct napi_async_context__* napi_async_context; +typedef struct napi_async_work__* napi_async_work; + +#if NAPI_VERSION >= 3 +typedef void(NAPI_CDECL* napi_cleanup_hook)(void* arg); +#endif // NAPI_VERSION >= 3 + +#if NAPI_VERSION >= 4 +typedef struct napi_threadsafe_function__* napi_threadsafe_function; +#endif // NAPI_VERSION >= 4 + +#if NAPI_VERSION >= 4 +typedef enum { + napi_tsfn_release, + napi_tsfn_abort +} napi_threadsafe_function_release_mode; + +typedef enum { + napi_tsfn_nonblocking, + napi_tsfn_blocking +} napi_threadsafe_function_call_mode; +#endif // NAPI_VERSION >= 4 + +typedef void(NAPI_CDECL* napi_async_execute_callback)(napi_env env, void* data); +typedef void(NAPI_CDECL* napi_async_complete_callback)(napi_env env, + napi_status status, + void* data); +#if NAPI_VERSION >= 4 +typedef void(NAPI_CDECL* napi_threadsafe_function_call_js)( + napi_env env, napi_value js_callback, void* context, void* data); +#endif // NAPI_VERSION >= 4 + +typedef struct { + uint32_t major; + uint32_t minor; + uint32_t patch; + const char* release; +} napi_node_version; + +#if NAPI_VERSION >= 8 +typedef struct napi_async_cleanup_hook_handle__* napi_async_cleanup_hook_handle; +typedef void(NAPI_CDECL* napi_async_cleanup_hook)( + napi_async_cleanup_hook_handle handle, void* data); +#endif // NAPI_VERSION >= 8 + +#endif // SRC_NODE_API_TYPES_H_ diff --git a/packages/windows-hermes/vendor/x64/icu/hermes-icu.dll b/packages/windows-hermes/vendor/x64/icu/hermes-icu.dll new file mode 100644 index 0000000..fff1c2a Binary files /dev/null and b/packages/windows-hermes/vendor/x64/icu/hermes-icu.dll differ diff --git a/packages/windows-hermes/vendor/x64/icu/hermes.dll b/packages/windows-hermes/vendor/x64/icu/hermes.dll new file mode 100644 index 0000000..eb44224 Binary files /dev/null and b/packages/windows-hermes/vendor/x64/icu/hermes.dll differ diff --git a/packages/windows-hermes/vendor/x64/icu/hermes.lib b/packages/windows-hermes/vendor/x64/icu/hermes.lib new file mode 100644 index 0000000..4a26d7f Binary files /dev/null and b/packages/windows-hermes/vendor/x64/icu/hermes.lib differ diff --git a/packages/windows-hermes/vendor/x64/icu/napi_symbols.txt b/packages/windows-hermes/vendor/x64/icu/napi_symbols.txt new file mode 100644 index 0000000..c9209cb --- /dev/null +++ b/packages/windows-hermes/vendor/x64/icu/napi_symbols.txt @@ -0,0 +1,115 @@ +napi_add_finalizer +napi_adjust_external_memory +napi_call_function +napi_check_object_type_tag +napi_close_escapable_handle_scope +napi_close_handle_scope +napi_coerce_to_bool +napi_coerce_to_number +napi_coerce_to_object +napi_coerce_to_string +napi_create_array +napi_create_array_with_length +napi_create_arraybuffer +napi_create_bigint_int64 +napi_create_bigint_uint64 +napi_create_bigint_words +napi_create_dataview +napi_create_date +napi_create_double +napi_create_error +napi_create_external +napi_create_external_arraybuffer +napi_create_function +napi_create_int32 +napi_create_int64 +napi_create_object +napi_create_promise +napi_create_range_error +napi_create_reference +napi_create_string_latin1 +napi_create_string_utf16 +napi_create_string_utf8 +napi_create_symbol +napi_create_type_error +napi_create_typedarray +napi_create_uint32 +napi_define_class +napi_define_properties +napi_delete_element +napi_delete_property +napi_delete_reference +napi_detach_arraybuffer +napi_escape_handle +napi_get_all_property_names +napi_get_and_clear_last_exception +napi_get_array_length +napi_get_arraybuffer_info +napi_get_boolean +napi_get_cb_info +napi_get_dataview_info +napi_get_date_value +napi_get_element +napi_get_global +napi_get_instance_data +napi_get_last_error_info +napi_get_named_property +napi_get_new_target +napi_get_null +napi_get_property +napi_get_property_names +napi_get_prototype +napi_get_reference_value +napi_get_typedarray_info +napi_get_undefined +napi_get_value_bigint_int64 +napi_get_value_bigint_uint64 +napi_get_value_bigint_words +napi_get_value_bool +napi_get_value_double +napi_get_value_external +napi_get_value_int32 +napi_get_value_int64 +napi_get_value_string_latin1 +napi_get_value_string_utf16 +napi_get_value_string_utf8 +napi_get_value_uint32 +napi_get_version +napi_has_element +napi_has_named_property +napi_has_own_property +napi_has_property +napi_instanceof +napi_is_array +napi_is_arraybuffer +napi_is_dataview +napi_is_date +napi_is_detached_arraybuffer +napi_is_error +napi_is_exception_pending +napi_is_promise +napi_is_typedarray +napi_new_instance +napi_object_freeze +napi_object_seal +napi_open_escapable_handle_scope +napi_open_handle_scope +napi_reference_ref +napi_reference_unref +napi_reject_deferred +napi_remove_wrap +napi_resolve_deferred +napi_run_script +napi_set_element +napi_set_instance_data +napi_set_named_property +napi_set_property +napi_strict_equals +napi_throw +napi_throw_error +napi_throw_range_error +napi_throw_type_error +napi_type_tag_object +napi_typeof +napi_unwrap +napi_wrap diff --git a/packages/windows-hermes/vendor/x64/no-icu/hermes.dll b/packages/windows-hermes/vendor/x64/no-icu/hermes.dll new file mode 100644 index 0000000..beffa82 Binary files /dev/null and b/packages/windows-hermes/vendor/x64/no-icu/hermes.dll differ diff --git a/packages/windows-hermes/vendor/x64/no-icu/hermes.lib b/packages/windows-hermes/vendor/x64/no-icu/hermes.lib new file mode 100644 index 0000000..4a26d7f Binary files /dev/null and b/packages/windows-hermes/vendor/x64/no-icu/hermes.lib differ diff --git a/packages/windows-hermes/vendor/x64/no-icu/napi_symbols.txt b/packages/windows-hermes/vendor/x64/no-icu/napi_symbols.txt new file mode 100644 index 0000000..c9209cb --- /dev/null +++ b/packages/windows-hermes/vendor/x64/no-icu/napi_symbols.txt @@ -0,0 +1,115 @@ +napi_add_finalizer +napi_adjust_external_memory +napi_call_function +napi_check_object_type_tag +napi_close_escapable_handle_scope +napi_close_handle_scope +napi_coerce_to_bool +napi_coerce_to_number +napi_coerce_to_object +napi_coerce_to_string +napi_create_array +napi_create_array_with_length +napi_create_arraybuffer +napi_create_bigint_int64 +napi_create_bigint_uint64 +napi_create_bigint_words +napi_create_dataview +napi_create_date +napi_create_double +napi_create_error +napi_create_external +napi_create_external_arraybuffer +napi_create_function +napi_create_int32 +napi_create_int64 +napi_create_object +napi_create_promise +napi_create_range_error +napi_create_reference +napi_create_string_latin1 +napi_create_string_utf16 +napi_create_string_utf8 +napi_create_symbol +napi_create_type_error +napi_create_typedarray +napi_create_uint32 +napi_define_class +napi_define_properties +napi_delete_element +napi_delete_property +napi_delete_reference +napi_detach_arraybuffer +napi_escape_handle +napi_get_all_property_names +napi_get_and_clear_last_exception +napi_get_array_length +napi_get_arraybuffer_info +napi_get_boolean +napi_get_cb_info +napi_get_dataview_info +napi_get_date_value +napi_get_element +napi_get_global +napi_get_instance_data +napi_get_last_error_info +napi_get_named_property +napi_get_new_target +napi_get_null +napi_get_property +napi_get_property_names +napi_get_prototype +napi_get_reference_value +napi_get_typedarray_info +napi_get_undefined +napi_get_value_bigint_int64 +napi_get_value_bigint_uint64 +napi_get_value_bigint_words +napi_get_value_bool +napi_get_value_double +napi_get_value_external +napi_get_value_int32 +napi_get_value_int64 +napi_get_value_string_latin1 +napi_get_value_string_utf16 +napi_get_value_string_utf8 +napi_get_value_uint32 +napi_get_version +napi_has_element +napi_has_named_property +napi_has_own_property +napi_has_property +napi_instanceof +napi_is_array +napi_is_arraybuffer +napi_is_dataview +napi_is_date +napi_is_detached_arraybuffer +napi_is_error +napi_is_exception_pending +napi_is_promise +napi_is_typedarray +napi_new_instance +napi_object_freeze +napi_object_seal +napi_open_escapable_handle_scope +napi_open_handle_scope +napi_reference_ref +napi_reference_unref +napi_reject_deferred +napi_remove_wrap +napi_resolve_deferred +napi_run_script +napi_set_element +napi_set_instance_data +napi_set_named_property +napi_set_property +napi_strict_equals +napi_throw +napi_throw_error +napi_throw_range_error +napi_throw_type_error +napi_type_tag_object +napi_typeof +napi_unwrap +napi_wrap diff --git a/packages/windows-jsc/Cargo.lock b/packages/windows-jsc/Cargo.lock new file mode 100644 index 0000000..62a6109 --- /dev/null +++ b/packages/windows-jsc/Cargo.lock @@ -0,0 +1,1706 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "serde", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link", +] + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex 1.3.0", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "calendrical_calculations" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5abbd6eeda6885048d357edc66748eea6e0268e3dd11f326fff5bd248d779c26" +dependencies = [ + "core_maths", + "displaydoc", +] + +[[package]] +name = "cc" +version = "1.2.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38" +dependencies = [ + "find-msvc-tools", + "shlex 2.0.1", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core_maths" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" +dependencies = [ + "libm", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "diplomat" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7935649d00000f5c5d735448ad3dc07b9738160727017914cf42138b8e8e6611" +dependencies = [ + "diplomat_core", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "diplomat-runtime" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "970ac38ad677632efcee6d517e783958da9bc78ec206d8d5e35b459ffc5e4864" + +[[package]] +name = "diplomat_core" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf41b94101a4bce993febaf0098092b0bb31deaf0ecaf6e0a2562465f61b383" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "smallvec", + "strck", + "syn", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fslock" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "gzip-header" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86848f4fd157d91041a62c78046fb7b248bcc2dce78376d436a1756e9a038577" +dependencies = [ + "crc32fast", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_calendar" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b2acc6263f494f1df50685b53ff8e57869e47d5c6fe39c23d518ae9a4f3e45" +dependencies = [ + "calendrical_calculations", + "displaydoc", + "icu_calendar_data", + "icu_locale", + "icu_locale_core", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_calendar_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "118577bcf3a0fa7c6ac0a7d6e951814da84ee56b9b1f68fb4d8d10b08cefaf4d" + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5a396343c7208121dc86e35623d3dfe19814a7613cfd14964994cdc9c9a2e26" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_locale_data", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "serde", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locale_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fdcc9ac77c6d74ff5cf6e65ef3181d6af32003b16fce3a77fb451d2f695993" + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "serde", + "stable_deref_trait", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "ixdtf" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ceaf4c6c48465bead8cb6a0b7c4ee0c86ecbb31239032b9c66ab9a08d2f3ee1" + +[[package]] +name = "js-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libffi" +version = "5.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed185dbb87539a100c1b36c219e16e71572c6d4d4fed3ded898140f755adeaaf" +dependencies = [ + "libc", + "libffi-sys", +] + +[[package]] +name = "libffi-sys" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25831b230b6a90bdea9f28339c1d00d59773a1c492e8ca09b1ad80e56394c261" +dependencies = [ + "cc", +] + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libmimalloc-sys" +version = "0.1.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9" +dependencies = [ + "cc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "metadata" +version = "0.1.0" +dependencies = [ + "ahash", + "dyn-clone", + "parking_lot", + "sha1", + "windows", +] + +[[package]] +name = "mimalloc" +version = "0.1.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d4139bb28d14ad1facf21d5eb8825051b326e172d216b39f6d31df53cc97862" +dependencies = [ + "libmimalloc-sys", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "napi" +version = "2.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55740c4ae1d8696773c78fdafd5d0e5fe9bc9f1b071c7ba493ba5c413a9184f3" +dependencies = [ + "bitflags", + "ctor", + "napi-derive", + "napi-sys", + "once_cell", +] + +[[package]] +name = "napi-derive" +version = "2.16.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cbe2585d8ac223f7d34f13701434b9d5f4eb9c332cccce8dee57ea18ab8ab0c" +dependencies = [ + "cfg-if", + "convert_case", + "napi-derive-backend", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "napi-derive-backend" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1639aaa9eeb76e91c6ae66da8ce3e89e921cd3885e99ec85f4abacae72fc91bf" +dependencies = [ + "convert_case", + "once_cell", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "napi-sys" +version = "2.4.0" +dependencies = [ + "libloading", + "windows-link", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "ns-windows-common" +version = "0.1.0" + +[[package]] +name = "ns-windows-demo" +version = "0.1.0" +dependencies = [ + "backtrace", + "windows", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "serde_core", + "writeable", + "zerovec", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "resb" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22d392791f3c6802a1905a509e9d1a6039cbbcb5e9e00e5a6d3661f7c874f390" +dependencies = [ + "potential_utf", + "serde_core", +] + +[[package]] +name = "runtime" +version = "0.1.0" +dependencies = [ + "ahash", + "anyhow", + "byteorder", + "chrono", + "form_urlencoded", + "libc", + "libffi", + "metadata", + "mimalloc", + "napi", + "parking_lot", + "regex", + "runtime-binding-gen", + "serde", + "serde_json", + "url", + "v8", + "windows", + "windows-collections", + "windows-core", +] + +[[package]] +name = "runtime-binding-gen" +version = "0.1.0" +dependencies = [ + "ahash", + "anyhow", + "metadata", + "regex", + "serde", + "serde_json", + "windows", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha1" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strck" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42316e70da376f3d113a68d138a60d8a9883c604fe97942721ec2068dab13a9f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "temporal_capi" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c534c1ac4165fb410b5ccd12c79040573622865e881bb8caad70981806a141f1" +dependencies = [ + "diplomat", + "diplomat-runtime", + "icu_calendar", + "icu_locale_core", + "num-traits", + "temporal_rs", + "timezone_provider", + "writeable", + "zoneinfo64", +] + +[[package]] +name = "temporal_rs" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1afc06e45b0d63943c777d0233523fa2e23a12431a73c37b1c0366777b31717" +dependencies = [ + "calendrical_calculations", + "core_maths", + "icu_calendar", + "icu_locale_core", + "ixdtf", + "num-traits", + "timezone_provider", + "tinystr", + "writeable", +] + +[[package]] +name = "timezone_provider" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48738555f588bc05b58cb55206843cde9875bb1fde50101dd1a7c50ac6535cd5" +dependencies = [ + "tinystr", + "zerotrie", + "zerovec", + "zoneinfo64", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "serde_core", + "zerovec", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "v8" +version = "147.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2df8fffd507fb18ed000673a83d937f58e60fb07f3306b2274284125b15137cd" +dependencies = [ + "bindgen", + "bitflags", + "fslock", + "gzip-header", + "home", + "miniz_oxide", + "paste", + "temporal_capi", + "which", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "which" +version = "6.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" +dependencies = [ + "either", + "home", + "rustix", + "winsafe", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-jsc" +version = "0.1.0" +dependencies = [ + "cc", + "napi", + "ns-windows-common", + "ns-windows-demo", + "runtime", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core", + "windows-link", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "serde", + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zoneinfo64" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6eb2607e906160c457fd573e9297e65029669906b9ac8fb1b5cd5e055f0705" +dependencies = [ + "calendrical_calculations", + "icu_locale_core", + "potential_utf", + "resb", + "serde", +] diff --git a/packages/windows-jsc/Cargo.toml b/packages/windows-jsc/Cargo.toml new file mode 100644 index 0000000..27cef55 --- /dev/null +++ b/packages/windows-jsc/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "windows-jsc" +version = "0.1.0" +edition = "2021" +description = "NativeScript Windows runtime on JavaScriptCore (napi-android JSC shim over JSC's public C API). Publishes as @nativescript/windows-jsc." + +# `cdylib` so `build.ps1 -Engine jsc` can emit `nativescript.dll` (the WinUI 3 host DLL); +# `rlib` so the standalone `nativescript-windows` bin can still link the crate. +[lib] +crate-type = ["rlib", "cdylib"] + +# The runnable bin needs a real JavaScriptCore.lib in vendor/x64 — gated so the shim still +# compile-verifies (cargo build --lib) without the engine binary present. +[[bin]] +name = "nativescript-windows" +path = "src/main.rs" +required-features = ["jsc_link"] + +[features] +default = [] +# Link JavaScriptCore.{lib,dll} (must be dropped into vendor/x64) and build the runtime host. +jsc_link = ["dep:napi", "dep:runtime", "dep:ns-windows-common", "dep:ns-windows-demo"] +# Compile the `nativescript.dll` C ABI (src/abi.rs) into the cdylib so the WinUI 3 host can load +# JSC as a drop-in replacement for the classic runtime. Selected by `build.ps1 -Engine jsc`; +# implies `jsc_link` (a real JavaScriptCore.{lib,dll} must be present in vendor/x64). +host_dll = ["jsc_link"] + +[dependencies] +napi = { version = "2", default-features = false, features = ["napi8"], optional = true } +runtime = { path = "../../runtime", features = ["napi_engine"], optional = true } +# Shared JS prelude + URL polyfill — used by both the cdylib (abi.rs) and the demo bin (main.rs). +ns-windows-common = { path = "../common", optional = true } +# Crash reporter + self-test harness for the demo bin (main.rs) only. +ns-windows-demo = { path = "../demo", optional = true } + +[build-dependencies] +cc = "1" + +# Windows-port fix so napi_* resolve from THIS cdylib (nativescript.dll) when loaded by the WinUI 3 +# .NET host, not from the host .exe (which has no napi exports). See packages/vendor/napi-sys. +[patch.crates-io] +napi-sys = { path = "../vendor/napi-sys" } + +[profile.release] +debug = true diff --git a/packages/windows-jsc/README.md b/packages/windows-jsc/README.md new file mode 100644 index 0000000..e9f7737 --- /dev/null +++ b/packages/windows-jsc/README.md @@ -0,0 +1,55 @@ +# @nativescript/windows-jsc + +NativeScript Windows runtime on **JavaScriptCore**, no Node. **Working** — the full WinRT demo +passes (`exit 0`): typed WinRT calls, a 20-call stress loop, and a `JsonObject` round-trip. + +## As an app runtime (drop-in for `@nativescript/windows`) +Publishes as `@nativescript/windows-jsc`, the **same** WinUI 3 framework as `@nativescript/windows` +with the JavaScriptCore runtime DLL — swap the dependency and an app runs unchanged. Build the +framework with the engine flag (needs a real `JavaScriptCore.lib` in `vendor/x64`): +```sh +pwsh -File ../../template/build.ps1 -Engine jsc # or: npm run build +``` +The engine → runtime-DLL adapter (the C ABI the WinUI 3 host P/Invokes) follows the reference +implementation in `../windows-quickjs/src/abi.rs`. See `../README.md` for the full contract. + +## The engine binary — Playwright's WebKit (current) +The official WebKit WinCairo buildbot is dead (last Windows build Sept 2024), and there's no NuGet/npm +prebuilt. The **current** source of a Windows `JavaScriptCore.dll` is **Playwright**, which rebuilds +WebKit constantly: + +``` +https://playwright.download.prss.microsoft.com/dbazure/download/playwright/builds/webkit//webkit-win64.zip +``` +(`` from `packages/playwright-core/browsers.json` in microsoft/playwright — 2331 at time of +writing; the vendored `JavaScriptCore.dll` is dated 2026-07-14). It exports the full JSC C API and +depends only on `icuin77.dll` / `icuuc77.dll` (+ `icudt77.dll` data). + +`vendor/x64/` holds (committed, no LFS): `JavaScriptCore.dll` (33 MB), `icudt77.dll` (32 MB), +`icuin77.dll`, `icuuc77.dll`, and `JavaScriptCore.lib` — an **import lib generated from the DLL's +exports** (no `.lib` ships in the zip): +```sh +llvm-objdump -p JavaScriptCore.dll | awk '/Export Table/{f=1;next} f&&/0x/{print $NF}' \ + | grep -E '^(JS|WK|k)' | awk '{print ($0 ~ /^k/) ? $0" DATA" : $0}' > exports # k* are DATA symbols +printf 'EXPORTS\n' > JavaScriptCore.def; cat exports >> JavaScriptCore.def +lib /def:JavaScriptCore.def /machine:x64 /out:JavaScriptCore.lib +``` + +## Build & run +```sh +cargo build --release --features jsc_link --manifest-path packages/windows-jsc/Cargo.toml +target/release/nativescript-windows.exe +``` +`build.rs` links `JavaScriptCore.lib` and copies the DLLs beside the exe. + +## Shim = napi-android's JSC provider (public C API), + two Windows fixes +`jsc-api.cpp` is over JSC's stable public C API (no WebKit internals), so it's version-robust. Two +bugs surfaced on Windows and are fixed in the vendored shim: +- **UTF-16 read truncation**: `CopyTo` did `memcpy(buf, chars, size)` where `size` is a count of + 2-byte `JSChar` → copied half the bytes (`'hi'`→`'h'`). Fixed to `size * sizeof(JSChar)`. +- **napi functions weren't constructors**: `FunctionInfo`'s `JSClassDefinition` set `callAsFunction` + but not `callAsConstructor`, so a JS `Proxy` over them wasn't a constructor (`new + Windows.Data.Json.JsonObject()` → "not a constructor"). Added a `CallAsConstructor` callback (the + JSC analog of the QuickJS `JS_SetConstructorBit` fix; V8's napi functions are constructable by + default). +Also `EXTERN_C` on the JSR bring-up decls (`jsr_common.h`) so the Rust host's `extern "C"` resolves. diff --git a/packages/windows-jsc/build.rs b/packages/windows-jsc/build.rs new file mode 100644 index 0000000..80fa21b --- /dev/null +++ b/packages/windows-jsc/build.rs @@ -0,0 +1,45 @@ +//! Compiles the napi-android JSC shim (jsc-api.cpp + jsr.cpp) over JavaScriptCore's **public C API** +//! (no WebKit internals / WTF), so it builds against just the vendored `JavaScriptCore/*.h` headers. +//! The shim compile-verifies with no engine binary present (`cargo build --lib`). The runnable bin +//! (`--features jsc_link`) additionally links `vendor/x64/JavaScriptCore.lib` — drop the WinCairo +//! `JavaScriptCore.dll`/`.lib` there (see README) to build/run it. +use std::path::PathBuf; + +fn main() { + let manifest = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); + let vendor = manifest.join("vendor"); + + let mut shim = cc::Build::new(); + shim.cpp(true) + .include(vendor.join("include")) // JavaScriptCore/*.h (public C API) + .include(vendor.join("napi")) // js_native_api.h etc. + .file(vendor.join("shim/jsc-api.cpp")) + .file(vendor.join("shim/jsr.cpp")) + .warnings(false); + if shim.get_compiler().is_like_msvc() { + shim.flag("/std:c++17") + // jsc-api.cpp uses (deprecated in C++17, still provided by MSVC under this). + .define("_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING", None) + .define("WIN32_LEAN_AND_MEAN", None) + .define("_CRT_SECURE_NO_WARNINGS", None); + } else { + shim.std("c++17"); + } + shim.compile("jsc_napi_shim"); + + // Runnable bin: link the (user-provided) JavaScriptCore import lib + copy the DLL beside the exe. + if std::env::var("CARGO_FEATURE_JSC_LINK").is_ok() { + let libdir = vendor.join("x64"); + println!("cargo:rustc-link-search=native={}", libdir.display()); + println!("cargo:rustc-link-lib=dylib=JavaScriptCore"); + let out = PathBuf::from(std::env::var("OUT_DIR").unwrap()); + if let Some(profile_dir) = out.ancestors().nth(3) { + for dll in ["JavaScriptCore.dll", "icuin77.dll", "icuuc77.dll", "icudt77.dll"] { + let _ = std::fs::copy(libdir.join(dll), profile_dir.join(dll)); + } + } + } + + println!("cargo:rerun-if-changed=vendor/shim/jsc-api.cpp"); + println!("cargo:rerun-if-changed=vendor/shim/jsr.cpp"); +} diff --git a/packages/windows-jsc/package.json b/packages/windows-jsc/package.json new file mode 100644 index 0000000..574c808 --- /dev/null +++ b/packages/windows-jsc/package.json @@ -0,0 +1,43 @@ +{ + "name": "@nativescript/windows-jsc", + "version": "0.1.0", + "description": "NativeScript Windows runtime (JavaScriptCore engine) with a WinUI 3 app template", + "keywords": [ + "NativeScript", + "Windows", + "WinRT", + "WinUI3", + "windows-app-sdk", + "runtime", + "jsc" + ], + "repository": { + "type": "git", + "url": "https://github.com/NativeScript/windows-runtime", + "directory": "packages/windows-jsc" + }, + "author": { + "name": "NativeScript Team", + "email": "oss@nativescript.org" + }, + "license": "Apache-2.0", + "os": [ + "win32" + ], + "cpu": [ + "x64" + ], + "scripts": { + "build": "pwsh -File ../../template/build.ps1 -Engine jsc" + }, + "files": [ + "framework/**/*", + "!framework/**/bin/**", + "!framework/**/obj/**", + "README.md" + ], + "nativescript": { + "runtime": "windows", + "engine": "jsc" + } +} diff --git a/packages/windows-jsc/src/abi.rs b/packages/windows-jsc/src/abi.rs new file mode 100644 index 0000000..00dd5e3 --- /dev/null +++ b/packages/windows-jsc/src/abi.rs @@ -0,0 +1,175 @@ +//! `nativescript.dll` C ABI for the JavaScriptCore engine — the WinUI 3 .NET host P/Invokes +//! exactly this surface (`runtime_init`, `runtime_runscript`, `runtime_pump_timers`, …), identical +//! to the classic V8 runtime's DLL, so an app swaps `@nativescript/windows` for +//! `@nativescript/windows-jsc` with no code change. Built into the cdylib only under the +//! `host_dll` feature (`build.ps1 -Engine jsc`, which links a real JavaScriptCore.{lib,dll} from +//! vendor/x64); the default build still produces the standalone `nativescript-windows.exe`. +//! +//! Same shape as the reference (`windows-quickjs/src/abi.rs`): the engine-neutral work (WinRT +//! init, globals, `Windows` namespace, event-loop turn) lives in `runtime::napi_engine::host_abi`; +//! the three engine-specific pieces (create the env, evaluate a script, drain microtasks) come +//! from `crate::host`. + +use std::cell::Cell; +use std::ffi::{c_char, c_int, c_void, CStr, CString}; + +use napi::Env; +use runtime::napi_engine::host_abi; + +use crate::host; + +thread_local! { + /// The JSC `napi_env` for this thread, captured at `runtime_init`. `runtime_pump_timers` takes + /// no handle (the classic ABI is stateless there), so the env is kept thread-local for the + /// pump to reach it. + static HOST_ENV: Cell<*mut c_void> = const { Cell::new(std::ptr::null_mut()) }; +} + +fn host_env() -> Option<*mut c_void> { + let raw = HOST_ENV.with(|c| c.get()); + (!raw.is_null()).then_some(raw) +} + +/// Create the runtime on JSC and bring WinRT up. Returns a non-zero handle on success (the classic +/// host treats `0` as failure). `app_root` is accepted for ABI parity. +#[no_mangle] +pub extern "C" fn runtime_init(app_root: *const c_char) -> i64 { + let result = std::panic::catch_unwind(|| unsafe { + // Populate napi-sys's symbol table from THIS module's own napi_* (the statically-linked, + // dllexported shim). Resolving this module rather than the process .exe requires the + // vendored napi-sys patch (packages/vendor/napi-sys): stock napi-sys queries + // GetModuleHandleExW(0, NULL) = the .NET host .exe, which exports no napi_*, so every call + // would abort ("Node-API symbol has not been loaded"). Validated by a C# P/Invoke harness + // (LoadLibrary nativescript.dll → runtime_init → real WinRT round-trip). + std::mem::forget(napi::sys::setup()); + + let app_root = if app_root.is_null() { + String::new() + } else { + CStr::from_ptr(app_root).to_string_lossy().into_owned() + }; + + let raw = host::shared_env_ptr(); + if raw.is_null() { + return 0; + } + let env = Env::from_raw(raw as napi::sys::napi_env); + // JSC's JSGlobalObject ships a built-in console that is inert without a ConsoleClient + // attached; drop it so initialize_runtime's install-if-missing check installs the + // runtime's real console instead. + let _ = host::run_script_checked(raw, "delete globalThis.console;"); + if host_abi::initialize_runtime(&env, &app_root).is_err() { + return 0; + } + // Engine-specific JS setup that needs the engine's own eval: URL polyfill + runtime prelude + // (queueMicrotask + NSWinRT.toPromise over the loop keep-alive natives). + if let Err(e) = host::run_script_checked(raw, ns_windows_common::url_polyfill::POLYFILL) { + runtime::store_last_js_error(format!("[url_polyfill] {e}")); + } + if let Err(e) = host::run_script_checked(raw, ns_windows_common::prelude::PRELUDE) { + runtime::store_last_js_error(format!("[prelude] {e}")); + } + + HOST_ENV.with(|c| c.set(raw)); + // A stable non-zero token; per-instance state is process-global (one leaked runtime), so + // the handle only needs to be truthy and round-trip through the host. + 1 + }); + result.unwrap_or(0) +} + +#[no_mangle] +pub extern "C" fn runtime_deinit(_runtime: i64) { + // The JSC runtime + env are process-lifetime (leaked, as a real host keeps them); nothing + // per-call to free. Present for ABI parity with the classic runtime. + HOST_ENV.with(|c| c.set(std::ptr::null_mut())); +} + +#[no_mangle] +pub extern "C" fn runtime_runscript( + _runtime: i64, + script: *const c_char, + _filename: *const c_char, +) { + if script.is_null() { + return; + } + let _ = std::panic::catch_unwind(|| unsafe { + if let Some(raw) = host_env() { + let code = CStr::from_ptr(script).to_string_lossy(); + if let Err(e) = host::run_script_checked(raw, &code) { + eprintln!("[NativeScript] script error: {e}"); + runtime::store_last_js_error(e); + } + } + }); +} + +/// Drive one turn of the event loop (timers, WinRT async completions, microtasks). The WinUI 3 +/// host calls this each frame from `CompositionTarget.Rendering`. +#[no_mangle] +pub extern "C" fn runtime_pump_timers() { + let _ = std::panic::catch_unwind(|| unsafe { + if let Some(raw) = host_env() { + let env = Env::from_raw(raw as napi::sys::napi_env); + let mut drain = || host::drain_microtasks(raw); + host_abi::pump_once(&env, &mut drain); + } + }); +} + +/// Forward a host lifecycle event into JS via `globalThis.__nsOnAppEvent(kind, message)`. +#[no_mangle] +pub extern "C" fn runtime_notify_app_event(_runtime: i64, kind: c_int, message: *const c_char) { + let _ = std::panic::catch_unwind(|| unsafe { + if let Some(raw) = host_env() { + let msg = if message.is_null() { + "null".to_string() + } else { + let m = CStr::from_ptr(message).to_string_lossy().replace('`', "\\`"); + format!("`{m}`") + }; + let code = format!( + "typeof __nsOnAppEvent==='function' && __nsOnAppEvent({kind}, {msg})" + ); + let _ = host::run_script_checked(raw, &code); + } + }); +} + +#[no_mangle] +pub extern "C" fn runtime_set_local_folder(path: *const c_char) { + if path.is_null() { + return; + } + let s = unsafe { CStr::from_ptr(path) }.to_string_lossy().into_owned(); + runtime::set_log_dir(s); +} + +#[no_mangle] +pub extern "C" fn runtime_install_ctrlc_handler(_exit_code: i32) { + // No-op on the engine hosts: the WinUI 3 process owns Ctrl+C. Present for ABI parity. +} + +#[no_mangle] +pub extern "C" fn runtime_has_devtools() -> bool { + false +} + +/// Returns the last JS error (message + stack) or NULL. Caller frees with `runtime_free_js_error`. +#[no_mangle] +pub extern "C" fn runtime_get_last_js_error() -> *mut c_char { + match runtime::get_last_js_error() { + Some(s) => CString::new(s) + .map(|c| c.into_raw()) + .unwrap_or(std::ptr::null_mut()), + None => std::ptr::null_mut(), + } +} + +#[no_mangle] +pub extern "C" fn runtime_free_js_error(ptr: *mut c_char) { + if !ptr.is_null() { + drop(unsafe { CString::from_raw(ptr) }); + } +} diff --git a/packages/windows-jsc/src/lib.rs b/packages/windows-jsc/src/lib.rs new file mode 100644 index 0000000..55b1d11 --- /dev/null +++ b/packages/windows-jsc/src/lib.rs @@ -0,0 +1,118 @@ +//! `@nativescript/windows-jsc` — NativeScript Windows runtime on JavaScriptCore. +//! +//! The napi provider is napi-android's JSC shim (`vendor/shim/jsc-api.cpp` + `jsr.cpp`), which is +//! implemented purely over JavaScriptCore's **public C API** (``), so +//! it compiles against just the vendored public headers — no WebKit internals or WTF. `build.rs` +//! compiles it (this verifies the MSVC port with no engine binary present). The runnable bin needs +//! a real `JavaScriptCore.dll`/`.lib` in `vendor/x64` (feature `jsc_link`); see the package README. + +/// FFI to the shim's JSR bring-up (available once the engine is linked via `jsc_link`). +#[cfg(feature = "jsc_link")] +pub mod ffi { + use napi::sys::{napi_env, napi_value}; + use std::os::raw::c_char; + + /// Opaque `napi_runtime__*` from the shim. + pub type NapiRuntime = *mut std::ffi::c_void; + + extern "C" { + pub fn js_create_runtime(runtime: *mut NapiRuntime) -> i32; + pub fn js_create_napi_env(env: *mut napi_env, runtime: NapiRuntime) -> i32; + pub fn js_execute_script( + env: napi_env, + script: napi_value, + file: *const c_char, + result: *mut napi_value, + ) -> i32; + /// Drain hook for the event loop. A no-op in the JSC shim: JSC drains its microtask + /// queue itself whenever the VM returns to the host. + pub fn js_execute_pending_jobs(env: napi_env) -> i32; + } +} + +// The `nativescript.dll` C ABI (WinUI 3 host DLL), compiled only under the `host_dll` feature +// (which enables `jsc_link`, so a real JavaScriptCore.{lib,dll} must be present in vendor/x64). +#[cfg(feature = "host_dll")] +pub mod abi; + +/// The three engine-specific pieces the `nativescript.dll` adapter needs: create the JSC engine + +/// its `napi_env`, evaluate a script string, and drain microtasks. Mirrors the QuickJS package's +/// `shim` surface (`shared_env_ptr` / `run_script_checked` / `drain_microtasks`) so `abi.rs` reads +/// the same across engines. Gated behind `host_dll` — the standalone bin (`main.rs`) keeps its own +/// copies so the validated host path is untouched. +#[cfg(feature = "host_dll")] +pub mod host { + use std::cell::Cell; + use std::ffi::{c_void, CString}; + + use napi::{Env, JsUnknown, NapiRaw, NapiValue}; + + use crate::ffi; + + /// The process-lifetime JSC `napi_env` as a raw pointer. Creates the VM + env on first call + /// (both process-lifetime, as a real host keeps them), then caches the env thread-local. + /// Returns null on failure. + pub fn shared_env_ptr() -> *mut c_void { + thread_local! { + static ENV: Cell<*mut c_void> = const { Cell::new(std::ptr::null_mut()) }; + } + ENV.with(|e| { + let cur = e.get(); + if !cur.is_null() { + return cur; + } + unsafe { + let mut runtime: ffi::NapiRuntime = std::ptr::null_mut(); + let mut env_raw: napi::sys::napi_env = std::ptr::null_mut(); + if ffi::js_create_runtime(&mut runtime) != 0 + || ffi::js_create_napi_env(&mut env_raw, runtime) != 0 + || env_raw.is_null() + { + return std::ptr::null_mut(); + } + e.set(env_raw as *mut c_void); + env_raw as *mut c_void + } + }) + } + + /// Evaluate `code`, returning its string coercion or the thrown exception's message. + pub fn run_script_checked(raw: *mut c_void, code: &str) -> Result { + unsafe { + let env = Env::from_raw(raw as napi::sys::napi_env); + let source = env.create_string(code).map_err(|e| e.to_string())?; + let file = CString::new("