mirror of
https://github.com/wgh136/flutter_qjs.git
synced 2025-09-27 13:27:24 +00:00
ffi wrapper
This commit is contained in:
263
cxx/ffi.cpp
Normal file
263
cxx/ffi.cpp
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
* @Description:
|
||||||
|
* @Author: ekibun
|
||||||
|
* @Date: 2020-09-06 18:32:45
|
||||||
|
* @LastEditors: ekibun
|
||||||
|
* @LastEditTime: 2020-09-20 15:50:41
|
||||||
|
*/
|
||||||
|
#include "quickjs/quickjs.h"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define DLLEXPORT __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define DLLEXPORT __attribute__((visibility("default")))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
typedef JSValue *JSChannel(JSContext *ctx, const char *method, JSValueConst *argv);
|
||||||
|
|
||||||
|
DLLEXPORT JSValue *jsEXCEPTION()
|
||||||
|
{
|
||||||
|
return new JSValue{JS_EXCEPTION};
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSValue *jsUNDEFINED()
|
||||||
|
{
|
||||||
|
return new JSValue{JS_UNDEFINED};
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSValue *jsNULL()
|
||||||
|
{
|
||||||
|
return new JSValue{JS_NULL};
|
||||||
|
}
|
||||||
|
|
||||||
|
JSModuleDef *js_module_loader(
|
||||||
|
JSContext *ctx,
|
||||||
|
const char *module_name, void *opaque)
|
||||||
|
{
|
||||||
|
JSRuntime *rt = JS_GetRuntime(ctx);
|
||||||
|
JSChannel *channel = (JSChannel *)JS_GetRuntimeOpaque(rt);
|
||||||
|
JSValue val = *channel(ctx, "__load_module__", new JSValue{JS_NewString(ctx, module_name)});
|
||||||
|
const char *str = JS_ToCString(ctx, val);
|
||||||
|
JSValue func_val = JS_Eval(ctx, str, strlen(str), module_name, JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
|
||||||
|
JS_FreeCString(ctx, str);
|
||||||
|
JS_FreeValue(ctx, val);
|
||||||
|
if (JS_IsException(func_val))
|
||||||
|
return NULL;
|
||||||
|
/* the module is already referenced, so we must free it */
|
||||||
|
JSModuleDef *m = (JSModuleDef *)JS_VALUE_GET_PTR(func_val);
|
||||||
|
JS_FreeValue(ctx, func_val);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue js_channel(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||||
|
{
|
||||||
|
JSRuntime *rt = JS_GetRuntime(ctx);
|
||||||
|
JSChannel *channel = (JSChannel *)JS_GetRuntimeOpaque(rt);
|
||||||
|
const char *str = JS_ToCString(ctx, argv[0]);
|
||||||
|
JS_DupValue(ctx, *(argv + 1));
|
||||||
|
JSValue ret = *channel(ctx, str, argv + 1);
|
||||||
|
JS_FreeValue(ctx, *(argv + 1));
|
||||||
|
JS_FreeCString(ctx, str);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSRuntime *jsNewRuntime(JSChannel channel)
|
||||||
|
{
|
||||||
|
JSRuntime *rt = JS_NewRuntime();
|
||||||
|
JS_SetRuntimeOpaque(rt, channel);
|
||||||
|
JS_SetModuleLoaderFunc(rt, nullptr, js_module_loader, nullptr);
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT void jsFreeRuntime(JSRuntime *rt)
|
||||||
|
{
|
||||||
|
JS_SetRuntimeOpaque(rt, nullptr);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSContext *jsNewContext(JSRuntime *rt)
|
||||||
|
{
|
||||||
|
JSContext *ctx = JS_NewContext(rt);
|
||||||
|
JSAtom atom = JS_NewAtom(ctx, "channel");
|
||||||
|
JSValue globalObject = JS_GetGlobalObject(ctx);
|
||||||
|
JS_SetProperty(ctx, globalObject, atom, JS_NewCFunction(ctx, js_channel, "channel", 2));
|
||||||
|
JS_FreeValue(ctx, globalObject);
|
||||||
|
JS_FreeAtom(ctx, atom);
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT void jsFreeContext(JSContext *ctx)
|
||||||
|
{
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSRuntime *jsGetRuntime(JSContext *ctx)
|
||||||
|
{
|
||||||
|
return JS_GetRuntime(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSValue *jsEval(JSContext *ctx, const char *input, size_t input_len, const char *filename, int eval_flags)
|
||||||
|
{
|
||||||
|
return new JSValue{JS_Eval(ctx, input, input_len, filename, eval_flags)};
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT int32_t jsValueGetTag(JSValue *val)
|
||||||
|
{
|
||||||
|
return JS_VALUE_GET_TAG(*val);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT void *jsValueGetPtr(JSValue *val)
|
||||||
|
{
|
||||||
|
return JS_VALUE_GET_PTR(*val);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT int32_t jsTagIsFloat64(int32_t tag)
|
||||||
|
{
|
||||||
|
return JS_TAG_IS_FLOAT64(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSValue *jsNewBool(JSContext *ctx, int val)
|
||||||
|
{
|
||||||
|
return new JSValue{JS_NewBool(ctx, val)};
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSValue *jsNewInt64(JSContext *ctx, int64_t val)
|
||||||
|
{
|
||||||
|
return new JSValue{JS_NewInt64(ctx, val)};
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSValue *jsNewFloat64(JSContext *ctx, double val)
|
||||||
|
{
|
||||||
|
return new JSValue{JS_NewFloat64(ctx, val)};
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSValue *jsNewString(JSContext *ctx, const char *str)
|
||||||
|
{
|
||||||
|
return new JSValue{JS_NewString(ctx, str)};
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSValue *jsNewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len)
|
||||||
|
{
|
||||||
|
return new JSValue{JS_NewArrayBufferCopy(ctx, buf, len)};
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSValue *jsNewArray(JSContext *ctx)
|
||||||
|
{
|
||||||
|
return new JSValue{JS_NewArray(ctx)};
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSValue *jsNewObject(JSContext *ctx)
|
||||||
|
{
|
||||||
|
return new JSValue{JS_NewObject(ctx)};
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT void jsFreeValue(JSContext *ctx, JSValue *v)
|
||||||
|
{
|
||||||
|
JS_FreeValue(ctx, *v);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT void jsFreeValueRT(JSRuntime *rt, JSValue *v)
|
||||||
|
{
|
||||||
|
JS_FreeValueRT(rt, *v);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSValue *jsDupValue(JSContext *ctx, JSValueConst *v)
|
||||||
|
{
|
||||||
|
return new JSValue{JS_DupValue(ctx, *v)};
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSValue *jsDupValueRT(JSRuntime *rt, JSValue *v)
|
||||||
|
{
|
||||||
|
return new JSValue{JS_DupValueRT(rt, *v)};
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT int32_t jsToBool(JSContext *ctx, JSValueConst *val)
|
||||||
|
{
|
||||||
|
return JS_ToBool(ctx, *val);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT int64_t jsToInt64(JSContext *ctx, JSValueConst *val)
|
||||||
|
{
|
||||||
|
int64_t p;
|
||||||
|
JS_ToInt64(ctx, &p, *val);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT double jsToFloat64(JSContext *ctx, JSValueConst *val)
|
||||||
|
{
|
||||||
|
double p;
|
||||||
|
JS_ToFloat64(ctx, &p, *val);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT const char *jsToCString(JSContext *ctx, JSValueConst *val)
|
||||||
|
{
|
||||||
|
return JS_ToCString(ctx, *val);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT void jsFreeCString(JSContext *ctx, const char *ptr)
|
||||||
|
{
|
||||||
|
return JS_FreeCString(ctx, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT uint8_t *jsGetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst *obj)
|
||||||
|
{
|
||||||
|
return JS_GetArrayBuffer(ctx, psize, *obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT int32_t jsIsFunction(JSContext *ctx, JSValueConst *val)
|
||||||
|
{
|
||||||
|
return JS_IsFunction(ctx, *val);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT int32_t jsIsArray(JSContext *ctx, JSValueConst *val)
|
||||||
|
{
|
||||||
|
return JS_IsArray(ctx, *val);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT void deleteJSValue(JSValueConst *val)
|
||||||
|
{
|
||||||
|
delete val;
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSValue *jsGetProperty(JSContext *ctx, JSValueConst *this_obj,
|
||||||
|
JSAtom prop)
|
||||||
|
{
|
||||||
|
return new JSValue{JS_GetProperty(ctx, *this_obj, prop)};
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT int jsDefinePropertyValue(JSContext *ctx, JSValueConst *this_obj,
|
||||||
|
JSAtom prop, JSValue *val, int flags)
|
||||||
|
{
|
||||||
|
return JS_DefinePropertyValue(ctx, *this_obj, prop, *val, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT void jsFreeAtom(JSContext *ctx, JSAtom v)
|
||||||
|
{
|
||||||
|
JS_FreeAtom(ctx, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSAtom jsValueToAtom(JSContext *ctx, JSValueConst *val)
|
||||||
|
{
|
||||||
|
return JS_ValueToAtom(ctx, *val);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSValue *jsAtomToValue(JSContext *ctx, JSAtom val)
|
||||||
|
{
|
||||||
|
return new JSValue{JS_AtomToValue(ctx, val)};
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT int jsGetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
|
||||||
|
uint32_t *plen, JSValueConst *obj, int flags)
|
||||||
|
{
|
||||||
|
return JS_GetOwnPropertyNames(ctx, ptab, plen, *obj, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT JSAtom jsPropertyEnumGetAtom(JSPropertyEnum *ptab, int i)
|
||||||
|
{
|
||||||
|
return ptab[i].atom;
|
||||||
|
}
|
||||||
|
}
|
594
lib/ffi.dart
Normal file
594
lib/ffi.dart
Normal file
@@ -0,0 +1,594 @@
|
|||||||
|
/*
|
||||||
|
* @Description:
|
||||||
|
* @Author: ekibun
|
||||||
|
* @Date: 2020-09-19 10:29:04
|
||||||
|
* @LastEditors: ekibun
|
||||||
|
* @LastEditTime: 2020-09-20 15:41:02
|
||||||
|
*/
|
||||||
|
import 'dart:ffi';
|
||||||
|
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
abstract class JSRef {
|
||||||
|
void release();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// JS_Eval() flags
|
||||||
|
class JSEvalType {
|
||||||
|
static const GLOBAL = 0 << 0;
|
||||||
|
static const MODULE = 1 << 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
class JSProp {
|
||||||
|
static const CONFIGURABLE = (1 << 0);
|
||||||
|
static const WRITABLE = (1 << 1);
|
||||||
|
static const ENUMERABLE = (1 << 2);
|
||||||
|
static const C_W_E = (CONFIGURABLE | WRITABLE | ENUMERABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
class JSTag {
|
||||||
|
static const FIRST = -11; /* first negative tag */
|
||||||
|
static const BIG_DECIMAL = -11;
|
||||||
|
static const BIG_INT = -10;
|
||||||
|
static const BIG_FLOAT = -9;
|
||||||
|
static const SYMBOL = -8;
|
||||||
|
static const STRING = -7;
|
||||||
|
static const MODULE = -3; /* used internally */
|
||||||
|
static const FUNCTION_BYTECODE = -2; /* used internally */
|
||||||
|
static const OBJECT = -1;
|
||||||
|
|
||||||
|
static const INT = 0;
|
||||||
|
static const BOOL = 1;
|
||||||
|
static const NULL = 2;
|
||||||
|
static const UNDEFINED = 3;
|
||||||
|
static const UNINITIALIZED = 4;
|
||||||
|
static const CATCH_OFFSET = 5;
|
||||||
|
static const EXCEPTION = 6;
|
||||||
|
static const FLOAT64 = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
final DynamicLibrary qjsLib = DynamicLibrary.open("test/lib/build/Debug/ffi_library.dll");
|
||||||
|
|
||||||
|
/// JSValue *jsEXCEPTION()
|
||||||
|
final Pointer Function() jsEXCEPTION =
|
||||||
|
qjsLib.lookup<NativeFunction<Pointer Function()>>("jsEXCEPTION").asFunction();
|
||||||
|
|
||||||
|
/// JSValue *jsUNDEFINED()
|
||||||
|
final Pointer Function() jsUNDEFINED =
|
||||||
|
qjsLib.lookup<NativeFunction<Pointer Function()>>("jsUNDEFINED").asFunction();
|
||||||
|
|
||||||
|
/// JSRuntime *jsNewRuntime(JSChannel channel)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer<NativeFunction<Pointer Function(Pointer ctx, Pointer method, Pointer argv)>>,
|
||||||
|
) _jsNewRuntime = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
)>>("jsNewRuntime")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
typedef JSChannel = Pointer Function(Pointer ctx, String method, Pointer argv);
|
||||||
|
|
||||||
|
class RuntimeOpaque {
|
||||||
|
JSChannel channel;
|
||||||
|
List<JSRef> ref = List();
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<Pointer, RuntimeOpaque> runtimeOpaques = Map();
|
||||||
|
|
||||||
|
Pointer channelDispacher(Pointer ctx, Pointer<Utf8> method, Pointer argv) {
|
||||||
|
return runtimeOpaques[jsGetRuntime(ctx)].channel(ctx, Utf8.fromUtf8(method), argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pointer jsNewRuntime(
|
||||||
|
JSChannel callback,
|
||||||
|
) {
|
||||||
|
var rt = _jsNewRuntime(Pointer.fromFunction(channelDispacher));
|
||||||
|
runtimeOpaques[rt] = RuntimeOpaque()..channel = callback;
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// void jsFreeRuntime(JSRuntime *rt)
|
||||||
|
final void Function(
|
||||||
|
Pointer,
|
||||||
|
) _jsFreeRuntime = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Void Function(
|
||||||
|
Pointer,
|
||||||
|
)>>("jsFreeRuntime")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
void jsFreeRuntime(
|
||||||
|
Pointer rt,
|
||||||
|
) {
|
||||||
|
runtimeOpaques[rt]?.ref?.forEach((val) {
|
||||||
|
val.release();
|
||||||
|
});
|
||||||
|
runtimeOpaques.remove(rt);
|
||||||
|
_jsFreeRuntime(rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// JSContext *jsNewContext(JSRuntime *rt)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer rt,
|
||||||
|
) jsNewContext = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
)>>("jsNewContext")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// void jsFreeContext(JSContext *ctx)
|
||||||
|
final void Function(
|
||||||
|
Pointer,
|
||||||
|
) jsFreeContext = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Void Function(
|
||||||
|
Pointer,
|
||||||
|
)>>("jsFreeContext")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// JSRuntime *jsGetRuntime(JSContext *ctx)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
) jsGetRuntime = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
)>>("jsGetRuntime")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// JSValue *jsEval(JSContext *ctx, const char *input, size_t input_len, const char *filename, int eval_flags)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer<Utf8> input,
|
||||||
|
int inputLen,
|
||||||
|
Pointer<Utf8> filename,
|
||||||
|
int evalFlags,
|
||||||
|
) _jsEval = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer<Utf8>,
|
||||||
|
Int64,
|
||||||
|
Pointer<Utf8>,
|
||||||
|
Int32,
|
||||||
|
)>>("jsEval")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
Pointer jsEval(
|
||||||
|
Pointer ctx,
|
||||||
|
String input,
|
||||||
|
String filename,
|
||||||
|
int evalFlags,
|
||||||
|
) {
|
||||||
|
var utf8input = Utf8.toUtf8(input);
|
||||||
|
var utf8filename = Utf8.toUtf8(filename);
|
||||||
|
var val = _jsEval(ctx, utf8input, Utf8.strlen(utf8input), utf8filename, evalFlags);
|
||||||
|
free(utf8input);
|
||||||
|
free(utf8filename);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// DLLEXPORT int32_t jsValueGetTag(JSValue *val)
|
||||||
|
final int Function(
|
||||||
|
Pointer val,
|
||||||
|
) jsValueGetTag = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Int32 Function(
|
||||||
|
Pointer,
|
||||||
|
)>>("jsValueGetTag")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// void *jsValueGetPtr(JSValue *val)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer val,
|
||||||
|
) jsValueGetPtr = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
)>>("jsValueGetPtr")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// DLLEXPORT bool jsTagIsFloat64(int32_t tag)
|
||||||
|
final int Function(
|
||||||
|
int val,
|
||||||
|
) jsTagIsFloat64 = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Int32 Function(
|
||||||
|
Int32,
|
||||||
|
)>>("jsTagIsFloat64")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// JSValue *jsNewBool(JSContext *ctx, int val)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer ctx,
|
||||||
|
int val,
|
||||||
|
) jsNewBool = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
Int32,
|
||||||
|
)>>("jsNewBool")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// JSValue *jsNewInt64(JSContext *ctx, int64_t val)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer ctx,
|
||||||
|
int val,
|
||||||
|
) jsNewInt64 = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
Int64,
|
||||||
|
)>>("jsNewInt64")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// JSValue *jsNewFloat64(JSContext *ctx, double val)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer ctx,
|
||||||
|
double val,
|
||||||
|
) jsNewFloat64 = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
Double,
|
||||||
|
)>>("jsNewFloat64")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// JSValue *jsNewString(JSContext *ctx, const char *str)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer<Utf8> str,
|
||||||
|
) _jsNewString = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer<Utf8>,
|
||||||
|
)>>("jsNewString")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
Pointer jsNewString(
|
||||||
|
Pointer ctx,
|
||||||
|
String str,
|
||||||
|
) {
|
||||||
|
var utf8str = Utf8.toUtf8(str);
|
||||||
|
return _jsNewString(ctx, utf8str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// JSValue *jsNewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer<Uint8> buf,
|
||||||
|
int len,
|
||||||
|
) jsNewArrayBufferCopy = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer<Uint8>,
|
||||||
|
Uint64,
|
||||||
|
)>>("jsNewArrayBufferCopy")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// JSValue *jsNewArray(JSContext *ctx)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer ctx,
|
||||||
|
) jsNewArray = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
)>>("jsNewArray")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// JSValue *jsNewObject(JSContext *ctx)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer ctx,
|
||||||
|
) jsNewObject = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
)>>("jsNewObject")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// void jsFreeValue(JSContext *ctx, JSValue *val)
|
||||||
|
final void Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer val,
|
||||||
|
) jsFreeValue = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Void Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer,
|
||||||
|
)>>("jsFreeValue")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// void jsFreeValueRT(JSRuntime *rt, JSValue *v)
|
||||||
|
final void Function(
|
||||||
|
Pointer rt,
|
||||||
|
Pointer val,
|
||||||
|
) jsFreeValueRT = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Void Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer,
|
||||||
|
)>>("jsFreeValueRT")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// JSValue *jsDupValue(JSContext *ctx, JSValueConst *v)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer val,
|
||||||
|
) jsDupValue = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer,
|
||||||
|
)>>("jsDupValue")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// JSValue *jsDupValueRT(JSRuntime *rt, JSValue *v)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer rt,
|
||||||
|
Pointer val,
|
||||||
|
) jsDupValueRT = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer,
|
||||||
|
)>>("jsDupValueRT")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// int32_t jsToBool(JSContext *ctx, JSValueConst *val)
|
||||||
|
final int Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer val,
|
||||||
|
) jsToBool = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Int32 Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer,
|
||||||
|
)>>("jsToBool")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// int64_t jsToFloat64(JSContext *ctx, JSValueConst *val)
|
||||||
|
final int Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer val,
|
||||||
|
) jsToInt64 = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Int64 Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer,
|
||||||
|
)>>("jsToInt64")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// double jsToFloat64(JSContext *ctx, JSValueConst *val)
|
||||||
|
final double Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer val,
|
||||||
|
) jsToFloat64 = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Double Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer,
|
||||||
|
)>>("jsToFloat64")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// const char *jsToCString(JSContext *ctx, JSValue *val)
|
||||||
|
final Pointer<Utf8> Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer val,
|
||||||
|
) _jsToCString = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer<Utf8> Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer,
|
||||||
|
)>>("jsToCString")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// void jsFreeCString(JSContext *ctx, const char *ptr)
|
||||||
|
final void Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer<Utf8> val,
|
||||||
|
) jsFreeCString = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Void Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer<Utf8>,
|
||||||
|
)>>("jsFreeCString")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
String jsToCString(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer val,
|
||||||
|
) {
|
||||||
|
var ptr = _jsToCString(ctx, val);
|
||||||
|
var str = Utf8.fromUtf8(ptr);
|
||||||
|
jsFreeCString(ctx, ptr);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// uint8_t *jsGetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst *obj)
|
||||||
|
final Pointer<Uint8> Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer<Int64> psize,
|
||||||
|
Pointer val,
|
||||||
|
) jsGetArrayBuffer = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer<Uint8> Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer<Int64>,
|
||||||
|
Pointer,
|
||||||
|
)>>("jsGetArrayBuffer")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// int32_t jsIsFunction(JSContext *ctx, JSValueConst *val)
|
||||||
|
final int Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer val,
|
||||||
|
) jsIsFunction = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Int32 Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer,
|
||||||
|
)>>("jsIsFunction")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// int32_t jsIsArray(JSContext *ctx, JSValueConst *val)
|
||||||
|
final int Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer val,
|
||||||
|
) jsIsArray = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Int32 Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer,
|
||||||
|
)>>("jsIsArray")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// void deleteJSValue(JSValueConst *val)
|
||||||
|
final void Function(
|
||||||
|
Pointer val,
|
||||||
|
) deleteJSValue = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Void Function(
|
||||||
|
Pointer,
|
||||||
|
)>>("deleteJSValue")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// JSValue *jsGetProperty(JSContext *ctx, JSValueConst *this_obj,
|
||||||
|
/// JSAtom prop)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer thisObj,
|
||||||
|
int prop,
|
||||||
|
) jsGetProperty = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer,
|
||||||
|
Uint32,
|
||||||
|
)>>("jsGetProperty")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// int jsDefinePropertyValue(JSContext *ctx, JSValueConst *this_obj,
|
||||||
|
/// JSAtom prop, JSValue *val, int flags)
|
||||||
|
final int Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer thisObj,
|
||||||
|
int prop,
|
||||||
|
Pointer val,
|
||||||
|
int flag
|
||||||
|
) jsDefinePropertyValue = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Int32 Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer,
|
||||||
|
Uint32,
|
||||||
|
Pointer,
|
||||||
|
Int32,
|
||||||
|
)>>("jsDefinePropertyValue")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// void jsFreeAtom(JSContext *ctx, JSAtom v)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer ctx,
|
||||||
|
int v,
|
||||||
|
) jsFreeAtom = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
Uint32,
|
||||||
|
)>>("jsFreeAtom")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// JSAtom jsValueToAtom(JSContext *ctx, JSValueConst *val)
|
||||||
|
final int Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer val,
|
||||||
|
) jsValueToAtom = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Uint32 Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer,
|
||||||
|
)>>("jsValueToAtom")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// JSValue *jsAtomToValue(JSContext *ctx, JSAtom val)
|
||||||
|
final Pointer Function(
|
||||||
|
Pointer ctx,
|
||||||
|
int val,
|
||||||
|
) jsAtomToValue = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Pointer Function(
|
||||||
|
Pointer,
|
||||||
|
Uint32,
|
||||||
|
)>>("jsAtomToValue")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// int jsGetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
|
||||||
|
/// uint32_t *plen, JSValueConst *obj, int flags)
|
||||||
|
final int Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer<Pointer> ptab,
|
||||||
|
Pointer<Uint32> plen,
|
||||||
|
Pointer obj,
|
||||||
|
int flags,
|
||||||
|
) jsGetOwnPropertyNames = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Int32 Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer<Pointer>,
|
||||||
|
Pointer<Uint32>,
|
||||||
|
Pointer,
|
||||||
|
Int32,
|
||||||
|
)>>("jsGetOwnPropertyNames")
|
||||||
|
.asFunction();
|
||||||
|
|
||||||
|
/// JSAtom jsPropertyEnumGetAtom(JSPropertyEnum *ptab, int i)
|
||||||
|
final int Function(
|
||||||
|
Pointer ptab,
|
||||||
|
int i,
|
||||||
|
) jsPropertyEnumGetAtom = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Uint32 Function(
|
||||||
|
Pointer,
|
||||||
|
Int32,
|
||||||
|
)>>("jsPropertyEnumGetAtom")
|
||||||
|
.asFunction();
|
177
lib/wrapper.dart
Normal file
177
lib/wrapper.dart
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
* @Description:
|
||||||
|
* @Author: ekibun
|
||||||
|
* @Date: 2020-09-19 22:07:47
|
||||||
|
* @LastEditors: ekibun
|
||||||
|
* @LastEditTime: 2020-09-20 15:41:16
|
||||||
|
*/
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
import 'ffi.dart';
|
||||||
|
|
||||||
|
class JSFunction extends JSRef {
|
||||||
|
Pointer val;
|
||||||
|
Pointer ctx;
|
||||||
|
JSFunction(this.ctx, Pointer val) {
|
||||||
|
Pointer rt = jsGetRuntime(ctx);
|
||||||
|
this.val = jsDupValue(ctx, val);
|
||||||
|
runtimeOpaques[rt]?.ref?.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void release() {
|
||||||
|
if (val != null) {
|
||||||
|
jsFreeValue(ctx, val);
|
||||||
|
deleteJSValue(val);
|
||||||
|
val = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
noSuchMethod(Invocation invocation) {
|
||||||
|
return super.noSuchMethod(invocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Pointer dartToJs(Pointer ctx, dynamic val, {Map<dynamic, dynamic> cache}) {
|
||||||
|
if (cache == null) cache = Map();
|
||||||
|
if (val is bool) return jsNewBool(ctx, val ? 1 : 0);
|
||||||
|
if (val is int) return jsNewInt64(ctx, val);
|
||||||
|
if (val is double) return jsNewFloat64(ctx, val);
|
||||||
|
if (val is String) return jsNewString(ctx, val);
|
||||||
|
if (val is Uint8List) {
|
||||||
|
var ptr = allocate<Uint8>(count: val.length);
|
||||||
|
var byteList = ptr.asTypedList(val.length);
|
||||||
|
byteList.setAll(0, val);
|
||||||
|
var ret = jsNewArrayBufferCopy(ctx, ptr, val.length);
|
||||||
|
free(ptr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (cache.containsKey(val)) {
|
||||||
|
return cache[val];
|
||||||
|
}
|
||||||
|
if (val is JSFunction) {
|
||||||
|
return jsDupValue(ctx, val.val);
|
||||||
|
}
|
||||||
|
if (val is List) {
|
||||||
|
Pointer ret = jsNewArray(ctx);
|
||||||
|
cache[val] = ret;
|
||||||
|
for (int i = 0; i < val.length; ++i) {
|
||||||
|
var jsAtomVal = jsNewInt64(ctx, i);
|
||||||
|
var jsAtom = jsValueToAtom(ctx, jsAtomVal);
|
||||||
|
jsDefinePropertyValue(
|
||||||
|
ctx,
|
||||||
|
ret,
|
||||||
|
jsAtom,
|
||||||
|
dartToJs(ctx, val[i], cache: cache),
|
||||||
|
JSProp.C_W_E,
|
||||||
|
);
|
||||||
|
jsFreeAtom(ctx, jsAtom);
|
||||||
|
jsFreeValue(ctx, jsAtomVal);
|
||||||
|
deleteJSValue(jsAtomVal);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (val is Map) {
|
||||||
|
Pointer ret = jsNewObject(ctx);
|
||||||
|
cache[val] = ret;
|
||||||
|
for (MapEntry<dynamic, dynamic> entry in val.entries){
|
||||||
|
var jsAtomVal = dartToJs(ctx, entry.key, cache: cache);
|
||||||
|
var jsAtom = jsValueToAtom(ctx, jsAtomVal);
|
||||||
|
jsDefinePropertyValue(
|
||||||
|
ctx,
|
||||||
|
ret,
|
||||||
|
jsAtom,
|
||||||
|
dartToJs(ctx, entry.value, cache: cache),
|
||||||
|
JSProp.C_W_E,
|
||||||
|
);
|
||||||
|
jsFreeAtom(ctx, jsAtom);
|
||||||
|
jsFreeValue(ctx, jsAtomVal);
|
||||||
|
deleteJSValue(jsAtomVal);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return jsUNDEFINED();
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic jsToDart(Pointer ctx, Pointer val, {Map<int, dynamic> cache}) {
|
||||||
|
if (cache == null) cache = Map();
|
||||||
|
int tag = jsValueGetTag(val);
|
||||||
|
if (jsTagIsFloat64(tag) != 0) {
|
||||||
|
return jsToFloat64(ctx, val);
|
||||||
|
}
|
||||||
|
switch (tag) {
|
||||||
|
case JSTag.BOOL:
|
||||||
|
return jsToBool(ctx, val) != 0;
|
||||||
|
case JSTag.INT:
|
||||||
|
return jsToInt64(ctx, val);
|
||||||
|
case JSTag.STRING:
|
||||||
|
return jsToCString(ctx, val);
|
||||||
|
case JSTag.OBJECT:
|
||||||
|
Pointer<Int64> psize = allocate<Int64>();
|
||||||
|
Pointer<Uint8> buf = jsGetArrayBuffer(ctx, psize, val);
|
||||||
|
int size = psize.value;
|
||||||
|
free(psize);
|
||||||
|
if (buf.address != 0) {
|
||||||
|
return buf.asTypedList(size);
|
||||||
|
}
|
||||||
|
int valptr = jsValueGetPtr(val).address;
|
||||||
|
if (cache.containsKey(valptr)) {
|
||||||
|
return cache[valptr];
|
||||||
|
}
|
||||||
|
if (jsIsFunction(ctx, val) != 0) {
|
||||||
|
return JSFunction(ctx, val);
|
||||||
|
} else if (jsIsArray(ctx, val) != 0) {
|
||||||
|
var jsAtomVal = jsNewString(ctx, "length");
|
||||||
|
var jsAtom = jsValueToAtom(ctx, jsAtomVal);
|
||||||
|
var jslength = jsGetProperty(ctx, val, jsAtom);
|
||||||
|
jsFreeAtom(ctx, jsAtom);
|
||||||
|
jsFreeValue(ctx, jsAtomVal);
|
||||||
|
deleteJSValue(jsAtomVal);
|
||||||
|
|
||||||
|
int length = jsToInt64(ctx, jslength);
|
||||||
|
deleteJSValue(jslength);
|
||||||
|
List<dynamic> ret = List();
|
||||||
|
cache[valptr] = ret;
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
var jsAtomVal = jsNewInt64(ctx, i);
|
||||||
|
var jsAtom = jsValueToAtom(ctx, jsAtomVal);
|
||||||
|
var jsProp = jsGetProperty(ctx, val, jsAtom);
|
||||||
|
jsFreeAtom(ctx, jsAtom);
|
||||||
|
jsFreeValue(ctx, jsAtomVal);
|
||||||
|
deleteJSValue(jsAtomVal);
|
||||||
|
ret.add(jsToDart(ctx, jsProp, cache: cache));
|
||||||
|
jsFreeValue(ctx, jsProp);
|
||||||
|
deleteJSValue(jsProp);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
Pointer<Pointer> ptab = allocate<Pointer>();
|
||||||
|
Pointer<Uint32> plen = allocate<Uint32>();
|
||||||
|
if (jsGetOwnPropertyNames(ctx, ptab, plen, val, -1) != 0) return null;
|
||||||
|
int len = plen.value;
|
||||||
|
free(plen);
|
||||||
|
Map<dynamic, dynamic> ret = Map();
|
||||||
|
cache[valptr] = ret;
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
var jsAtom = jsPropertyEnumGetAtom(ptab.value, i);
|
||||||
|
var jsAtomValue = jsAtomToValue(ctx, jsAtom);
|
||||||
|
var jsProp = jsGetProperty(ctx, val, jsAtom);
|
||||||
|
ret[jsToDart(ctx, jsAtomValue, cache: cache)] = jsToDart(ctx, jsProp, cache: cache);
|
||||||
|
jsFreeValue(ctx, jsAtomValue);
|
||||||
|
deleteJSValue(jsAtomValue);
|
||||||
|
jsFreeValue(ctx, jsProp);
|
||||||
|
deleteJSValue(jsProp);
|
||||||
|
jsFreeAtom(ctx, jsAtom);
|
||||||
|
}
|
||||||
|
free(ptab);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
@@ -3,31 +3,75 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-09-06 13:02:46
|
* @Date: 2020-09-06 13:02:46
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-09-13 22:59:06
|
* @LastEditTime: 2020-09-20 15:55:50
|
||||||
*/
|
*/
|
||||||
import 'dart:ffi';
|
import 'dart:convert';
|
||||||
import 'package:ffi/ffi.dart';
|
import 'dart:io';
|
||||||
|
|
||||||
void main() {
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
final DynamicLibrary qjsLib = DynamicLibrary.open("test/lib/build/Debug/ffi_library.dll");
|
|
||||||
print(qjsLib);
|
import 'package:flutter_qjs/ffi.dart';
|
||||||
// JSRuntime *js_NewRuntime(void);
|
import 'package:flutter_qjs/wrapper.dart';
|
||||||
final Pointer Function() jsNewRuntime =
|
|
||||||
qjsLib.lookup<NativeFunction<Pointer Function()>>("jsNewRuntime").asFunction();
|
void main() async {
|
||||||
final rt = jsNewRuntime();
|
test('make', () async {
|
||||||
print(rt);
|
final utf8Encoding = Encoding.getByName('utf-8');
|
||||||
// JSContext *js_NewContext(JSRuntime *rt);
|
final cmakePath =
|
||||||
final Pointer Function(Pointer rt) jsNewContext =
|
"C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/bin/cmake.exe";
|
||||||
qjsLib.lookup<NativeFunction<Pointer Function(Pointer)>>("jsNewContext").asFunction();
|
final buildDir = "./build";
|
||||||
final ctx = jsNewContext(rt);
|
var result = Process.runSync(
|
||||||
print(ctx);
|
cmakePath,
|
||||||
// JSValue *js_Eval(JSContext *ctx, const char *input, const char *filename, int eval_flags)
|
['-S', './', '-B', buildDir],
|
||||||
final Pointer Function(Pointer rt, Pointer<Utf8> input, Pointer<Utf8> filename, int evalFlags) jsEval =
|
workingDirectory: 'test/lib',
|
||||||
qjsLib.lookup<NativeFunction<Pointer Function(Pointer,Pointer<Utf8>,Pointer<Utf8>, Int32)>>("jsEval").asFunction();
|
stdoutEncoding: utf8Encoding,
|
||||||
final jsval = jsEval(ctx, Utf8.toUtf8("`hello \${'world'}!`"), Utf8.toUtf8("<eval>"), 0);
|
stderrEncoding: utf8Encoding,
|
||||||
// const char *js_ToCString(JSContext *ctx, JSValue *val)
|
);
|
||||||
final Pointer<Utf8> Function(Pointer rt, Pointer val) jsToCString =
|
stdout.write(result.stdout);
|
||||||
qjsLib.lookup<NativeFunction<Pointer<Utf8> Function(Pointer,Pointer)>>("jsToCString").asFunction();
|
stderr.write(result.stderr);
|
||||||
final str = Utf8.fromUtf8(jsToCString(ctx, jsval));
|
expect(result.exitCode, 0);
|
||||||
print(str);
|
|
||||||
|
result = Process.runSync(
|
||||||
|
cmakePath,
|
||||||
|
['--build', buildDir, '--verbose'],
|
||||||
|
workingDirectory: 'test/lib',
|
||||||
|
stdoutEncoding: utf8Encoding,
|
||||||
|
stderrEncoding: utf8Encoding,
|
||||||
|
);
|
||||||
|
stdout.write(result.stdout);
|
||||||
|
stderr.write(result.stderr);
|
||||||
|
expect(result.exitCode, 0);
|
||||||
|
});
|
||||||
|
test('jsToDart', () async {
|
||||||
|
final rt = jsNewRuntime((ctx, method, argv) {
|
||||||
|
var argvs = jsToDart(ctx, argv);
|
||||||
|
print([method, argvs]);
|
||||||
|
return dartToJs(ctx, [
|
||||||
|
argvs,
|
||||||
|
{
|
||||||
|
[233, 2]: {}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
final ctx = jsNewContext(rt);
|
||||||
|
final jsval = jsEval(
|
||||||
|
ctx,
|
||||||
|
"""
|
||||||
|
const a = {};
|
||||||
|
a.a = a;
|
||||||
|
channel('channel', [
|
||||||
|
0.1, true, false, 1, "world",
|
||||||
|
new ArrayBuffer(2),
|
||||||
|
()=>'hello',
|
||||||
|
a
|
||||||
|
]);
|
||||||
|
""",
|
||||||
|
"<eval>",
|
||||||
|
JSEvalType.GLOBAL,
|
||||||
|
);
|
||||||
|
print(jsToDart(ctx, jsval));
|
||||||
|
jsFreeValue(ctx, jsval);
|
||||||
|
deleteJSValue(jsval);
|
||||||
|
jsFreeContext(ctx);
|
||||||
|
jsFreeRuntime(rt);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.7 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.7 FATAL_ERROR)
|
||||||
project(ffi_library LANGUAGES CXX)
|
project(ffi_library LANGUAGES CXX)
|
||||||
add_library(ffi_library SHARED ffi.cpp)
|
add_library(ffi_library SHARED ${CMAKE_CURRENT_SOURCE_DIR}/../../cxx/ffi.cpp)
|
||||||
|
|
||||||
# quickjs
|
# quickjs
|
||||||
set(QUICK_JS_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../cxx/quickjs)
|
set(QUICK_JS_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../cxx/quickjs)
|
||||||
|
@@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* @Description:
|
|
||||||
* @Author: ekibun
|
|
||||||
* @Date: 2020-09-06 18:32:45
|
|
||||||
* @LastEditors: ekibun
|
|
||||||
* @LastEditTime: 2020-09-13 17:26:29
|
|
||||||
*/
|
|
||||||
#include "../../cxx/quickjs/quickjs.h"
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#define DLLEXPORT __declspec(dllexport)
|
|
||||||
#else
|
|
||||||
#define DLLEXPORT __attribute__((visibility("default")))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
|
|
||||||
DLLEXPORT JSRuntime *jsNewRuntime()
|
|
||||||
{
|
|
||||||
return JS_NewRuntime();
|
|
||||||
}
|
|
||||||
|
|
||||||
DLLEXPORT JSContext *jsNewContext(JSRuntime *rt)
|
|
||||||
{
|
|
||||||
return JS_NewContext(rt);
|
|
||||||
}
|
|
||||||
|
|
||||||
DLLEXPORT JSValue *jsEval(JSContext *ctx, const char *input, const char *filename, int eval_flags)
|
|
||||||
{
|
|
||||||
return new JSValue{JS_Eval(ctx, input, strlen(input), filename, eval_flags)};
|
|
||||||
}
|
|
||||||
|
|
||||||
DLLEXPORT const char *jsToCString(JSContext *ctx, JSValue *val)
|
|
||||||
{
|
|
||||||
return JS_ToCString(ctx, *val);
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user