@nativescript/windows-quickjs 0.1.0-alpha.0 → 0.1.0-alpha.140
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/README.md +3 -27
- package/framework/__PROJECT_NAME__/App.xaml +13 -13
- package/framework/__PROJECT_NAME__/Package.appxmanifest +35 -35
- package/framework/__PROJECT_NAME__/Program.cs +34 -34
- package/framework/__PROJECT_NAME__/Properties/Default.rd.xml +9 -9
- package/framework/__PROJECT_NAME__/RuntimeHost.cs +67 -11
- package/framework/__PROJECT_NAME__/__PROJECT_NAME__.csproj +6 -1
- package/framework/dotnet-bridge/BinaryProtocol.cs +161 -161
- package/framework/dotnet-bridge/Bridge.JsDelegate.cs +244 -244
- package/framework/dotnet-bridge/Bridge.TaskHelper.cs +207 -207
- package/framework/dotnet-bridge/DispatchTypes.cs +333 -333
- package/framework/dotnet-bridge/DotNetBridge.csproj +30 -30
- package/framework/libs/x64/nativescript.dll +0 -0
- package/framework/tools/ManifestMerger/ManifestMerger.dll +0 -0
- package/framework/tools/ManifestMerger/ManifestMerger.pdb +0 -0
- package/framework/tools/dotnet-tool-arm64.exe +0 -0
- package/framework/tools/dotnet-tool-x64.exe +0 -0
- package/framework/tools/dotnet-tool.exe +0 -0
- package/framework/tools/dotnet-typings-gen/dotnet-typings-gen.dll +0 -0
- package/framework/tools/dotnet-typings-gen/dotnet-typings-gen.exe +0 -0
- package/framework/tools/dotnet-typings-gen/dotnet-typings-gen.pdb +0 -0
- package/framework/tools/nsbundle_pack-x64.exe +0 -0
- package/framework/tools/nsbundle_pack.exe +0 -0
- package/framework/tools/sbg-arm64.exe +0 -0
- package/framework/tools/sbg-x64.exe +0 -0
- package/framework/tools/sbg.exe +0 -0
- package/framework/tools/typings-generator-arm64.exe +0 -0
- package/framework/tools/typings-generator-x64.exe +0 -0
- package/framework/tools/typings-generator.exe +0 -0
- package/package.json +43 -43
|
@@ -1,333 +1,333 @@
|
|
|
1
|
-
using System;
|
|
2
|
-
using System.Buffers;
|
|
3
|
-
using System.Collections;
|
|
4
|
-
using System.Collections.Concurrent;
|
|
5
|
-
using System.Collections.Generic;
|
|
6
|
-
using System.Linq.Expressions;
|
|
7
|
-
using System.Reflection;
|
|
8
|
-
using System.Text.Json;
|
|
9
|
-
using System.Text.Json.Serialization;
|
|
10
|
-
using System.Threading;
|
|
11
|
-
using System.Threading.Tasks;
|
|
12
|
-
|
|
13
|
-
namespace NativeScriptBridge;
|
|
14
|
-
|
|
15
|
-
[JsonSerializable(typeof(InvokeRequest))]
|
|
16
|
-
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
|
|
17
|
-
internal partial class BridgeJsonContext : JsonSerializerContext { }
|
|
18
|
-
|
|
19
|
-
internal sealed record InvokeRequest(
|
|
20
|
-
string? Assembly,
|
|
21
|
-
string? TypeName,
|
|
22
|
-
string? Method,
|
|
23
|
-
int? Handle,
|
|
24
|
-
JsonElement[]? Args
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
//
|
|
28
|
-
// Using Type as the key field (rather than Type.FullName) is correct and faster:
|
|
29
|
-
// Type instances are singletons within an AssemblyLoadContext, so reference
|
|
30
|
-
// equality and reference hash codes are sufficient and allocation-free.
|
|
31
|
-
|
|
32
|
-
internal readonly record struct MethodKey(Type Type, string Name, int ArgCount, BindingFlags Flags);
|
|
33
|
-
internal readonly record struct PropKey(Type Type, string Name, BindingFlags Flags);
|
|
34
|
-
internal readonly record struct CtorKey(Type Type, int ArgCount);
|
|
35
|
-
|
|
36
|
-
internal readonly struct DispatchEntry(Func<object?, object?[], object?>? invoke, ParameterInfo[] parameters)
|
|
37
|
-
{
|
|
38
|
-
public readonly Func<object?, object?[], object?>? Invoke = invoke;
|
|
39
|
-
public readonly ParameterInfo[] Parameters = parameters;
|
|
40
|
-
public static readonly DispatchEntry Empty = new(null, []);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
internal readonly struct CtorEntry(ConstructorInfo? ctor, ParameterInfo[] parameters)
|
|
44
|
-
{
|
|
45
|
-
public readonly ConstructorInfo? Ctor = ctor;
|
|
46
|
-
public readonly ParameterInfo[] Parameters = parameters;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
internal enum DispatchKind : byte { Void, Primitive, Handle, Collection, Members, TaskHandle }
|
|
50
|
-
|
|
51
|
-
internal readonly struct DispatchResult
|
|
52
|
-
{
|
|
53
|
-
public static readonly DispatchResult Void =
|
|
54
|
-
new(DispatchKind.Void, null, null, 0, null, null, null, null, null);
|
|
55
|
-
|
|
56
|
-
private readonly DispatchKind _kind;
|
|
57
|
-
private readonly object? _value;
|
|
58
|
-
private readonly Type? _type;
|
|
59
|
-
private readonly int _handle;
|
|
60
|
-
private readonly string? _typeName;
|
|
61
|
-
private readonly string[]? _methods;
|
|
62
|
-
private readonly string[]? _properties;
|
|
63
|
-
private readonly string[]? _staticMethods;
|
|
64
|
-
private readonly string[]? _staticProperties;
|
|
65
|
-
private readonly string[]? _readonlyProperties;
|
|
66
|
-
private readonly string[]? _readonlyStaticProperties;
|
|
67
|
-
private readonly string[]? _writeonlyProperties;
|
|
68
|
-
private readonly string[]? _writeonlyStaticProperties;
|
|
69
|
-
|
|
70
|
-
private DispatchResult(DispatchKind kind, object? value, Type? type, int handle,
|
|
71
|
-
string? typeName, string[]? methods, string[]? props,
|
|
72
|
-
string[]? staticMethods, string[]? staticProps,
|
|
73
|
-
string[]? readonlyProps = null, string[]? readonlyStaticProps = null,
|
|
74
|
-
string[]? writeonlyProps = null, string[]? writeonlyStaticProps = null)
|
|
75
|
-
{
|
|
76
|
-
_kind = kind; _value = value; _type = type; _handle = handle;
|
|
77
|
-
_typeName = typeName; _methods = methods; _properties = props;
|
|
78
|
-
_staticMethods = staticMethods; _staticProperties = staticProps;
|
|
79
|
-
_readonlyProperties = readonlyProps; _readonlyStaticProperties = readonlyStaticProps;
|
|
80
|
-
_writeonlyProperties = writeonlyProps; _writeonlyStaticProperties = writeonlyStaticProps;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
public static DispatchResult Primitive(object value, Type type)
|
|
84
|
-
=> new(DispatchKind.Primitive, value, type, 0, null, null, null, null, null);
|
|
85
|
-
|
|
86
|
-
public static DispatchResult Handle(int id, string typeName)
|
|
87
|
-
=> new(DispatchKind.Handle, null, null, id, typeName, null, null, null, null);
|
|
88
|
-
|
|
89
|
-
public static DispatchResult TaskHandle(int id, string typeName)
|
|
90
|
-
=> new(DispatchKind.TaskHandle, null, null, id, typeName, null, null, null, null);
|
|
91
|
-
|
|
92
|
-
public static DispatchResult Collection(IEnumerable items)
|
|
93
|
-
=> new(DispatchKind.Collection, items, null, 0, null, null, null, null, null);
|
|
94
|
-
|
|
95
|
-
public static DispatchResult Members(
|
|
96
|
-
string[] methods, string[] props, string[] staticMethods, string[] staticProps,
|
|
97
|
-
string[] readonlyProps, string[] readonlyStaticProps,
|
|
98
|
-
string[] writeonlyProps, string[] writeonlyStaticProps)
|
|
99
|
-
=> new(DispatchKind.Members, null, null, 0, null,
|
|
100
|
-
methods, props, staticMethods, staticProps,
|
|
101
|
-
readonlyProps, readonlyStaticProps, writeonlyProps, writeonlyStaticProps);
|
|
102
|
-
|
|
103
|
-
internal int HandleId() => _handle;
|
|
104
|
-
|
|
105
|
-
public void WriteTo(Utf8JsonWriter w, JsonSerializerOptions opts)
|
|
106
|
-
{
|
|
107
|
-
switch (_kind)
|
|
108
|
-
{
|
|
109
|
-
case DispatchKind.Void:
|
|
110
|
-
w.WriteNullValue();
|
|
111
|
-
break;
|
|
112
|
-
|
|
113
|
-
case DispatchKind.Primitive:
|
|
114
|
-
JsonSerializer.Serialize(w, _value, _type!, opts);
|
|
115
|
-
break;
|
|
116
|
-
|
|
117
|
-
case DispatchKind.Handle:
|
|
118
|
-
w.WriteStartObject();
|
|
119
|
-
w.WriteNumber("__handle"u8, _handle);
|
|
120
|
-
w.WriteString("__type"u8, _typeName);
|
|
121
|
-
// If the bridge has a canonical native pointer for this handle,
|
|
122
|
-
// expose it as a hex string so the runtime can detect and use it.
|
|
123
|
-
if (Bridge.s_nativePtrs.TryGetValue(_handle, out var nativePtr))
|
|
124
|
-
{
|
|
125
|
-
try
|
|
126
|
-
{
|
|
127
|
-
w.WriteString("__native_ptr"u8, nativePtr.ToInt64().ToString("x"));
|
|
128
|
-
}
|
|
129
|
-
catch
|
|
130
|
-
{
|
|
131
|
-
// ignore formatting errors
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
w.WriteEndObject();
|
|
135
|
-
break;
|
|
136
|
-
|
|
137
|
-
case DispatchKind.TaskHandle:
|
|
138
|
-
w.WriteStartObject();
|
|
139
|
-
w.WriteNumber("__handle"u8, _handle);
|
|
140
|
-
w.WriteString("__type"u8, _typeName);
|
|
141
|
-
w.WriteBoolean("__isTask"u8, true);
|
|
142
|
-
w.WriteEndObject();
|
|
143
|
-
break;
|
|
144
|
-
|
|
145
|
-
case DispatchKind.Collection:
|
|
146
|
-
w.WriteStartArray();
|
|
147
|
-
foreach (var item in (IEnumerable)_value!)
|
|
148
|
-
JsonSerializer.Serialize(w, item, item?.GetType() ?? typeof(object), opts);
|
|
149
|
-
w.WriteEndArray();
|
|
150
|
-
break;
|
|
151
|
-
|
|
152
|
-
case DispatchKind.Members:
|
|
153
|
-
w.WriteStartObject();
|
|
154
|
-
WriteStringArray(w, "methods"u8, _methods!);
|
|
155
|
-
WriteStringArray(w, "properties"u8, _properties!);
|
|
156
|
-
WriteStringArray(w, "staticMethods"u8, _staticMethods!);
|
|
157
|
-
WriteStringArray(w, "staticProperties"u8, _staticProperties!);
|
|
158
|
-
WriteStringArray(w, "readonlyProperties"u8, _readonlyProperties!);
|
|
159
|
-
WriteStringArray(w, "readonlyStaticProperties"u8, _readonlyStaticProperties!);
|
|
160
|
-
WriteStringArray(w, "writeonlyProperties"u8, _writeonlyProperties!);
|
|
161
|
-
WriteStringArray(w, "writeonlyStaticProperties"u8,_writeonlyStaticProperties!);
|
|
162
|
-
w.WriteEndObject();
|
|
163
|
-
break;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
private static void WriteStringArray(Utf8JsonWriter w, ReadOnlySpan<byte> name, string[] arr)
|
|
168
|
-
{
|
|
169
|
-
w.WriteStartArray(name);
|
|
170
|
-
foreach (var s in arr) w.WriteStringValue(s);
|
|
171
|
-
w.WriteEndArray();
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
//
|
|
175
|
-
// Response tags:
|
|
176
|
-
// 0x00 = null 0x01 = false 0x02 = true
|
|
177
|
-
// 0x03 = i32[4] 0x04 = f64[8] 0x05 = string[u32+utf8]
|
|
178
|
-
// 0x06 = handle[i32 + u16+utf8 type]
|
|
179
|
-
// 0x07 = array[u32 count + N tagged items]
|
|
180
|
-
// 0x08 = members{ methods, props, staticMethods, staticProps }
|
|
181
|
-
// 0xFF = error[u32+utf8]
|
|
182
|
-
|
|
183
|
-
public void WriteAsBin(ArrayBufferWriter<byte> outBuf)
|
|
184
|
-
{
|
|
185
|
-
var w = new BinWriter(outBuf);
|
|
186
|
-
switch (_kind)
|
|
187
|
-
{
|
|
188
|
-
case DispatchKind.Void:
|
|
189
|
-
w.WriteByte(0x00);
|
|
190
|
-
break;
|
|
191
|
-
|
|
192
|
-
case DispatchKind.Primitive:
|
|
193
|
-
WritePrimitiveBin(ref w, _value!);
|
|
194
|
-
break;
|
|
195
|
-
|
|
196
|
-
case DispatchKind.Handle:
|
|
197
|
-
w.WriteByte(0x06);
|
|
198
|
-
w.WriteI32(_handle);
|
|
199
|
-
w.WriteString16(_typeName ?? "");
|
|
200
|
-
// Optionally include a canonical native pointer for this handle
|
|
201
|
-
// so binary clients (Rust runtime) can avoid an extra bridge
|
|
202
|
-
// round-trip when a COM pointer is available.
|
|
203
|
-
if (Bridge.s_nativePtrs.TryGetValue(_handle, out var nativePtr)) {
|
|
204
|
-
w.WriteByte(1);
|
|
205
|
-
w.WriteI64(nativePtr.ToInt64());
|
|
206
|
-
} else {
|
|
207
|
-
w.WriteByte(0);
|
|
208
|
-
}
|
|
209
|
-
break;
|
|
210
|
-
|
|
211
|
-
case DispatchKind.TaskHandle:
|
|
212
|
-
w.WriteByte(0x0C);
|
|
213
|
-
w.WriteI32(_handle);
|
|
214
|
-
w.WriteString16(_typeName ?? "");
|
|
215
|
-
if (Bridge.s_nativePtrs.TryGetValue(_handle, out var nativePtr2)) {
|
|
216
|
-
w.WriteByte(1);
|
|
217
|
-
w.WriteI64(nativePtr2.ToInt64());
|
|
218
|
-
} else {
|
|
219
|
-
w.WriteByte(0);
|
|
220
|
-
}
|
|
221
|
-
break;
|
|
222
|
-
|
|
223
|
-
case DispatchKind.Collection:
|
|
224
|
-
var items = new List<object?>();
|
|
225
|
-
foreach (var item in (IEnumerable)_value!) items.Add(item);
|
|
226
|
-
w.WriteByte(0x07);
|
|
227
|
-
w.WriteU32((uint)items.Count);
|
|
228
|
-
foreach (var item in items) WriteValueBin(ref w, item);
|
|
229
|
-
break;
|
|
230
|
-
|
|
231
|
-
case DispatchKind.Members:
|
|
232
|
-
w.WriteByte(0x08);
|
|
233
|
-
WriteStringArrayBin(ref w, _methods!);
|
|
234
|
-
WriteStringArrayBin(ref w, _properties!);
|
|
235
|
-
WriteStringArrayBin(ref w, _staticMethods!);
|
|
236
|
-
WriteStringArrayBin(ref w, _staticProperties!);
|
|
237
|
-
WriteStringArrayBin(ref w, _readonlyProperties!);
|
|
238
|
-
WriteStringArrayBin(ref w, _readonlyStaticProperties!);
|
|
239
|
-
WriteStringArrayBin(ref w, _writeonlyProperties!);
|
|
240
|
-
WriteStringArrayBin(ref w, _writeonlyStaticProperties!);
|
|
241
|
-
break;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
private static void WritePrimitiveBin(ref BinWriter w, object value)
|
|
246
|
-
{
|
|
247
|
-
switch (value)
|
|
248
|
-
{
|
|
249
|
-
case bool b: w.WriteByte(b ? (byte)0x02 : (byte)0x01); break;
|
|
250
|
-
case sbyte v: w.WriteByte(0x03); w.WriteI32(v); break;
|
|
251
|
-
case byte v: w.WriteByte(0x03); w.WriteI32(v); break;
|
|
252
|
-
case short v: w.WriteByte(0x03); w.WriteI32(v); break;
|
|
253
|
-
case ushort v: w.WriteByte(0x03); w.WriteI32(v); break;
|
|
254
|
-
case int v: w.WriteByte(0x03); w.WriteI32(v); break;
|
|
255
|
-
case uint v: w.WriteByte(0x04); w.WriteF64(v); break;
|
|
256
|
-
case long v: w.WriteByte(0x04); w.WriteF64(v); break;
|
|
257
|
-
case ulong v: w.WriteByte(0x04); w.WriteF64(v); break;
|
|
258
|
-
case float v: w.WriteByte(0x04); w.WriteF64(v); break;
|
|
259
|
-
case double v: w.WriteByte(0x04); w.WriteF64(v); break;
|
|
260
|
-
case decimal v: w.WriteByte(0x04); w.WriteF64((double)v); break;
|
|
261
|
-
case string s: w.WriteByte(0x05); w.WriteString32(s); break;
|
|
262
|
-
default: w.WriteByte(0x05); w.WriteString32(value.ToString() ?? ""); break;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
private static void WriteValueBin(ref BinWriter w, object? value)
|
|
267
|
-
{
|
|
268
|
-
if (value is null) { w.WriteByte(0x00); return; }
|
|
269
|
-
var t = value.GetType();
|
|
270
|
-
if (t.IsPrimitive || t == typeof(string) || t == typeof(decimal))
|
|
271
|
-
{
|
|
272
|
-
WritePrimitiveBin(ref w, value);
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
if (value is IEnumerable enumerable)
|
|
276
|
-
{
|
|
277
|
-
var items = new List<object?>();
|
|
278
|
-
foreach (var item in enumerable) items.Add(item);
|
|
279
|
-
w.WriteByte(0x07);
|
|
280
|
-
w.WriteU32((uint)items.Count);
|
|
281
|
-
foreach (var item in items) WriteValueBin(ref w, item);
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
var id = Interlocked.Increment(ref Bridge.s_nextHandle);
|
|
285
|
-
Bridge.s_handles[id] = value;
|
|
286
|
-
w.WriteByte(0x06);
|
|
287
|
-
w.WriteI32(id);
|
|
288
|
-
w.WriteString16(t.FullName ?? t.Name);
|
|
289
|
-
w.WriteByte(0); // no native ptr
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
private static void WriteStringArrayBin(ref BinWriter w, string[] arr)
|
|
293
|
-
{
|
|
294
|
-
w.WriteU16((ushort)arr.Length);
|
|
295
|
-
foreach (var s in arr) w.WriteString16(s);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
internal static class TaskResultCache
|
|
300
|
-
{
|
|
301
|
-
private static readonly ConcurrentDictionary<Type, Func<Task, object?>> s_cache = new();
|
|
302
|
-
|
|
303
|
-
public static object? GetResult(Task task)
|
|
304
|
-
{
|
|
305
|
-
var taskType = task.GetType();
|
|
306
|
-
if (!taskType.IsGenericType) return null;
|
|
307
|
-
var fn = s_cache.GetOrAdd(taskType, static t =>
|
|
308
|
-
{
|
|
309
|
-
var param = Expression.Parameter(typeof(Task));
|
|
310
|
-
Expression body = Expression.Property(Expression.Convert(param, t), "Result");
|
|
311
|
-
if (body.Type.IsValueType) body = Expression.Convert(body, typeof(object));
|
|
312
|
-
return Expression.Lambda<Func<Task, object?>>(body, param).Compile();
|
|
313
|
-
});
|
|
314
|
-
return fn(task);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
internal static class ValueTaskAsTaskCache
|
|
319
|
-
{
|
|
320
|
-
private static readonly ConcurrentDictionary<Type, Func<object, Task>> s_cache = new();
|
|
321
|
-
|
|
322
|
-
public static Task AsTask(Type valueTaskType, object vt)
|
|
323
|
-
{
|
|
324
|
-
var fn = s_cache.GetOrAdd(valueTaskType, static t =>
|
|
325
|
-
{
|
|
326
|
-
var param = Expression.Parameter(typeof(object));
|
|
327
|
-
var cast = Expression.Convert(param, t);
|
|
328
|
-
var call = Expression.Call(cast, t.GetMethod("AsTask")!);
|
|
329
|
-
return Expression.Lambda<Func<object, Task>>(call, param).Compile();
|
|
330
|
-
});
|
|
331
|
-
return fn(vt);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
1
|
+
using System;
|
|
2
|
+
using System.Buffers;
|
|
3
|
+
using System.Collections;
|
|
4
|
+
using System.Collections.Concurrent;
|
|
5
|
+
using System.Collections.Generic;
|
|
6
|
+
using System.Linq.Expressions;
|
|
7
|
+
using System.Reflection;
|
|
8
|
+
using System.Text.Json;
|
|
9
|
+
using System.Text.Json.Serialization;
|
|
10
|
+
using System.Threading;
|
|
11
|
+
using System.Threading.Tasks;
|
|
12
|
+
|
|
13
|
+
namespace NativeScriptBridge;
|
|
14
|
+
|
|
15
|
+
[JsonSerializable(typeof(InvokeRequest))]
|
|
16
|
+
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
|
|
17
|
+
internal partial class BridgeJsonContext : JsonSerializerContext { }
|
|
18
|
+
|
|
19
|
+
internal sealed record InvokeRequest(
|
|
20
|
+
string? Assembly,
|
|
21
|
+
string? TypeName,
|
|
22
|
+
string? Method,
|
|
23
|
+
int? Handle,
|
|
24
|
+
JsonElement[]? Args
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
//
|
|
28
|
+
// Using Type as the key field (rather than Type.FullName) is correct and faster:
|
|
29
|
+
// Type instances are singletons within an AssemblyLoadContext, so reference
|
|
30
|
+
// equality and reference hash codes are sufficient and allocation-free.
|
|
31
|
+
|
|
32
|
+
internal readonly record struct MethodKey(Type Type, string Name, int ArgCount, BindingFlags Flags);
|
|
33
|
+
internal readonly record struct PropKey(Type Type, string Name, BindingFlags Flags);
|
|
34
|
+
internal readonly record struct CtorKey(Type Type, int ArgCount);
|
|
35
|
+
|
|
36
|
+
internal readonly struct DispatchEntry(Func<object?, object?[], object?>? invoke, ParameterInfo[] parameters)
|
|
37
|
+
{
|
|
38
|
+
public readonly Func<object?, object?[], object?>? Invoke = invoke;
|
|
39
|
+
public readonly ParameterInfo[] Parameters = parameters;
|
|
40
|
+
public static readonly DispatchEntry Empty = new(null, []);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
internal readonly struct CtorEntry(ConstructorInfo? ctor, ParameterInfo[] parameters)
|
|
44
|
+
{
|
|
45
|
+
public readonly ConstructorInfo? Ctor = ctor;
|
|
46
|
+
public readonly ParameterInfo[] Parameters = parameters;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
internal enum DispatchKind : byte { Void, Primitive, Handle, Collection, Members, TaskHandle }
|
|
50
|
+
|
|
51
|
+
internal readonly struct DispatchResult
|
|
52
|
+
{
|
|
53
|
+
public static readonly DispatchResult Void =
|
|
54
|
+
new(DispatchKind.Void, null, null, 0, null, null, null, null, null);
|
|
55
|
+
|
|
56
|
+
private readonly DispatchKind _kind;
|
|
57
|
+
private readonly object? _value;
|
|
58
|
+
private readonly Type? _type;
|
|
59
|
+
private readonly int _handle;
|
|
60
|
+
private readonly string? _typeName;
|
|
61
|
+
private readonly string[]? _methods;
|
|
62
|
+
private readonly string[]? _properties;
|
|
63
|
+
private readonly string[]? _staticMethods;
|
|
64
|
+
private readonly string[]? _staticProperties;
|
|
65
|
+
private readonly string[]? _readonlyProperties;
|
|
66
|
+
private readonly string[]? _readonlyStaticProperties;
|
|
67
|
+
private readonly string[]? _writeonlyProperties;
|
|
68
|
+
private readonly string[]? _writeonlyStaticProperties;
|
|
69
|
+
|
|
70
|
+
private DispatchResult(DispatchKind kind, object? value, Type? type, int handle,
|
|
71
|
+
string? typeName, string[]? methods, string[]? props,
|
|
72
|
+
string[]? staticMethods, string[]? staticProps,
|
|
73
|
+
string[]? readonlyProps = null, string[]? readonlyStaticProps = null,
|
|
74
|
+
string[]? writeonlyProps = null, string[]? writeonlyStaticProps = null)
|
|
75
|
+
{
|
|
76
|
+
_kind = kind; _value = value; _type = type; _handle = handle;
|
|
77
|
+
_typeName = typeName; _methods = methods; _properties = props;
|
|
78
|
+
_staticMethods = staticMethods; _staticProperties = staticProps;
|
|
79
|
+
_readonlyProperties = readonlyProps; _readonlyStaticProperties = readonlyStaticProps;
|
|
80
|
+
_writeonlyProperties = writeonlyProps; _writeonlyStaticProperties = writeonlyStaticProps;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public static DispatchResult Primitive(object value, Type type)
|
|
84
|
+
=> new(DispatchKind.Primitive, value, type, 0, null, null, null, null, null);
|
|
85
|
+
|
|
86
|
+
public static DispatchResult Handle(int id, string typeName)
|
|
87
|
+
=> new(DispatchKind.Handle, null, null, id, typeName, null, null, null, null);
|
|
88
|
+
|
|
89
|
+
public static DispatchResult TaskHandle(int id, string typeName)
|
|
90
|
+
=> new(DispatchKind.TaskHandle, null, null, id, typeName, null, null, null, null);
|
|
91
|
+
|
|
92
|
+
public static DispatchResult Collection(IEnumerable items)
|
|
93
|
+
=> new(DispatchKind.Collection, items, null, 0, null, null, null, null, null);
|
|
94
|
+
|
|
95
|
+
public static DispatchResult Members(
|
|
96
|
+
string[] methods, string[] props, string[] staticMethods, string[] staticProps,
|
|
97
|
+
string[] readonlyProps, string[] readonlyStaticProps,
|
|
98
|
+
string[] writeonlyProps, string[] writeonlyStaticProps)
|
|
99
|
+
=> new(DispatchKind.Members, null, null, 0, null,
|
|
100
|
+
methods, props, staticMethods, staticProps,
|
|
101
|
+
readonlyProps, readonlyStaticProps, writeonlyProps, writeonlyStaticProps);
|
|
102
|
+
|
|
103
|
+
internal int HandleId() => _handle;
|
|
104
|
+
|
|
105
|
+
public void WriteTo(Utf8JsonWriter w, JsonSerializerOptions opts)
|
|
106
|
+
{
|
|
107
|
+
switch (_kind)
|
|
108
|
+
{
|
|
109
|
+
case DispatchKind.Void:
|
|
110
|
+
w.WriteNullValue();
|
|
111
|
+
break;
|
|
112
|
+
|
|
113
|
+
case DispatchKind.Primitive:
|
|
114
|
+
JsonSerializer.Serialize(w, _value, _type!, opts);
|
|
115
|
+
break;
|
|
116
|
+
|
|
117
|
+
case DispatchKind.Handle:
|
|
118
|
+
w.WriteStartObject();
|
|
119
|
+
w.WriteNumber("__handle"u8, _handle);
|
|
120
|
+
w.WriteString("__type"u8, _typeName);
|
|
121
|
+
// If the bridge has a canonical native pointer for this handle,
|
|
122
|
+
// expose it as a hex string so the runtime can detect and use it.
|
|
123
|
+
if (Bridge.s_nativePtrs.TryGetValue(_handle, out var nativePtr))
|
|
124
|
+
{
|
|
125
|
+
try
|
|
126
|
+
{
|
|
127
|
+
w.WriteString("__native_ptr"u8, nativePtr.ToInt64().ToString("x"));
|
|
128
|
+
}
|
|
129
|
+
catch
|
|
130
|
+
{
|
|
131
|
+
// ignore formatting errors
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
w.WriteEndObject();
|
|
135
|
+
break;
|
|
136
|
+
|
|
137
|
+
case DispatchKind.TaskHandle:
|
|
138
|
+
w.WriteStartObject();
|
|
139
|
+
w.WriteNumber("__handle"u8, _handle);
|
|
140
|
+
w.WriteString("__type"u8, _typeName);
|
|
141
|
+
w.WriteBoolean("__isTask"u8, true);
|
|
142
|
+
w.WriteEndObject();
|
|
143
|
+
break;
|
|
144
|
+
|
|
145
|
+
case DispatchKind.Collection:
|
|
146
|
+
w.WriteStartArray();
|
|
147
|
+
foreach (var item in (IEnumerable)_value!)
|
|
148
|
+
JsonSerializer.Serialize(w, item, item?.GetType() ?? typeof(object), opts);
|
|
149
|
+
w.WriteEndArray();
|
|
150
|
+
break;
|
|
151
|
+
|
|
152
|
+
case DispatchKind.Members:
|
|
153
|
+
w.WriteStartObject();
|
|
154
|
+
WriteStringArray(w, "methods"u8, _methods!);
|
|
155
|
+
WriteStringArray(w, "properties"u8, _properties!);
|
|
156
|
+
WriteStringArray(w, "staticMethods"u8, _staticMethods!);
|
|
157
|
+
WriteStringArray(w, "staticProperties"u8, _staticProperties!);
|
|
158
|
+
WriteStringArray(w, "readonlyProperties"u8, _readonlyProperties!);
|
|
159
|
+
WriteStringArray(w, "readonlyStaticProperties"u8, _readonlyStaticProperties!);
|
|
160
|
+
WriteStringArray(w, "writeonlyProperties"u8, _writeonlyProperties!);
|
|
161
|
+
WriteStringArray(w, "writeonlyStaticProperties"u8,_writeonlyStaticProperties!);
|
|
162
|
+
w.WriteEndObject();
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private static void WriteStringArray(Utf8JsonWriter w, ReadOnlySpan<byte> name, string[] arr)
|
|
168
|
+
{
|
|
169
|
+
w.WriteStartArray(name);
|
|
170
|
+
foreach (var s in arr) w.WriteStringValue(s);
|
|
171
|
+
w.WriteEndArray();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
//
|
|
175
|
+
// Response tags:
|
|
176
|
+
// 0x00 = null 0x01 = false 0x02 = true
|
|
177
|
+
// 0x03 = i32[4] 0x04 = f64[8] 0x05 = string[u32+utf8]
|
|
178
|
+
// 0x06 = handle[i32 + u16+utf8 type]
|
|
179
|
+
// 0x07 = array[u32 count + N tagged items]
|
|
180
|
+
// 0x08 = members{ methods, props, staticMethods, staticProps }
|
|
181
|
+
// 0xFF = error[u32+utf8]
|
|
182
|
+
|
|
183
|
+
public void WriteAsBin(ArrayBufferWriter<byte> outBuf)
|
|
184
|
+
{
|
|
185
|
+
var w = new BinWriter(outBuf);
|
|
186
|
+
switch (_kind)
|
|
187
|
+
{
|
|
188
|
+
case DispatchKind.Void:
|
|
189
|
+
w.WriteByte(0x00);
|
|
190
|
+
break;
|
|
191
|
+
|
|
192
|
+
case DispatchKind.Primitive:
|
|
193
|
+
WritePrimitiveBin(ref w, _value!);
|
|
194
|
+
break;
|
|
195
|
+
|
|
196
|
+
case DispatchKind.Handle:
|
|
197
|
+
w.WriteByte(0x06);
|
|
198
|
+
w.WriteI32(_handle);
|
|
199
|
+
w.WriteString16(_typeName ?? "");
|
|
200
|
+
// Optionally include a canonical native pointer for this handle
|
|
201
|
+
// so binary clients (Rust runtime) can avoid an extra bridge
|
|
202
|
+
// round-trip when a COM pointer is available.
|
|
203
|
+
if (Bridge.s_nativePtrs.TryGetValue(_handle, out var nativePtr)) {
|
|
204
|
+
w.WriteByte(1);
|
|
205
|
+
w.WriteI64(nativePtr.ToInt64());
|
|
206
|
+
} else {
|
|
207
|
+
w.WriteByte(0);
|
|
208
|
+
}
|
|
209
|
+
break;
|
|
210
|
+
|
|
211
|
+
case DispatchKind.TaskHandle:
|
|
212
|
+
w.WriteByte(0x0C);
|
|
213
|
+
w.WriteI32(_handle);
|
|
214
|
+
w.WriteString16(_typeName ?? "");
|
|
215
|
+
if (Bridge.s_nativePtrs.TryGetValue(_handle, out var nativePtr2)) {
|
|
216
|
+
w.WriteByte(1);
|
|
217
|
+
w.WriteI64(nativePtr2.ToInt64());
|
|
218
|
+
} else {
|
|
219
|
+
w.WriteByte(0);
|
|
220
|
+
}
|
|
221
|
+
break;
|
|
222
|
+
|
|
223
|
+
case DispatchKind.Collection:
|
|
224
|
+
var items = new List<object?>();
|
|
225
|
+
foreach (var item in (IEnumerable)_value!) items.Add(item);
|
|
226
|
+
w.WriteByte(0x07);
|
|
227
|
+
w.WriteU32((uint)items.Count);
|
|
228
|
+
foreach (var item in items) WriteValueBin(ref w, item);
|
|
229
|
+
break;
|
|
230
|
+
|
|
231
|
+
case DispatchKind.Members:
|
|
232
|
+
w.WriteByte(0x08);
|
|
233
|
+
WriteStringArrayBin(ref w, _methods!);
|
|
234
|
+
WriteStringArrayBin(ref w, _properties!);
|
|
235
|
+
WriteStringArrayBin(ref w, _staticMethods!);
|
|
236
|
+
WriteStringArrayBin(ref w, _staticProperties!);
|
|
237
|
+
WriteStringArrayBin(ref w, _readonlyProperties!);
|
|
238
|
+
WriteStringArrayBin(ref w, _readonlyStaticProperties!);
|
|
239
|
+
WriteStringArrayBin(ref w, _writeonlyProperties!);
|
|
240
|
+
WriteStringArrayBin(ref w, _writeonlyStaticProperties!);
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
private static void WritePrimitiveBin(ref BinWriter w, object value)
|
|
246
|
+
{
|
|
247
|
+
switch (value)
|
|
248
|
+
{
|
|
249
|
+
case bool b: w.WriteByte(b ? (byte)0x02 : (byte)0x01); break;
|
|
250
|
+
case sbyte v: w.WriteByte(0x03); w.WriteI32(v); break;
|
|
251
|
+
case byte v: w.WriteByte(0x03); w.WriteI32(v); break;
|
|
252
|
+
case short v: w.WriteByte(0x03); w.WriteI32(v); break;
|
|
253
|
+
case ushort v: w.WriteByte(0x03); w.WriteI32(v); break;
|
|
254
|
+
case int v: w.WriteByte(0x03); w.WriteI32(v); break;
|
|
255
|
+
case uint v: w.WriteByte(0x04); w.WriteF64(v); break;
|
|
256
|
+
case long v: w.WriteByte(0x04); w.WriteF64(v); break;
|
|
257
|
+
case ulong v: w.WriteByte(0x04); w.WriteF64(v); break;
|
|
258
|
+
case float v: w.WriteByte(0x04); w.WriteF64(v); break;
|
|
259
|
+
case double v: w.WriteByte(0x04); w.WriteF64(v); break;
|
|
260
|
+
case decimal v: w.WriteByte(0x04); w.WriteF64((double)v); break;
|
|
261
|
+
case string s: w.WriteByte(0x05); w.WriteString32(s); break;
|
|
262
|
+
default: w.WriteByte(0x05); w.WriteString32(value.ToString() ?? ""); break;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
private static void WriteValueBin(ref BinWriter w, object? value)
|
|
267
|
+
{
|
|
268
|
+
if (value is null) { w.WriteByte(0x00); return; }
|
|
269
|
+
var t = value.GetType();
|
|
270
|
+
if (t.IsPrimitive || t == typeof(string) || t == typeof(decimal))
|
|
271
|
+
{
|
|
272
|
+
WritePrimitiveBin(ref w, value);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (value is IEnumerable enumerable)
|
|
276
|
+
{
|
|
277
|
+
var items = new List<object?>();
|
|
278
|
+
foreach (var item in enumerable) items.Add(item);
|
|
279
|
+
w.WriteByte(0x07);
|
|
280
|
+
w.WriteU32((uint)items.Count);
|
|
281
|
+
foreach (var item in items) WriteValueBin(ref w, item);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
var id = Interlocked.Increment(ref Bridge.s_nextHandle);
|
|
285
|
+
Bridge.s_handles[id] = value;
|
|
286
|
+
w.WriteByte(0x06);
|
|
287
|
+
w.WriteI32(id);
|
|
288
|
+
w.WriteString16(t.FullName ?? t.Name);
|
|
289
|
+
w.WriteByte(0); // no native ptr
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private static void WriteStringArrayBin(ref BinWriter w, string[] arr)
|
|
293
|
+
{
|
|
294
|
+
w.WriteU16((ushort)arr.Length);
|
|
295
|
+
foreach (var s in arr) w.WriteString16(s);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
internal static class TaskResultCache
|
|
300
|
+
{
|
|
301
|
+
private static readonly ConcurrentDictionary<Type, Func<Task, object?>> s_cache = new();
|
|
302
|
+
|
|
303
|
+
public static object? GetResult(Task task)
|
|
304
|
+
{
|
|
305
|
+
var taskType = task.GetType();
|
|
306
|
+
if (!taskType.IsGenericType) return null;
|
|
307
|
+
var fn = s_cache.GetOrAdd(taskType, static t =>
|
|
308
|
+
{
|
|
309
|
+
var param = Expression.Parameter(typeof(Task));
|
|
310
|
+
Expression body = Expression.Property(Expression.Convert(param, t), "Result");
|
|
311
|
+
if (body.Type.IsValueType) body = Expression.Convert(body, typeof(object));
|
|
312
|
+
return Expression.Lambda<Func<Task, object?>>(body, param).Compile();
|
|
313
|
+
});
|
|
314
|
+
return fn(task);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
internal static class ValueTaskAsTaskCache
|
|
319
|
+
{
|
|
320
|
+
private static readonly ConcurrentDictionary<Type, Func<object, Task>> s_cache = new();
|
|
321
|
+
|
|
322
|
+
public static Task AsTask(Type valueTaskType, object vt)
|
|
323
|
+
{
|
|
324
|
+
var fn = s_cache.GetOrAdd(valueTaskType, static t =>
|
|
325
|
+
{
|
|
326
|
+
var param = Expression.Parameter(typeof(object));
|
|
327
|
+
var cast = Expression.Convert(param, t);
|
|
328
|
+
var call = Expression.Call(cast, t.GetMethod("AsTask")!);
|
|
329
|
+
return Expression.Lambda<Func<object, Task>>(call, param).Compile();
|
|
330
|
+
});
|
|
331
|
+
return fn(vt);
|
|
332
|
+
}
|
|
333
|
+
}
|