@nativescript/windows 0.1.0-alpha.57 → 0.1.0-alpha.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/framework/dotnet-bridge/Bridge.BinaryDispatch.cs +8 -0
- package/framework/dotnet-bridge/Bridge.Dispatch.cs +27 -1
- package/framework/dotnet-bridge/Bridge.TaskHelper.cs +121 -0
- package/framework/dotnet-bridge/DispatchTypes.cs +18 -1
- package/framework/libs/arm64/nativescript.dll +0 -0
- package/framework/libs/devtools/arm64/nativescript.dll +0 -0
- package/framework/libs/devtools/x64/nativescript.dll +0 -0
- package/framework/libs/x64/nativescript.dll +0 -0
- package/package.json +1 -1
|
@@ -65,6 +65,14 @@ public static partial class Bridge
|
|
|
65
65
|
var type = target?.GetType() ?? throw new InvalidOperationException("Handle is null");
|
|
66
66
|
var method = r.ReadString16();
|
|
67
67
|
var args = r.ReadArgs();
|
|
68
|
+
|
|
69
|
+
if (method == "__dotnet_await__" && args.Length == 2
|
|
70
|
+
&& args[0] is int resolveId && args[1] is int rejectId)
|
|
71
|
+
{
|
|
72
|
+
ScheduleTaskContinuation(handle, resolveId, rejectId);
|
|
73
|
+
return DispatchResult.Void;
|
|
74
|
+
}
|
|
75
|
+
|
|
68
76
|
return DispatchCallBin(target, type, method, args, isStatic: false);
|
|
69
77
|
}
|
|
70
78
|
|
|
@@ -42,6 +42,18 @@ public static partial class Bridge
|
|
|
42
42
|
if (method == "__members__")
|
|
43
43
|
return BuildMembersResult(type);
|
|
44
44
|
|
|
45
|
+
if (method == "__dotnet_await__" && req.Handle.HasValue)
|
|
46
|
+
{
|
|
47
|
+
var a = req.Args ?? [];
|
|
48
|
+
if (a.Length >= 2)
|
|
49
|
+
{
|
|
50
|
+
var resolveId = (int)a[0].GetInt64();
|
|
51
|
+
var rejectId = (int)a[1].GetInt64();
|
|
52
|
+
ScheduleTaskContinuation(req.Handle.Value, resolveId, rejectId);
|
|
53
|
+
}
|
|
54
|
+
return DispatchResult.Void;
|
|
55
|
+
}
|
|
56
|
+
|
|
45
57
|
if (method == ".ctor")
|
|
46
58
|
{
|
|
47
59
|
var argElems = req.Args ?? [];
|
|
@@ -228,7 +240,21 @@ public static partial class Bridge
|
|
|
228
240
|
|
|
229
241
|
var id = Interlocked.Increment(ref s_nextHandle);
|
|
230
242
|
s_handles[id] = value;
|
|
231
|
-
|
|
243
|
+
var typeName = t.FullName ?? t.Name;
|
|
244
|
+
return IsAwaitable(value, t)
|
|
245
|
+
? DispatchResult.TaskHandle(id, typeName)
|
|
246
|
+
: DispatchResult.Handle(id, typeName);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private static bool IsAwaitable(object value, Type t)
|
|
250
|
+
{
|
|
251
|
+
if (value is Task || value is ValueTask) return true;
|
|
252
|
+
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(ValueTask<>)) return true;
|
|
253
|
+
var fn = t.FullName ?? "";
|
|
254
|
+
if (fn.StartsWith("Windows.Foundation.IAsync", StringComparison.Ordinal)) return true;
|
|
255
|
+
return t.GetMethod("GetAwaiter",
|
|
256
|
+
BindingFlags.Public | BindingFlags.Instance,
|
|
257
|
+
null, Type.EmptyTypes, null) is not null;
|
|
232
258
|
}
|
|
233
259
|
|
|
234
260
|
internal static DispatchResult BuildMembersResult(Type t)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Concurrent;
|
|
3
|
+
using System.Collections.Generic;
|
|
4
|
+
using System.Reflection;
|
|
5
|
+
using System.Threading.Tasks;
|
|
6
|
+
|
|
7
|
+
namespace NativeScriptBridge;
|
|
8
|
+
|
|
9
|
+
public static partial class Bridge
|
|
10
|
+
{
|
|
11
|
+
private static readonly ConcurrentDictionary<Type, Func<object, Task>?> s_awaitableCache = new();
|
|
12
|
+
|
|
13
|
+
// Invoked when the binary instance call "__dotnet_await__(resolveId, rejectId)" arrives.
|
|
14
|
+
// Converts any awaitable handle (Task<T>, ValueTask<T>, IAsyncOperation<T>, …) into an
|
|
15
|
+
// async continuation that calls back into V8 via s_jsInvoker when it completes —
|
|
16
|
+
// without blocking the main thread.
|
|
17
|
+
internal static void ScheduleTaskContinuation(int handleId, int resolveId, int rejectId)
|
|
18
|
+
{
|
|
19
|
+
if (!s_handles.TryGetValue(handleId, out var obj) || obj is null)
|
|
20
|
+
throw new KeyNotFoundException($"Invalid handle {handleId}");
|
|
21
|
+
|
|
22
|
+
var task = GetTaskForAwaitable(obj)
|
|
23
|
+
?? throw new InvalidOperationException(
|
|
24
|
+
$"Object of type {obj.GetType().FullName} is not awaitable. " +
|
|
25
|
+
$"Expected Task<T>, ValueTask<T>, or any type implementing GetAwaiter().");
|
|
26
|
+
|
|
27
|
+
task.ContinueWith(completed =>
|
|
28
|
+
{
|
|
29
|
+
s_handles.TryRemove(handleId, out _);
|
|
30
|
+
try
|
|
31
|
+
{
|
|
32
|
+
if (completed.IsFaulted)
|
|
33
|
+
{
|
|
34
|
+
var ex = completed.Exception?.InnerException ?? completed.Exception;
|
|
35
|
+
CallJsCallback(rejectId, [ex?.Message ?? "Task faulted"]);
|
|
36
|
+
}
|
|
37
|
+
else if (completed.IsCanceled)
|
|
38
|
+
{
|
|
39
|
+
CallJsCallback(rejectId, ["Task cancelled"]);
|
|
40
|
+
}
|
|
41
|
+
else
|
|
42
|
+
{
|
|
43
|
+
CallJsCallback(resolveId, [TaskResultCache.GetResult(completed)]);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (Exception ex)
|
|
47
|
+
{
|
|
48
|
+
CallJsCallback(rejectId, [ex.Message]);
|
|
49
|
+
}
|
|
50
|
+
}, TaskScheduler.Default);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Converts any awaitable to a Task<object?> using the GetAwaiter() pattern via
|
|
54
|
+
// reflection. Handles Task<T>, ValueTask<T>, WinRT IAsyncOperation<T>, and any
|
|
55
|
+
// custom awaitable without requiring compile-time type knowledge. Results are
|
|
56
|
+
// cached per awaitable type so reflection only runs on the first encounter.
|
|
57
|
+
private static Task? GetTaskForAwaitable(object obj)
|
|
58
|
+
{
|
|
59
|
+
if (obj is Task t) return t;
|
|
60
|
+
if (obj is ValueTask vt) return vt.AsTask();
|
|
61
|
+
|
|
62
|
+
var type = obj.GetType();
|
|
63
|
+
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ValueTask<>))
|
|
64
|
+
return ValueTaskAsTaskCache.AsTask(type, obj);
|
|
65
|
+
|
|
66
|
+
return s_awaitableCache.GetOrAdd(type, BuildAwaitableFactory)?.Invoke(obj);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Builds a factory that wraps an arbitrary awaitable type in a
|
|
70
|
+
// TaskCompletionSource<object?>. Works for any type with GetAwaiter() returning
|
|
71
|
+
// an object that has IsCompleted, GetResult(), and OnCompleted/UnsafeOnCompleted.
|
|
72
|
+
private static Func<object, Task>? BuildAwaitableFactory(Type type)
|
|
73
|
+
{
|
|
74
|
+
var getAwaiter = type.GetMethod("GetAwaiter",
|
|
75
|
+
BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
|
|
76
|
+
if (getAwaiter is null) return null;
|
|
77
|
+
|
|
78
|
+
var awaiterType = getAwaiter.ReturnType;
|
|
79
|
+
var isCompleted = awaiterType.GetProperty("IsCompleted");
|
|
80
|
+
var getResult = awaiterType.GetMethod("GetResult",
|
|
81
|
+
BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
|
|
82
|
+
var onCompleted = awaiterType.GetMethod("UnsafeOnCompleted",
|
|
83
|
+
BindingFlags.Instance | BindingFlags.Public)
|
|
84
|
+
?? awaiterType.GetMethod("OnCompleted",
|
|
85
|
+
BindingFlags.Instance | BindingFlags.Public);
|
|
86
|
+
|
|
87
|
+
if (isCompleted is null || onCompleted is null) return null;
|
|
88
|
+
|
|
89
|
+
return obj =>
|
|
90
|
+
{
|
|
91
|
+
var tcs = new TaskCompletionSource<object?>(
|
|
92
|
+
TaskCreationOptions.RunContinuationsAsynchronously);
|
|
93
|
+
try
|
|
94
|
+
{
|
|
95
|
+
var awaiter = getAwaiter.Invoke(obj, null);
|
|
96
|
+
if (awaiter is null) { tcs.SetResult(null); return tcs.Task; }
|
|
97
|
+
|
|
98
|
+
void Complete()
|
|
99
|
+
{
|
|
100
|
+
try
|
|
101
|
+
{
|
|
102
|
+
tcs.SetResult(getResult?.Invoke(awaiter, null));
|
|
103
|
+
}
|
|
104
|
+
catch (System.Reflection.TargetInvocationException ex)
|
|
105
|
+
{
|
|
106
|
+
tcs.SetException(ex.InnerException ?? ex);
|
|
107
|
+
}
|
|
108
|
+
catch (Exception ex) { tcs.SetException(ex); }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if ((bool)(isCompleted.GetValue(awaiter) ?? false))
|
|
112
|
+
Complete();
|
|
113
|
+
else
|
|
114
|
+
onCompleted.Invoke(awaiter, [(Action)Complete]);
|
|
115
|
+
}
|
|
116
|
+
catch (Exception ex) { tcs.SetException(ex); }
|
|
117
|
+
|
|
118
|
+
return tcs.Task;
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -46,7 +46,7 @@ internal readonly struct CtorEntry(ConstructorInfo? ctor, ParameterInfo[] parame
|
|
|
46
46
|
public readonly ParameterInfo[] Parameters = parameters;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
internal enum DispatchKind : byte { Void, Primitive, Handle, Collection, Members }
|
|
49
|
+
internal enum DispatchKind : byte { Void, Primitive, Handle, Collection, Members, TaskHandle }
|
|
50
50
|
|
|
51
51
|
internal readonly struct DispatchResult
|
|
52
52
|
{
|
|
@@ -86,6 +86,9 @@ internal readonly struct DispatchResult
|
|
|
86
86
|
public static DispatchResult Handle(int id, string typeName)
|
|
87
87
|
=> new(DispatchKind.Handle, null, null, id, typeName, null, null, null, null);
|
|
88
88
|
|
|
89
|
+
public static DispatchResult TaskHandle(int id, string typeName)
|
|
90
|
+
=> new(DispatchKind.TaskHandle, null, null, id, typeName, null, null, null, null);
|
|
91
|
+
|
|
89
92
|
public static DispatchResult Collection(IEnumerable items)
|
|
90
93
|
=> new(DispatchKind.Collection, items, null, 0, null, null, null, null, null);
|
|
91
94
|
|
|
@@ -118,6 +121,14 @@ internal readonly struct DispatchResult
|
|
|
118
121
|
w.WriteEndObject();
|
|
119
122
|
break;
|
|
120
123
|
|
|
124
|
+
case DispatchKind.TaskHandle:
|
|
125
|
+
w.WriteStartObject();
|
|
126
|
+
w.WriteNumber("__handle"u8, _handle);
|
|
127
|
+
w.WriteString("__type"u8, _typeName);
|
|
128
|
+
w.WriteBoolean("__isTask"u8, true);
|
|
129
|
+
w.WriteEndObject();
|
|
130
|
+
break;
|
|
131
|
+
|
|
121
132
|
case DispatchKind.Collection:
|
|
122
133
|
w.WriteStartArray();
|
|
123
134
|
foreach (var item in (IEnumerable)_value!)
|
|
@@ -175,6 +186,12 @@ internal readonly struct DispatchResult
|
|
|
175
186
|
w.WriteString16(_typeName ?? "");
|
|
176
187
|
break;
|
|
177
188
|
|
|
189
|
+
case DispatchKind.TaskHandle:
|
|
190
|
+
w.WriteByte(0x0C);
|
|
191
|
+
w.WriteI32(_handle);
|
|
192
|
+
w.WriteString16(_typeName ?? "");
|
|
193
|
+
break;
|
|
194
|
+
|
|
178
195
|
case DispatchKind.Collection:
|
|
179
196
|
var items = new List<object?>();
|
|
180
197
|
foreach (var item in (IEnumerable)_value!) items.Add(item);
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|