@nativescript/windows 0.1.0-alpha.8 → 0.1.0-alpha.81

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/build.ps1 +44 -2
  2. package/framework/__PROJECT_NAME__/App.xaml.cs +67 -22
  3. package/framework/__PROJECT_NAME__/Assets/SplashScreen.png +0 -0
  4. package/framework/__PROJECT_NAME__/Assets/Square150x150Logo.png +0 -0
  5. package/framework/__PROJECT_NAME__/Assets/Square44x44Logo.png +0 -0
  6. package/framework/__PROJECT_NAME__/Assets/StoreLogo.png +0 -0
  7. package/framework/__PROJECT_NAME__/Assets/Wide310x150Logo.png +0 -0
  8. package/framework/__PROJECT_NAME__/CrashDiagnostics.cs +262 -66
  9. package/framework/__PROJECT_NAME__/Directory.Build.props +15 -0
  10. package/framework/__PROJECT_NAME__/Directory.Build.targets +153 -0
  11. package/framework/__PROJECT_NAME__/Package.appxmanifest +2 -5
  12. package/framework/__PROJECT_NAME__/RuntimeHost.cs +97 -10
  13. package/framework/__PROJECT_NAME__/__PROJECT_NAME__.csproj +90 -17
  14. package/framework/dotnet-bridge/BinaryProtocol.cs +145 -0
  15. package/framework/dotnet-bridge/Bridge.BinaryDispatch.cs +216 -0
  16. package/framework/dotnet-bridge/Bridge.Dispatch.cs +468 -0
  17. package/framework/dotnet-bridge/Bridge.JsDelegate.cs +96 -0
  18. package/framework/dotnet-bridge/Bridge.TaskHelper.cs +207 -0
  19. package/framework/dotnet-bridge/Bridge.cs +402 -263
  20. package/framework/dotnet-bridge/DispatchTypes.cs +317 -0
  21. package/framework/dotnet-bridge/DotNetBridge.csproj +7 -1
  22. package/framework/libs/arm64/nativescript.dll +0 -0
  23. package/framework/libs/devtools/arm64/nativescript.dll +0 -0
  24. package/framework/libs/devtools/x64/nativescript.dll +0 -0
  25. package/framework/libs/x64/nativescript.dll +0 -0
  26. package/framework/tools/dotnet-tool-arm64.exe +0 -0
  27. package/framework/tools/dotnet-tool-x64.exe +0 -0
  28. package/framework/tools/dotnet-tool.exe +0 -0
  29. package/package.json +19 -19
