Skip to content

Commit 6549151

Browse files
committed
add quickjs api bridge
1 parent b747f0f commit 6549151

File tree

10 files changed

+191
-1
lines changed

10 files changed

+191
-1
lines changed

Runtime/ReactUnity.asmdef

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"GUID:9a66a2efedc711946b7428ea9b41cc0d",
1010
"GUID:118b4ca3a1852354bac065cf952c1e85",
1111
"GUID:ac4126d60783f3d4a98aee6be9a997aa",
12-
"GUID:eda0539582471264796e5affb41fe082"
12+
"GUID:eda0539582471264796e5affb41fe082",
13+
"GUID:595d45be140461240b6b4358dc45f2c0"
1314
],
1415
"includePlatforms": [],
1516
"excludePlatforms": [],

Runtime/Scripting/QuickJS.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
#if !REACT_DISABLE_QUICKJS && REACT_QUICKJS_AVAILABLE && (!UNITY_WEBGL || UNITY_EDITOR)
2+
#define REACT_QUICKJS
3+
#endif
4+
5+
#if REACT_QUICKJS
6+
7+
using System;
8+
using System.Collections.Generic;
9+
using QuickJS;
10+
using QuickJS.Native;
11+
using QuickJS.Experimental;
12+
using QScriptContext = QuickJS.ScriptContext;
13+
14+
namespace ReactUnity.Scripting
15+
{
16+
public class QuickJSApiBridge : IJSApiBridge
17+
{
18+
public const string KeyForCSharpIdentity = "__csharp_host_identity__";
19+
20+
public JSPayloadHeader GetPayloadHeader(QScriptContext context, JSValue val)
21+
{
22+
JSContext ctx = context;
23+
bool valueDuplicated = false;
24+
25+
if (val.IsObject())
26+
{
27+
var identityAtom = context.GetAtom(KeyForCSharpIdentity);
28+
var identity = JSApi.JS_GetProperty(ctx, val, identityAtom);
29+
if (!identity.IsNullish())
30+
{
31+
val = identity;
32+
valueDuplicated = true;
33+
}
34+
}
35+
36+
var header = JSApi.jsb_get_payload_header(ctx, val);
37+
38+
if (valueDuplicated)
39+
{
40+
JSApi.JS_FreeValue(ctx, val);
41+
}
42+
return header;
43+
}
44+
45+
public JSValue NewBridgeObject(QScriptContext context, object o, JSValue proto)
46+
{
47+
var cache = context.GetObjectCache();
48+
var object_id = cache.AddObject(o, false);
49+
var val = JSApi.jsb_new_bridge_object(context, proto, object_id);
50+
51+
if (val.IsException())
52+
{
53+
cache.RemoveObject(object_id);
54+
}
55+
else
56+
{
57+
if (typeof(IDictionary<string, object>).IsAssignableFrom(o.GetType()))
58+
{
59+
var proxy = CreateDictionaryProxy(context, val);
60+
if (proxy.IsException())
61+
{
62+
JSApi.JS_FreeValue(context, proxy);
63+
cache.RemoveObject(object_id);
64+
return proxy;
65+
}
66+
val = proxy;
67+
}
68+
69+
cache.AddJSValue(o, val);
70+
}
71+
72+
return val;
73+
}
74+
75+
private static unsafe JSValue CreateDictionaryProxy(QScriptContext _context, JSValue target)
76+
{
77+
var ctx = (JSContext) _context;
78+
79+
var createDictionaryProxy = _context.EvalSource<ScriptFunction>(@"
80+
function createDictionaryProxy (targetProxy, contains, getter, setter, remover, keys) {
81+
return new Proxy(targetProxy, {
82+
get(target, key, receiver) {
83+
if(key === '" + KeyForCSharpIdentity + @"') return target;
84+
if(typeof key === 'string' && contains(target, key)) return getter(target, key);
85+
var res = target[key];
86+
return res;
87+
},
88+
set(target, key, value) {
89+
if(typeof key === 'string') setter(target, key, value);
90+
else target[key] = value;
91+
return true;
92+
},
93+
has(target, key) {
94+
return contains(target, key);
95+
},
96+
deleteProperty(target, key) {
97+
remover(target, key);
98+
return true;
99+
},
100+
ownKeys(target) {
101+
return keys(target);
102+
},
103+
getOwnPropertyDescriptor(target, key) {
104+
if(typeof key === 'string' && contains(target, key)) {
105+
return {
106+
value: getter(target, key),
107+
enumerable: true,
108+
configurable: true
109+
};
110+
}
111+
return undefined;
112+
},
113+
});
114+
}
115+
createDictionaryProxy;
116+
", "createDictionaryProxy");
117+
118+
var contains = new Func<IDictionary<string, object>, string, bool>(
119+
(IDictionary<string, object> dc, string key) => {
120+
return key != null && dc.ContainsKey(key);
121+
});
122+
123+
var getter = new Func<IDictionary<string, object>, string, object>(
124+
(IDictionary<string, object> dc, string key) => {
125+
return dc[key];
126+
});
127+
128+
var setter = new Action<IDictionary<string, object>, string, object>(
129+
(IDictionary<string, object> dc, string key, object value) => {
130+
dc[key] = value;
131+
});
132+
133+
var remover = new Action<IDictionary<string, object>, string>(
134+
(IDictionary<string, object> dc, string key) => {
135+
dc.Remove(key);
136+
});
137+
138+
var keys = new Func<IDictionary<string, object>, object>(
139+
(IDictionary<string, object> dc) => {
140+
var items = dc.Keys;
141+
var len = items.Count;
142+
var arr = new string[len];
143+
var i = 0;
144+
foreach (var item in items)
145+
arr[i++] = item;
146+
return arr;
147+
});
148+
149+
var prs = new object[] {
150+
target,
151+
contains,
152+
getter,
153+
setter,
154+
remover,
155+
keys,
156+
};
157+
158+
var _proxy = createDictionaryProxy.Invoke<ScriptValue>(prs);
159+
160+
var res = JSApi.JS_DupValue(ctx, _proxy);
161+
_proxy.Dispose();
162+
createDictionaryProxy.Dispose();
163+
JSApi.JS_FreeValue(ctx, target);
164+
return res;
165+
}
166+
}
167+
}
168+
169+
#endif

Runtime/Scripting/QuickJS/QuickJSApiBridge.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
File renamed without changes.
File renamed without changes.

Runtime/Scripting/QuickJSEngine.cs renamed to Runtime/Scripting/QuickJS/QuickJSEngine.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public QuickJSEngine(ReactContext context, bool debug, bool awaitDebugger, Actio
5555
debugServerPort = 9222,
5656
byteBufferAllocator = new QuickJS.IO.ByteBufferPooledAllocator(),
5757
pathResolver = new PathResolver(),
58+
apiBridge = new QuickJSApiBridge(),
5859
});
5960
}
6061

File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)