Line data Source code
1 : /*
2 : * @Description: wrapper
3 : * @Author: ekibun
4 : * @Date: 2020-09-19 22:07:47
5 : * @LastEditors: ekibun
6 : * @LastEditTime: 2020-12-02 11:14:03
7 : */
8 : part of '../flutter_qjs.dart';
9 :
10 2 : dynamic _parseJSException(Pointer<JSContext> ctx, [Pointer<JSValue>? perr]) {
11 2 : final e = perr ?? jsGetException(ctx);
12 : var err;
13 : try {
14 2 : err = _jsToDart(ctx, e);
15 : } catch (exception) {
16 : err = exception;
17 : }
18 1 : if (perr == null) jsFreeValue(ctx, e);
19 : return err;
20 : }
21 :
22 2 : void _definePropertyValue(
23 : Pointer<JSContext> ctx,
24 : Pointer<JSValue> obj,
25 : dynamic key,
26 : dynamic val, {
27 : Map<dynamic, Pointer<JSValue>>? cache,
28 : }) {
29 2 : final jsAtomVal = _dartToJs(ctx, key, cache: cache);
30 4 : final jsAtom = jsValueToAtom(ctx, jsAtomVal);
31 4 : jsDefinePropertyValue(
32 : ctx,
33 : obj,
34 : jsAtom,
35 2 : _dartToJs(ctx, val, cache: cache),
36 : JSProp.C_W_E,
37 : );
38 4 : jsFreeAtom(ctx, jsAtom);
39 2 : jsFreeValue(ctx, jsAtomVal);
40 : }
41 :
42 3 : Pointer<JSValue> _jsGetPropertyValue(
43 : Pointer<JSContext> ctx,
44 : Pointer<JSValue> obj,
45 : dynamic key, {
46 : Map<dynamic, Pointer<JSValue>>? cache,
47 : }) {
48 3 : final jsAtomVal = _dartToJs(ctx, key, cache: cache);
49 6 : final jsAtom = jsValueToAtom(ctx, jsAtomVal);
50 6 : final jsProp = jsGetProperty(ctx, obj, jsAtom);
51 6 : jsFreeAtom(ctx, jsAtom);
52 3 : jsFreeValue(ctx, jsAtomVal);
53 : return jsProp;
54 : }
55 :
56 3 : Pointer<JSValue> _dartToJs(Pointer<JSContext> ctx, dynamic val,
57 : {Map<dynamic, Pointer<JSValue>>? cache}) {
58 6 : if (val == null) return jsUNDEFINED();
59 3 : if (val is Error) return _dartToJs(ctx, JSError(val, val.stackTrace));
60 3 : if (val is Exception) return _dartToJs(ctx, JSError(val));
61 3 : if (val is JSError) {
62 4 : final ret = jsNewError(ctx);
63 2 : _definePropertyValue(ctx, ret, "name", "");
64 4 : _definePropertyValue(ctx, ret, "message", val.message);
65 4 : _definePropertyValue(ctx, ret, "stack", val.stack);
66 : return ret;
67 : }
68 12 : if (val is _JSObject) return jsDupValue(ctx, val._val!);
69 3 : if (val is Future) {
70 9 : final resolvingFunc = malloc<Uint8>(sizeOfJSValue * 2).cast<JSValue>();
71 : final resolvingFunc2 =
72 12 : Pointer<JSValue>.fromAddress(resolvingFunc.address + sizeOfJSValue);
73 6 : final ret = jsNewPromiseCapability(ctx, resolvingFunc);
74 3 : final _JSFunction res = _jsToDart(ctx, resolvingFunc);
75 3 : final _JSFunction rej = _jsToDart(ctx, resolvingFunc2);
76 3 : jsFreeValue(ctx, resolvingFunc, free: false);
77 3 : jsFreeValue(ctx, resolvingFunc2, free: false);
78 3 : malloc.free(resolvingFunc);
79 3 : final refRes = _DartObject(ctx, res);
80 3 : final refRej = _DartObject(ctx, rej);
81 3 : res.free();
82 3 : rej.free();
83 6 : val.then((value) {
84 6 : res.invoke([value]);
85 2 : }, onError: (e) {
86 4 : rej.invoke([e]);
87 6 : }).whenComplete(() {
88 3 : refRes.free();
89 3 : refRej.free();
90 : });
91 : return ret;
92 : }
93 3 : if (cache == null) cache = Map();
94 7 : if (val is bool) return jsNewBool(ctx, val ? 1 : 0);
95 7 : if (val is int) return jsNewInt64(ctx, val);
96 7 : if (val is double) return jsNewFloat64(ctx, val);
97 6 : if (val is String) return jsNewString(ctx, val);
98 3 : if (val is Uint8List) {
99 0 : final ptr = malloc<Uint8>(val.length);
100 0 : final byteList = ptr.asTypedList(val.length);
101 0 : byteList.setAll(0, val);
102 0 : final ret = jsNewArrayBufferCopy(ctx, ptr, val.length);
103 0 : malloc.free(ptr);
104 : return ret;
105 : }
106 3 : if (cache.containsKey(val)) {
107 6 : return jsDupValue(ctx, cache[val]!);
108 : }
109 3 : if (val is List) {
110 4 : final ret = jsNewArray(ctx);
111 2 : cache[val] = ret;
112 6 : for (int i = 0; i < val.length; ++i) {
113 4 : _definePropertyValue(ctx, ret, i, val[i], cache: cache);
114 : }
115 : return ret;
116 : }
117 3 : if (val is Map) {
118 4 : final ret = jsNewObject(ctx);
119 2 : cache[val] = ret;
120 4 : for (MapEntry<dynamic, dynamic> entry in val.entries) {
121 6 : _definePropertyValue(ctx, ret, entry.key, entry.value, cache: cache);
122 : }
123 : return ret;
124 : }
125 : // wrap Function to JSInvokable
126 3 : final valWrap = JSInvokable._wrap(val);
127 : final dartObjectClassId =
128 15 : runtimeOpaques[jsGetRuntime(ctx)]?.dartObjectClassId ?? 0;
129 3 : if (dartObjectClassId == 0) return jsUNDEFINED();
130 6 : final dartObject = jsNewObjectClass(
131 : ctx,
132 : dartObjectClassId,
133 6 : identityHashCode(_DartObject(ctx, valWrap)),
134 : );
135 3 : if (valWrap is JSInvokable) {
136 6 : final ret = jsNewCFunction(ctx, dartObject);
137 3 : jsFreeValue(ctx, dartObject);
138 : return ret;
139 : }
140 : return dartObject;
141 : }
142 :
143 3 : dynamic _jsToDart(Pointer<JSContext> ctx, Pointer<JSValue> val,
144 : {Map<int, dynamic>? cache}) {
145 3 : if (cache == null) cache = Map();
146 6 : final tag = jsValueGetTag(val);
147 9 : if (jsTagIsFloat64(tag) != 0) {
148 4 : return jsToFloat64(ctx, val);
149 : }
150 : switch (tag) {
151 3 : case JSTag.BOOL:
152 6 : return jsToBool(ctx, val) != 0;
153 3 : case JSTag.INT:
154 4 : return jsToInt64(ctx, val);
155 3 : case JSTag.STRING:
156 3 : return jsToCString(ctx, val);
157 3 : case JSTag.OBJECT:
158 6 : final rt = jsGetRuntime(ctx);
159 9 : final dartObjectClassId = runtimeOpaques[rt]?.dartObjectClassId;
160 : if (dartObjectClassId != null) {
161 3 : final dartObject = _DartObject.fromAddress(
162 6 : rt, jsGetObjectOpaque(val, dartObjectClassId));
163 3 : if (dartObject != null) return dartObject._obj;
164 : }
165 : final psize = malloc<IntPtr>();
166 6 : final buf = jsGetArrayBuffer(ctx, psize, val);
167 3 : final size = psize.value;
168 3 : malloc.free(psize);
169 6 : if (buf.address != 0) {
170 0 : return Uint8List.fromList(buf.asTypedList(size));
171 : }
172 6 : final valptr = jsValueGetPtr(val);
173 3 : if (cache.containsKey(valptr)) {
174 2 : return cache[valptr];
175 : }
176 9 : if (jsIsFunction(ctx, val) != 0) {
177 3 : return _JSFunction(ctx, val);
178 9 : } else if (jsIsError(ctx, val) != 0) {
179 2 : final err = jsToCString(ctx, val);
180 2 : final pstack = _jsGetPropertyValue(ctx, val, 'stack');
181 : final stack =
182 8 : jsToBool(ctx, pstack) != 0 ? jsToCString(ctx, pstack) : null;
183 2 : jsFreeValue(ctx, pstack);
184 2 : return JSError(err, stack);
185 9 : } else if (jsIsPromise(ctx, val) != 0) {
186 3 : final jsPromiseThen = _jsGetPropertyValue(ctx, val, 'then');
187 : final _JSFunction promiseThen =
188 3 : _jsToDart(ctx, jsPromiseThen, cache: cache);
189 3 : jsFreeValue(ctx, jsPromiseThen);
190 3 : final completer = Completer();
191 8 : completer.future.catchError((e) {});
192 3 : final jsPromise = _JSObject(ctx, val);
193 6 : final jsRet = promiseThen._invoke([
194 3 : (v) {
195 3 : JSRef.dupRecursive(v);
196 6 : if (!completer.isCompleted) completer.complete(v);
197 : },
198 2 : (e) {
199 2 : JSRef.dupRecursive(e);
200 4 : if (!completer.isCompleted) completer.completeError(e);
201 : },
202 : ], jsPromise);
203 3 : jsPromise.free();
204 3 : promiseThen.free();
205 9 : final isException = jsIsException(jsRet) != 0;
206 3 : jsFreeValue(ctx, jsRet);
207 0 : if (isException) throw _parseJSException(ctx);
208 3 : return completer.future;
209 6 : } else if (jsIsArray(ctx, val) != 0) {
210 2 : final jslength = _jsGetPropertyValue(ctx, val, 'length');
211 4 : final length = jsToInt64(ctx, jslength);
212 2 : final ret = [];
213 2 : cache[valptr] = ret;
214 4 : for (var i = 0; i < length; ++i) {
215 2 : final jsProp = _jsGetPropertyValue(ctx, val, i);
216 4 : ret.add(_jsToDart(ctx, jsProp, cache: cache));
217 2 : jsFreeValue(ctx, jsProp);
218 : }
219 : return ret;
220 : } else {
221 : final ptab = malloc<Pointer<JSPropertyEnum>>();
222 : final plen = malloc<Uint32>();
223 8 : if (jsGetOwnPropertyNames(ctx, ptab, plen, val, -1) != 0) {
224 0 : malloc.free(plen);
225 0 : malloc.free(ptab);
226 : return null;
227 : }
228 2 : final len = plen.value;
229 2 : malloc.free(plen);
230 2 : final ret = Map();
231 2 : cache[valptr] = ret;
232 4 : for (var i = 0; i < len; ++i) {
233 6 : final jsAtom = jsPropertyEnumGetAtom(ptab.value, i);
234 4 : final jsAtomValue = jsAtomToValue(ctx, jsAtom);
235 4 : final jsProp = jsGetProperty(ctx, val, jsAtom);
236 4 : ret[_jsToDart(ctx, jsAtomValue, cache: cache)] =
237 2 : _jsToDart(ctx, jsProp, cache: cache);
238 2 : jsFreeValue(ctx, jsAtomValue);
239 2 : jsFreeValue(ctx, jsProp);
240 4 : jsFreeAtom(ctx, jsAtom);
241 : }
242 6 : jsFree(ctx, ptab.value);
243 2 : malloc.free(ptab);
244 : return ret;
245 : }
246 : default:
247 : }
248 : return null;
249 : }
|