@@ -0,0 +1,96 @@
1
+ using System;
2
+ using System.Buffers;
3
+ using System.Linq;
4
+ using System.Linq.Expressions;
5
+ using System.Reflection;
6
+ using System.Runtime.InteropServices;
7
+ using System.Threading;
8
+
9
+ namespace NativeScriptBridge;
10
+
11
+ public static partial class Bridge
12
+ {
13
+ // opcode 0x09: given a delegate type name (or "" for System.Action) and a
14
+ // JS callback id, compile a .NET delegate that serialises its parameters as
15
+ // binary and calls back into V8 via the s_jsInvoker function pointer.
16
+
17
+ private static DispatchResult CreateJsDelegate(string typeName, int callbackId)
18
+ {
19
+ var delegateType = string.IsNullOrEmpty(typeName)
20
+ ? typeof(Action)
21
+ : ResolveType(null, typeName)
22
+ ?? throw new TypeLoadException($"Delegate type not found: {typeName}");
23
+
24
+ var invokeMethod = delegateType.GetMethod("Invoke")
25
+ ?? throw new MissingMethodException($"No Invoke method on {delegateType}");
26
+
27
+ var parameters = invokeMethod.GetParameters();
28
+ var returnType = invokeMethod.ReturnType;
29
+
30
+ var paramExprs = parameters
31
+ .Select((p, i) => Expression.Parameter(p.ParameterType, p.Name ?? $"p{i}"))
32
+ .ToArray();
33
+
34
+ // object?[] args = new object?[] { (object?)p0, (object?)p1, … }
35
+ var objArgs = paramExprs.Select(p => (Expression)Expression.Convert(p, typeof(object)));
36
+ var argsArray = Expression.NewArrayInit(typeof(object), objArgs);
37
+
38
+ var callMethod = typeof(Bridge).GetMethod(
39
+ nameof(CallJsCallback),
40
+ BindingFlags.Static | BindingFlags.NonPublic)!;
41
+
42
+ var callExpr = Expression.Call(callMethod, Expression.Constant(callbackId), argsArray);
43
+
44
+ Expression body = returnType == typeof(void)
45
+ ? callExpr
46
+ : (Expression)Expression.Block(returnType, callExpr, Expression.Default(returnType));
47
+
48
+ var del = Expression.Lambda(delegateType, body, paramExprs).Compile();
49
+ return Box(del);
50
+ }
51
+
52
+ internal static unsafe void CallJsCallback(int id, object?[] args)
53
+ {
54
+ if (s_jsInvoker == null) return;
55
+
56
+ var buf = new ArrayBufferWriter<byte>(64);
57
+ var w = new BinWriter(buf);
58
+ w.WriteByte((byte)Math.Min(args.Length, 255));
59
+ foreach (var arg in args)
60
+ WriteCallbackArg(ref w, arg);
61
+
62
+ var bytes = buf.WrittenSpan;
63
+ byte* respPtr = null;
64
+ int respLen = 0;
65
+ fixed (byte* p = bytes)
66
+ s_jsInvoker(id, p, bytes.Length, &respPtr, &respLen);
67
+
68
+ // Response is only set for non-void delegates; free it when present.
69
+ if (respPtr != null && respLen > 0)
70
+ Marshal.FreeHGlobal((IntPtr)respPtr);
71
+ }
72
+
73
+ // Serialises a single delegate argument in response-binary tag format so
74
+ // the Rust side can reuse its existing bin_read_value parser.
75
+ private static void WriteCallbackArg(ref BinWriter w, object? arg)
76
+ {
77
+ if (arg is null) { w.WriteByte(0x00); return; }
78
+ if (arg is bool b) { w.WriteByte(b ? (byte)0x02 : (byte)0x01); return; }
79
+ if (arg is int i) { w.WriteByte(0x03); w.WriteI32(i); return; }
80
+ if (arg is uint u) { w.WriteByte(0x03); w.WriteI32((int)u); return; }
81
+ if (arg is long l) { w.WriteByte(0x04); w.WriteF64((double)l); return; }
82
+ if (arg is float f) { w.WriteByte(0x04); w.WriteF64((double)f); return; }
83
+ if (arg is double d){ w.WriteByte(0x04); w.WriteF64(d); return; }
84
+ if (arg is string s){ w.WriteByte(0x05); w.WriteString32(s); return; }
85
+
86
+ // Object: box in the handle map and send as a handle reference.
87
+ // The JS side receives {__handle, __type} which can be turned into a
88
+ // proxy via NSWinRT.dotnet.fromHandle(...).
89
+ var handleId = Interlocked.Increment(ref s_nextHandle);
90
+ s_handles[handleId] = arg;
91
+ var typeName = arg.GetType().FullName ?? arg.GetType().Name;
92
+ w.WriteByte(0x06);
93
+ w.WriteI32(handleId);
94
+ w.WriteString16(typeName); // u16 length prefix (matches bin_read_value tag 0x06)
95
+ }
96
+ }
@@ -0,0 +1,207 @@
1
+ using System;
2
+ using System.Collections.Concurrent;
3
+ using System.Collections.Generic;
4
+ using System.Linq;
5
+ using System.Linq.Expressions;
6
+ using System.Reflection;
7
+ using System.Threading.Tasks;
8
+
9
+ namespace NativeScriptBridge;
10
+
11
+ public static partial class Bridge
12
+ {
13
+ private static readonly ConcurrentDictionary<Type, Func<object, Task>?> s_awaitableCache = new();
14
+
15
+ internal static void ScheduleTaskContinuation(int handleId, int resolveId, int rejectId)
16
+ {
17
+ if (!s_handles.TryGetValue(handleId, out var obj) || obj is null)
18
+ throw new KeyNotFoundException($"Invalid handle {handleId}");
19
+
20
+ var task = GetTaskForAwaitable(obj)
21
+ ?? throw new InvalidOperationException(
22
+ $"Object of type {obj.GetType().FullName} is not awaitable. " +
23
+ $"Expected Task<T>, ValueTask<T>, IAsyncOperation<T>, or any type implementing GetAwaiter().");
24
+
25
+ task.ContinueWith(completed =>
26
+ {
27
+ s_handles.TryRemove(handleId, out _);
28
+ try
29
+ {
30
+ if (completed.IsFaulted)
31
+ {
32
+ var ex = completed.Exception?.InnerException ?? completed.Exception;
33
+ CallJsCallback(rejectId, [ex?.Message ?? "Task faulted"]);
34
+ }
35
+ else if (completed.IsCanceled)
36
+ {
37
+ CallJsCallback(rejectId, ["Task cancelled"]);
38
+ }
39
+ else
40
+ {
41
+ CallJsCallback(resolveId, [TaskResultCache.GetResult(completed)]);
42
+ }
43
+ }
44
+ catch (Exception ex)
45
+ {
46
+ CallJsCallback(rejectId, [ex.Message]);
47
+ }
48
+ }, TaskScheduler.Default);
49
+ }
50
+
51
+ private static Task? GetTaskForAwaitable(object obj)
52
+ {
53
+ if (obj is Task t) return t;
54
+ if (obj is ValueTask vt) return vt.AsTask();
55
+
56
+ var type = obj.GetType();
57
+ if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ValueTask<>))
58
+ return ValueTaskAsTaskCache.AsTask(type, obj);
59
+
60
+ var winrtTask = WinRtAsyncCache.TryGetTask(type, obj);
61
+ if (winrtTask != null) return winrtTask;
62
+
63
+ return s_awaitableCache.GetOrAdd(type, BuildAwaitableFactory)?.Invoke(obj);
64
+ }
65
+
66
+ private static Func<object, Task>? BuildAwaitableFactory(Type type)
67
+ {
68
+ var getAwaiter = type.GetMethod("GetAwaiter",
69
+ BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
70
+ if (getAwaiter is null) return null;
71
+
72
+ var awaiterType = getAwaiter.ReturnType;
73
+ var isCompleted = awaiterType.GetProperty("IsCompleted");
74
+ var getResult = awaiterType.GetMethod("GetResult",
75
+ BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
76
+ var onCompleted = awaiterType.GetMethod("UnsafeOnCompleted",
77
+ BindingFlags.Instance | BindingFlags.Public)
78
+ ?? awaiterType.GetMethod("OnCompleted",
79
+ BindingFlags.Instance | BindingFlags.Public);
80
+
81
+ if (isCompleted is null || onCompleted is null) return null;
82
+
83
+ return obj =>
84
+ {
85
+ var tcs = new TaskCompletionSource<object?>(
86
+ TaskCreationOptions.RunContinuationsAsynchronously);
87
+ try
88
+ {
89
+ var awaiter = getAwaiter.Invoke(obj, null);
90
+ if (awaiter is null) { tcs.SetResult(null); return tcs.Task; }
91
+
92
+ void Complete()
93
+ {
94
+ try
95
+ {
96
+ tcs.SetResult(getResult?.Invoke(awaiter, null));
97
+ }
98
+ catch (TargetInvocationException ex)
99
+ {
100
+ tcs.SetException(ex.InnerException ?? ex);
101
+ }
102
+ catch (Exception ex) { tcs.SetException(ex); }
103
+ }
104
+
105
+ if ((bool)(isCompleted.GetValue(awaiter) ?? false))
106
+ Complete();
107
+ else
108
+ onCompleted.Invoke(awaiter, [(Action)Complete]);
109
+ }
110
+ catch (Exception ex) { tcs.SetException(ex); }
111
+
112
+ return tcs.Task;
113
+ };
114
+ }
115
+ }
116
+
117
+ internal static class WinRtAsyncCache
118
+ {
119
+ private static readonly ConcurrentDictionary<Type, Func<object, Task>?> s_cache = new();
120
+
121
+ public static Task? TryGetTask(Type type, object obj)
122
+ => s_cache.GetOrAdd(type, BuildFactory)?.Invoke(obj);
123
+
124
+ private static Func<object, Task>? BuildFactory(Type type)
125
+ {
126
+ foreach (var iface in type.GetInterfaces())
127
+ {
128
+ var ifn = iface.FullName ?? "";
129
+ if (!ifn.StartsWith("Windows.Foundation.IAsync", StringComparison.Ordinal)) continue;
130
+
131
+ var completedProp = iface.GetProperty("Completed");
132
+ if (completedProp?.GetSetMethod() is not { } setter) continue;
133
+
134
+ var delegateType = completedProp.PropertyType;
135
+ var delegateInvoke = delegateType.GetMethod("Invoke");
136
+ if (delegateInvoke == null) continue;
137
+
138
+ var dp = delegateInvoke.GetParameters()
139
+ .Select(p => Expression.Parameter(p.ParameterType))
140
+ .ToArray();
141
+
142
+ if (iface.IsGenericType)
143
+ {
144
+ var resultType = iface.GetGenericArguments()[0];
145
+ var getResults = iface.GetMethod("GetResults");
146
+ if (getResults == null) continue;
147
+
148
+ var tcsType = typeof(TaskCompletionSource<>).MakeGenericType(resultType);
149
+ var taskProp = tcsType.GetProperty("Task")!;
150
+ var completeM = typeof(WinRtAsyncCache)
151
+ .GetMethod(nameof(CompleteResult), BindingFlags.NonPublic | BindingFlags.Static)!
152
+ .MakeGenericMethod(resultType);
153
+
154
+ return obj =>
155
+ {
156
+ var tcs = Activator.CreateInstance(tcsType, TaskCreationOptions.RunContinuationsAsynchronously)!;
157
+ var body = Expression.Call(completeM,
158
+ Expression.Constant(tcs),
159
+ Expression.Convert(dp[0], typeof(object)),
160
+ Expression.Convert(dp[1], typeof(int)),
161
+ Expression.Constant(getResults));
162
+ setter.Invoke(obj, [Expression.Lambda(delegateType, body, dp).Compile()]);
163
+ return (Task)taskProp.GetValue(tcs)!;
164
+ };
165
+ }
166
+ else
167
+ {
168
+ var completeM = typeof(WinRtAsyncCache)
169
+ .GetMethod(nameof(CompleteAction), BindingFlags.NonPublic | BindingFlags.Static)!;
170
+
171
+ return obj =>
172
+ {
173
+ var tcs = new TaskCompletionSource<object?>(TaskCreationOptions.RunContinuationsAsynchronously);
174
+ var body = Expression.Call(completeM,
175
+ Expression.Constant(tcs),
176
+ Expression.Convert(dp[1], typeof(int)));
177
+ setter.Invoke(obj, [Expression.Lambda(delegateType, body, dp).Compile()]);
178
+ return tcs.Task;
179
+ };
180
+ }
181
+ }
182
+ return null;
183
+ }
184
+
185
+ private static void CompleteResult<T>(object tcs, object sender, int status, MethodInfo getResults)
186
+ {
187
+ var typed = (TaskCompletionSource<T>)tcs;
188
+ try
189
+ {
190
+ if (status == 1)
191
+ typed.TrySetResult((T)getResults.Invoke(sender, null)!);
192
+ else if (status == 2)
193
+ typed.TrySetCanceled();
194
+ else
195
+ typed.TrySetException(new Exception($"WinRT async operation failed (status {status})"));
196
+ }
197
+ catch (TargetInvocationException ex) { typed.TrySetException(ex.InnerException ?? ex); }
198
+ catch (Exception ex) { typed.TrySetException(ex); }
199
+ }
200
+
201
+ private static void CompleteAction(TaskCompletionSource<object?> tcs, int status)
202
+ {
203
+ if (status == 1) tcs.TrySetResult(null);
204
+ else if (status == 2) tcs.TrySetCanceled();
205
+ else tcs.TrySetException(new Exception($"WinRT async action failed (status {status})"));
206
+ }
207
+ }