2626#include " napi_env_quickjs.h"
2727#include " quickjs/include/quickjs-inner.h"
2828
29+
30+ std::unordered_map<LEPUSRuntime *, napi_env> napi_context__::rt_to_env_cache;
2931struct napi_callback_info__ {
3032 napi_value newTarget;
3133 napi_value thisArg;
@@ -2622,7 +2624,6 @@ napi_status napi_get_instance_data(napi_env env, uint64_t key, void **data) {
26222624void napi_attach_quickjs (napi_env env, LEPUSContext *context) {
26232625 env->ctx = new napi_context__ (env, context);
26242626
2625-
26262627 InitNapiScope (context);
26272628}
26282629
@@ -2678,5 +2679,203 @@ napi_status primjs_execute_pending_jobs(napi_env env) {
26782679 }
26792680 } while (error != 0 );
26802681
2682+ return napi_clear_last_error (env);
2683+ }
2684+
2685+
2686+ typedef struct NapiHostObjectInfo {
2687+ void *data;
2688+ napi_ref ref;
2689+ napi_finalize finalize_cb;
2690+ bool is_array;
2691+ napi_ref getter;
2692+ napi_ref setter;
2693+ } NapiHostObjectInfo;
2694+
2695+ void host_object_finalizer (LEPUSRuntime *rt, LEPUSValue value) {
2696+ napi_env env = (napi_env) napi_context__::GetEnv (rt);
2697+ NapiHostObjectInfo *info = (NapiHostObjectInfo *) LEPUS_GetOpaque (value,
2698+ env->ctx ->napiHostObjectClassId );
2699+ if (info->finalize_cb ) {
2700+ info->finalize_cb (env, info->data , NULL );
2701+ }
2702+ if (info->is_array ) {
2703+ napi_delete_reference (env, info->getter );
2704+ napi_delete_reference (env, info->setter );
2705+ }
2706+
2707+ napi_delete_reference (env, info->ref );
2708+ delete info;
2709+ }
2710+
2711+ int host_object_set (LEPUSContext *ctx, LEPUSValue obj, JSAtom atom,
2712+ LEPUSValue value, LEPUSValue receiver, int flags) {
2713+ napi_env env = (napi_env) napi_context__::GetEnv (LEPUS_GetRuntime (ctx));
2714+ NapiHostObjectInfo *info = (NapiHostObjectInfo *) LEPUS_GetOpaque (obj,
2715+ env->ctx ->napiHostObjectClassId );
2716+ if (info != NULL ) {
2717+ auto *target = reinterpret_cast <qjsimpl::Reference *>(info->ref );
2718+ if (info->is_array ) {
2719+ LEPUSValue atom_val = LEPUS_AtomToValue (ctx, atom);
2720+
2721+ auto *setter = reinterpret_cast <qjsimpl::Reference *>(info->setter );
2722+
2723+ LEPUSValue argv[4 ] = {
2724+ ToJSValue (target->Get ()),
2725+ atom_val,
2726+ value,
2727+ obj
2728+ };
2729+
2730+ LEPUSValue result = LEPUS_Call (ctx, ToJSValue (setter->Get ()), LEPUS_UNDEFINED, 4 , argv);
2731+
2732+ JS_FreeValue_Comp (ctx, atom_val);
2733+
2734+ if (LEPUS_IsException (result)) return -1 ;
2735+
2736+ return true ;
2737+ }
2738+ return LEPUS_SetProperty (ctx, ToJSValue (target->Get ()), atom, JS_DupValue_Comp (ctx, value));
2739+ }
2740+ return true ;
2741+ }
2742+
2743+ LEPUSValue host_object_get (LEPUSContext *ctx, LEPUSValue obj, JSAtom atom, LEPUSValue receiver) {
2744+ napi_env env = (napi_env) napi_context__::GetEnv (LEPUS_GetRuntime (ctx));
2745+ NapiHostObjectInfo *info = (NapiHostObjectInfo *) LEPUS_GetOpaque (obj,
2746+ env->ctx ->napiHostObjectClassId );
2747+ if (info != NULL ) {
2748+ auto *target = reinterpret_cast <qjsimpl::Reference *>(info->ref );
2749+ if (info->is_array ) {
2750+ LEPUSValue atom_val = LEPUS_AtomToValue (ctx, atom);
2751+ auto *getter = reinterpret_cast <qjsimpl::Reference *>(info->getter );
2752+ LEPUSValue argv[3 ] = {
2753+ ToJSValue (target->Get ()),
2754+ atom_val,
2755+ obj
2756+ };
2757+ LEPUSValue value = LEPUS_Call (ctx, ToJSValue (getter->Get ()), LEPUS_UNDEFINED, 3 , argv);
2758+ JS_FreeValue_Comp (ctx, atom_val);
2759+ return value;
2760+ }
2761+ return LEPUS_GetProperty (ctx, ToJSValue (target->Get ()), atom);
2762+ }
2763+ return LEPUS_UNDEFINED;
2764+ }
2765+
2766+ int host_object_has (LEPUSContext *ctx, LEPUSValue obj, JSAtom atom) {
2767+ napi_env env = (napi_env) napi_context__::GetEnv (LEPUS_GetRuntime (ctx));
2768+ NapiHostObjectInfo *info = (NapiHostObjectInfo *) LEPUS_GetOpaque (obj,
2769+ env->ctx ->napiHostObjectClassId );
2770+ if (info != NULL ) {
2771+ auto *target = reinterpret_cast <qjsimpl::Reference *>(info->ref );
2772+ return LEPUS_HasProperty (ctx, ToJSValue (target->Get ()), atom);
2773+ }
2774+ return false ;
2775+ }
2776+
2777+ static int host_object_delete (LEPUSContext *ctx, LEPUSValue obj, JSAtom atom) {
2778+ napi_env env = (napi_env) napi_context__::GetEnv (LEPUS_GetRuntime (ctx));
2779+ NapiHostObjectInfo *info = (NapiHostObjectInfo *) LEPUS_GetOpaque (obj,
2780+ env->ctx ->napiHostObjectClassId );
2781+ if (info != NULL ) {
2782+ auto *target = reinterpret_cast <qjsimpl::Reference *>(info->ref );
2783+ return LEPUS_DeleteProperty (ctx, ToJSValue (target->Get ()), atom, 0 );
2784+ }
2785+ return true ;
2786+ }
2787+
2788+ LEPUSClassExoticMethods NapiHostObjectExoticMethods = {
2789+ .get_own_property = nullptr ,
2790+ .get_own_property_names = nullptr ,
2791+ .delete_property = host_object_delete,
2792+ .define_own_property = nullptr ,
2793+ .has_property = host_object_has,
2794+ .get_property = host_object_get,
2795+ .set_property = host_object_set,
2796+ };
2797+
2798+ napi_status
2799+ napi_create_host_object (napi_env env, napi_value value, napi_finalize finalize, void *data,
2800+ bool is_array, napi_value getter, napi_value setter, napi_value *result) {
2801+ CHECK_ARG (env, result);
2802+
2803+ if (env->ctx ->napi_host_object_class_init == 0 ) {
2804+ LEPUSClassDef NapiHostObjectClassDef = {" NapiHostObject" , host_object_finalizer, NULL , NULL ,
2805+ &NapiHostObjectExoticMethods};
2806+ LEPUS_NewClass (env->ctx ->rt , env->ctx ->napiHostObjectClassId , &NapiHostObjectClassDef);
2807+ env->ctx ->napi_host_object_class_init = 1 ;
2808+ }
2809+
2810+ napi_value constructor;
2811+ napi_get_named_property (env, value, " constructor" , &constructor);
2812+
2813+ napi_value prototype;
2814+ napi_get_named_property (env, constructor, " prototype" , &prototype);
2815+
2816+ LEPUSValue jsValue = LEPUS_NewObjectClass (env->ctx ->ctx , env->ctx ->napiHostObjectClassId );
2817+ LEPUS_SetPrototype (env->ctx ->ctx , jsValue, ToJSValue (prototype));
2818+
2819+ NapiHostObjectInfo *info = new NapiHostObjectInfo;
2820+ info->data = data;
2821+ if (finalize) {
2822+ info->finalize_cb = finalize;
2823+ } else {
2824+ info->finalize_cb = NULL ;
2825+ }
2826+ info->is_array = is_array;
2827+
2828+ if (is_array) {
2829+ if (getter) napi_create_reference (env, getter, 1 , &info->getter );
2830+ if (setter) napi_create_reference (env, setter, 1 , &info->setter );
2831+ }
2832+
2833+ napi_create_reference (env, value, 1 , &info->ref );
2834+
2835+ LEPUS_SetOpaque (jsValue, info);
2836+
2837+ *result = env->ctx ->CreateHandle (jsValue);
2838+ return napi_ok;
2839+ }
2840+
2841+ napi_status napi_get_host_object_data (napi_env env, napi_value object, void **data) {
2842+ CHECK_ARG (env, object);
2843+ CHECK_ARG (env, data);
2844+
2845+ LEPUSValue jsValue = ToJSValue (object);
2846+
2847+
2848+ if (!LEPUS_IsObject (jsValue)) {
2849+ return napi_set_last_error (env, napi_object_expected);
2850+ }
2851+
2852+ NapiHostObjectInfo *info = (NapiHostObjectInfo *) LEPUS_GetOpaque (jsValue,
2853+ env->ctx ->napiHostObjectClassId );
2854+ if (info) {
2855+ *data = info->data ;
2856+ } else {
2857+ *data = NULL ;
2858+ }
2859+
2860+ return napi_clear_last_error (env);
2861+ }
2862+
2863+ napi_status napi_is_host_object (napi_env env, napi_value object, bool *result) {
2864+ CHECK_ARG (env, object);
2865+
2866+ LEPUSValue jsValue = ToJSValue (object);
2867+
2868+ if (!LEPUS_IsObject (jsValue)) {
2869+ return napi_set_last_error (env, napi_object_expected);
2870+ }
2871+
2872+ void *data = LEPUS_GetOpaque (jsValue,
2873+ env->ctx ->napiHostObjectClassId );
2874+ if (data != NULL ) {
2875+ *result = true ;
2876+ } else {
2877+ *result = false ;
2878+ }
2879+
26812880 return napi_clear_last_error (env);
26822881}
0 commit comments