Page MenuHomePhorge

napi.c
No OneTemporary

Size
84 KB
Referenced Files
None
Subscribers
None
#include <compat.h> // IWYU pragma: keep
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define NAPI_DLOPEN(name, flags) ((void*)LoadLibraryA(name))
#define NAPI_DLSYM(handle, name) ((void*)GetProcAddress((HMODULE)(handle), (name)))
#define NAPI_DLERROR() "LoadLibrary failed"
#define NAPI_RTLD_NOW 0
#define NAPI_RTLD_LOCAL 0
#define NAPI_RTLD_GLOBAL 0
#else
#include <dlfcn.h>
#define NAPI_DLOPEN(name, flags) dlopen((name), (flags))
#define NAPI_DLSYM(handle, name) dlsym((handle), (name))
#define NAPI_DLERROR() dlerror()
#define NAPI_RTLD_NOW RTLD_NOW
#define NAPI_RTLD_LOCAL RTLD_LOCAL
#define NAPI_RTLD_GLOBAL RTLD_GLOBAL
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uthash.h>
#include <uv.h>
#include "ant.h"
#include "descriptors.h"
#include "errors.h"
#include "internal.h"
#include "silver/engine.h"
#include "modules/buffer.h"
#include "modules/napi.h"
typedef struct napi_cleanup_hook_entry {
napi_cleanup_hook hook;
void *arg;
struct napi_cleanup_hook_entry *next;
} napi_cleanup_hook_entry_t;
typedef struct ant_napi_env__ {
ant_t *js;
napi_extended_error_info last_error;
char last_error_msg[256];
bool has_pending_exception;
napi_value pending_exception;
uint32_t version;
napi_cleanup_hook_entry_t *cleanup_hooks;
} ant_napi_env_t;
typedef struct napi_callback_binding {
ant_napi_env_t *env;
napi_callback cb;
void *data;
} napi_callback_binding_t;
struct napi_callback_info__ {
ant_napi_env_t *env;
const napi_value *argv;
size_t argc;
napi_value this_arg;
napi_value new_target;
void *data;
};
struct napi_ref__ {
ant_napi_env_t *env;
jshdl_t root;
napi_value value;
uint32_t refcount;
};
struct napi_deferred__ {
ant_napi_env_t *env;
jshdl_t promise_root;
bool settled;
};
struct napi_handle_scope__ {
ant_napi_env_t *env;
};
struct napi_escapable_handle_scope__ {
ant_napi_env_t *env;
bool escaped;
};
struct napi_async_context__ {
ant_napi_env_t *env;
};
struct napi_callback_scope__ {
ant_napi_env_t *env;
};
typedef struct napi_external_entry {
uint64_t id;
void *data;
node_api_basic_finalize finalize_cb;
void *finalize_hint;
UT_hash_handle hh;
} napi_external_entry_t;
typedef struct napi_wrap_entry {
uint64_t id;
void *native_object;
node_api_basic_finalize finalize_cb;
void *finalize_hint;
UT_hash_handle hh;
} napi_wrap_entry_t;
typedef struct napi_async_work_impl {
ant_napi_env_t *env;
napi_async_execute_callback execute;
napi_async_complete_callback complete;
void *data;
uv_work_t req;
bool queued;
bool delete_after_complete;
} napi_async_work_impl_t;
typedef struct napi_tsfn_item {
void *data;
struct napi_tsfn_item *next;
} napi_tsfn_item_t;
struct napi_threadsafe_function__ {
ant_napi_env_t *env;
jshdl_t func_root;
napi_threadsafe_function_call_js call_js_cb;
node_api_basic_finalize thread_finalize_cb;
void *thread_finalize_data;
void *context;
size_t max_queue_size;
size_t queue_size;
size_t thread_count;
bool closing;
bool aborted;
uv_async_t async;
uv_mutex_t mutex;
napi_tsfn_item_t *head;
napi_tsfn_item_t *tail;
};
typedef napi_value(NAPI_CDECL* napi_register_module_v1_fn)(napi_env env, napi_value exports);
typedef struct napi_native_lib {
void *handle;
struct napi_native_lib *next;
} napi_native_lib_t;
static ant_napi_env_t *g_napi_env = NULL;
static napi_external_entry_t *g_napi_externals = NULL;
static napi_wrap_entry_t *g_napi_wraps = NULL;
static uint64_t g_napi_external_next_id = 1;
static uint64_t g_napi_wrap_next_id = 1;
static napi_native_lib_t *g_napi_native_libs = NULL;
static napi_module *g_pending_napi_module = NULL;
static const napi_node_version g_napi_node_version = {
.major = 25,
.minor = 0,
.patch = 0,
.release = "ant",
};
static int64_t g_napi_external_memory = 0;
static const char *napi_status_text(napi_status status) {
switch (status) {
case napi_ok: return "ok";
case napi_invalid_arg: return "invalid argument";
case napi_object_expected: return "object expected";
case napi_string_expected: return "string expected";
case napi_name_expected: return "name expected";
case napi_function_expected: return "function expected";
case napi_number_expected: return "number expected";
case napi_boolean_expected: return "boolean expected";
case napi_array_expected: return "array expected";
case napi_generic_failure: return "generic failure";
case napi_pending_exception: return "pending exception";
case napi_cancelled: return "cancelled";
case napi_escape_called_twice: return "escape called twice";
case napi_handle_scope_mismatch: return "handle scope mismatch";
case napi_callback_scope_mismatch: return "callback scope mismatch";
case napi_queue_full: return "queue full";
case napi_closing: return "closing";
case napi_bigint_expected: return "bigint expected";
case napi_date_expected: return "date expected";
case napi_arraybuffer_expected: return "arraybuffer expected";
case napi_detachable_arraybuffer_expected: return "detachable arraybuffer expected";
case napi_would_deadlock: return "would deadlock";
case napi_no_external_buffers_allowed: return "no external buffers allowed";
case napi_cannot_run_js: return "cannot run js";
default: return "unknown";
}
}
static napi_status napi_set_last(napi_env env, napi_status status, const char *message) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv) return status;
const char *msg = message ? message : napi_status_text(status);
snprintf(nenv->last_error_msg, sizeof(nenv->last_error_msg), "%s", msg);
nenv->last_error.error_message = nenv->last_error_msg;
nenv->last_error.engine_reserved = NULL;
nenv->last_error.engine_error_code = 0;
nenv->last_error.error_code = status;
return status;
}
static ant_napi_env_t *napi_get_or_create_env(ant_t *js) {
if (!g_napi_env) {
g_napi_env = (ant_napi_env_t *)calloc(1, sizeof(*g_napi_env));
if (!g_napi_env) return NULL;
g_napi_env->version = 8;
napi_set_last((napi_env)g_napi_env, napi_ok, NULL);
}
g_napi_env->js = js;
return g_napi_env;
}
napi_env ant_napi_get_env(ant_t *js) {
return (napi_env)napi_get_or_create_env(js);
}
static inline bool napi_is_callable(jsval_t v) {
uint8_t t = vtype(v);
return t == T_FUNC || t == T_CFUNC;
}
static void napi_mark_pending_exception(napi_env env, napi_value exception) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv) return;
nenv->has_pending_exception = true;
nenv->pending_exception = exception;
napi_set_last(env, napi_pending_exception, "pending exception");
}
static napi_status napi_check_pending_from_result(napi_env env, jsval_t result) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
if (is_err(result) || nenv->js->thrown_exists) {
napi_mark_pending_exception(
env,
nenv->js->thrown_exists ? nenv->js->thrown_value : result
);
return napi_pending_exception;
}
return napi_set_last(env, napi_ok, NULL);
}
static bool napi_slot_get_u64(ant_t *js, jsval_t obj, internal_slot_t slot, uint64_t *out) {
jsval_t value = js_get_slot(js, obj, slot);
if (vtype(value) != T_NUM) return false;
*out = (uint64_t)js_getnum(value);
return true;
}
static void napi_slot_set_u64(ant_t *js, jsval_t obj, internal_slot_t slot, uint64_t v) {
js_set_slot(js, obj, slot, js_mknum((double)v));
}
static napi_external_entry_t *napi_find_external(ant_t *js, napi_value value) {
if (!is_object_type((jsval_t)value)) return NULL;
uint64_t id = 0;
if (!napi_slot_get_u64(js, (jsval_t)value, SLOT_NAPI_EXTERNAL_ID, &id)) return NULL;
napi_external_entry_t *entry = NULL;
HASH_FIND(hh, g_napi_externals, &id, sizeof(id), entry);
return entry;
}
static napi_wrap_entry_t *napi_find_wrap(ant_t *js, napi_value value) {
if (!is_object_type((jsval_t)value)) return NULL;
uint64_t id = 0;
if (!napi_slot_get_u64(js, (jsval_t)value, SLOT_NAPI_WRAP_ID, &id)) return NULL;
napi_wrap_entry_t *entry = NULL;
HASH_FIND(hh, g_napi_wraps, &id, sizeof(id), entry);
return entry;
}
static bool napi_get_typedarray_data(
ant_t *js,
napi_value value,
TypedArrayData **out
) {
jsval_t slot = js_get_slot(js, (jsval_t)value, SLOT_BUFFER);
if (vtype(slot) != T_TYPEDARRAY) return false;
TypedArrayData *ta = (TypedArrayData *)js_gettypedarray(slot);
if (!ta || !ta->buffer || ta->buffer->is_detached) return false;
*out = ta;
return true;
}
static const char *napi_typed_array_name(TypedArrayType t) {
switch (t) {
case TYPED_ARRAY_INT8: return "Int8Array";
case TYPED_ARRAY_UINT8: return "Uint8Array";
case TYPED_ARRAY_UINT8_CLAMPED: return "Uint8ClampedArray";
case TYPED_ARRAY_INT16: return "Int16Array";
case TYPED_ARRAY_UINT16: return "Uint16Array";
case TYPED_ARRAY_INT32: return "Int32Array";
case TYPED_ARRAY_UINT32: return "Uint32Array";
case TYPED_ARRAY_FLOAT32: return "Float32Array";
case TYPED_ARRAY_FLOAT64: return "Float64Array";
case TYPED_ARRAY_BIGINT64: return "BigInt64Array";
case TYPED_ARRAY_BIGUINT64: return "BigUint64Array";
default: return "Uint8Array";
}
}
static bool napi_to_ant_typedarray_type(
napi_typedarray_type in,
TypedArrayType *out
) {
switch (in) {
case napi_int8_array: *out = TYPED_ARRAY_INT8; return true;
case napi_uint8_array: *out = TYPED_ARRAY_UINT8; return true;
case napi_uint8_clamped_array: *out = TYPED_ARRAY_UINT8_CLAMPED; return true;
case napi_int16_array: *out = TYPED_ARRAY_INT16; return true;
case napi_uint16_array: *out = TYPED_ARRAY_UINT16; return true;
case napi_int32_array: *out = TYPED_ARRAY_INT32; return true;
case napi_uint32_array: *out = TYPED_ARRAY_UINT32; return true;
case napi_float32_array: *out = TYPED_ARRAY_FLOAT32; return true;
case napi_float64_array: *out = TYPED_ARRAY_FLOAT64; return true;
case napi_bigint64_array: *out = TYPED_ARRAY_BIGINT64; return true;
case napi_biguint64_array: *out = TYPED_ARRAY_BIGUINT64; return true;
default: return false;
}
}
static napi_typedarray_type napi_from_ant_typedarray_type(TypedArrayType in) {
switch (in) {
case TYPED_ARRAY_INT8: return napi_int8_array;
case TYPED_ARRAY_UINT8: return napi_uint8_array;
case TYPED_ARRAY_UINT8_CLAMPED: return napi_uint8_clamped_array;
case TYPED_ARRAY_INT16: return napi_int16_array;
case TYPED_ARRAY_UINT16: return napi_uint16_array;
case TYPED_ARRAY_INT32: return napi_int32_array;
case TYPED_ARRAY_UINT32: return napi_uint32_array;
case TYPED_ARRAY_FLOAT32: return napi_float32_array;
case TYPED_ARRAY_FLOAT64: return napi_float64_array;
case TYPED_ARRAY_BIGINT64: return napi_bigint64_array;
case TYPED_ARRAY_BIGUINT64: return napi_biguint64_array;
default: return napi_uint8_array;
}
}
static int napi_desc_flags(napi_property_attributes attributes) {
int flags = 0;
if (attributes & napi_writable) flags |= JS_DESC_W;
if (attributes & napi_enumerable) flags |= JS_DESC_E;
if (attributes & napi_configurable) flags |= JS_DESC_C;
return flags;
}
static jsval_t napi_callback_trampoline(ant_t *js, jsval_t *args, int nargs) {
jsval_t current = js_getcurrentfunc(js);
jsval_t data_slot = js_get_slot(js, current, SLOT_DATA);
if (vtype(data_slot) != T_NUM) return js_mkundef();
napi_callback_binding_t *binding = (napi_callback_binding_t *)(uintptr_t)js_getnum(data_slot);
if (!binding || !binding->cb) return js_mkundef();
ant_napi_env_t *nenv = binding->env ? binding->env : napi_get_or_create_env(js);
if (!nenv) return js_mkerr(js, "napi OOM");
struct napi_callback_info__ info = {
.env = nenv,
.argv = (const napi_value *)args,
.argc = (size_t)(nargs < 0 ? 0 : nargs),
.this_arg = (napi_value)js_getthis(js),
.new_target = (napi_value)sv_vm_get_new_target(js->vm, js),
.data = binding->data,
};
napi_value ret = binding->cb((napi_env)nenv, (napi_callback_info)&info);
if (nenv->has_pending_exception) {
jsval_t ex = (jsval_t)nenv->pending_exception;
nenv->has_pending_exception = false;
nenv->pending_exception = (napi_value)js_mkundef();
return js_throw(js, ex);
}
if ((jsval_t)ret == 0) return js_mkundef();
return (jsval_t)ret;
}
static napi_status napi_create_function_common(
napi_env env,
const char *utf8name,
size_t length,
napi_callback cb,
void *data,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !cb || !result) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
napi_callback_binding_t *binding = (napi_callback_binding_t *)calloc(1, sizeof(*binding));
if (!binding) return napi_set_last(env, napi_generic_failure, "out of memory");
binding->env = nenv;
binding->cb = cb;
binding->data = data;
jsval_t fn = js_heavy_mkfun(nenv->js, napi_callback_trampoline, ANT_PTR(binding));
if (utf8name && utf8name[0]) {
size_t nlen = (length == NAPI_AUTO_LENGTH) ? strlen(utf8name) : length;
js_set(nenv->js, fn, "name", js_mkstr(nenv->js, utf8name, nlen));
}
*result = (napi_value)fn;
return napi_set_last(env, napi_ok, NULL);
}
static jsval_t napi_make_string(ant_t *js, const char *s, size_t len) {
if (!s) return js_mkstr(js, "", 0);
if (len == NAPI_AUTO_LENGTH) len = strlen(s);
return js_mkstr(js, s, len);
}
static napi_status napi_make_error_object(
napi_env env,
const char *name,
napi_value msg,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
ant_t *js = nenv->js;
jsval_t message = (jsval_t)msg;
if (vtype(message) != T_STR) {
message = coerce_to_str(js, message);
if (is_err(message)) return napi_check_pending_from_result(env, message);
}
jsval_t err = js_mkobj(js);
js_set(js, err, "name", js_mkstr(js, name, strlen(name)));
js_set(js, err, "message", message);
jsval_t proto = js_get_ctor_proto(js, name, strlen(name));
if (is_object_type(proto)) js_set_proto(js, err, proto);
*result = (napi_value)err;
return napi_set_last(env, napi_ok, NULL);
}
static napi_status napi_throw_with_message(
napi_env env,
js_err_type_t err_type,
const char *msg
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
jsval_t error = js_mkerr_typed(nenv->js, err_type, "%s", msg ? msg : "");
if (is_err(error) && nenv->js->thrown_exists) {
napi_mark_pending_exception(env, (napi_value)nenv->js->thrown_value);
return napi_pending_exception;
}
return napi_set_last(env, napi_generic_failure, "failed to throw");
}
static void napi_tsfn_maybe_finish(struct napi_threadsafe_function__ *tsfn);
static void napi_tsfn_async_cb(uv_async_t *handle) {
struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)handle->data;
if (!tsfn || !tsfn->env || !tsfn->env->js) return;
ant_t *js = tsfn->env->js;
for (;;) {
napi_tsfn_item_t *item = NULL;
uv_mutex_lock(&tsfn->mutex);
if (tsfn->head) {
item = tsfn->head;
tsfn->head = item->next;
if (!tsfn->head) tsfn->tail = NULL;
tsfn->queue_size--;
}
bool done = tsfn->closing && tsfn->queue_size == 0;
uv_mutex_unlock(&tsfn->mutex);
if (!item) {
if (done) napi_tsfn_maybe_finish(tsfn);
break;
}
jsval_t cb = js_deref(js, tsfn->func_root);
if (tsfn->call_js_cb) {
tsfn->call_js_cb((napi_env)tsfn->env, (napi_value)cb, tsfn->context, item->data);
} else if (napi_is_callable(cb)) {
sv_vm_call(js->vm, js, cb, js_mkundef(), NULL, 0, NULL, false);
}
free(item);
}
}
static void napi_tsfn_close_cb(uv_handle_t *handle) {
struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)handle->data;
if (!tsfn) return;
if (tsfn->thread_finalize_cb) {
tsfn->thread_finalize_cb((napi_env)tsfn->env, tsfn->thread_finalize_data, NULL);
}
if (tsfn->env && tsfn->env->js) {
js_root_update(tsfn->env->js, tsfn->func_root, js_mkundef());
}
uv_mutex_destroy(&tsfn->mutex);
free(tsfn);
}
static void napi_tsfn_maybe_finish(struct napi_threadsafe_function__ *tsfn) {
if (!tsfn) return;
uv_close((uv_handle_t *)&tsfn->async, napi_tsfn_close_cb);
}
static void napi_async_work_execute_cb(uv_work_t *req) {
napi_async_work_impl_t *work = (napi_async_work_impl_t *)req->data;
if (!work || !work->execute) return;
work->execute((napi_env)work->env, work->data);
}
static void napi_async_work_after_cb(uv_work_t *req, int status) {
napi_async_work_impl_t *work = (napi_async_work_impl_t *)req->data;
if (!work) return;
work->queued = false;
if (work->complete) {
napi_status st = (status == UV_ECANCELED) ? napi_cancelled : napi_ok;
work->complete((napi_env)work->env, st, work->data);
}
if (work->delete_after_complete) free(work);
}
static jsval_t napi_dlopen_common(ant_t *js, jsval_t module_obj, const char *filename) {
napi_env env = ant_napi_get_env(js);
if (!env) return js_mkerr(js, "napi env allocation failed");
if (!is_object_type(module_obj)) return js_mkerr(js, "process.dlopen module must be an object");
if (!filename || !filename[0]) return js_mkerr(js, "process.dlopen filename must be a non-empty string");
void *handle = NAPI_DLOPEN(filename, NAPI_RTLD_NOW | NAPI_RTLD_GLOBAL | NAPI_RTLD_LOCAL);
if (!handle) {
const char *msg = NAPI_DLERROR();
return js_mkerr(js, "Failed to load native module '%s': %s", filename, msg ? msg : "unknown");
}
g_pending_napi_module = NULL;
napi_register_module_v1_fn reg_fn = (napi_register_module_v1_fn)NAPI_DLSYM(handle, "napi_register_module_v1");
jsval_t exports = js_get(js, module_obj, "exports");
if (!is_object_type(exports)) {
exports = js_mkobj(js);
js_set(js, module_obj, "exports", exports);
}
jsval_t ret = js_mkundef();
if (reg_fn) {
ret = (jsval_t)reg_fn(env, (napi_value)exports);
} else if (g_pending_napi_module && g_pending_napi_module->nm_register_func) {
ret = (jsval_t)g_pending_napi_module->nm_register_func(env, (napi_value)exports);
} else {
return js_mkerr(js, "No N-API registration entrypoint found in '%s'", filename);
}
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (nenv->has_pending_exception || js->thrown_exists) {
jsval_t ex = nenv->has_pending_exception
? (jsval_t)nenv->pending_exception
: js->thrown_value;
nenv->has_pending_exception = false;
nenv->pending_exception = (napi_value)js_mkundef();
return js_throw(js, ex);
}
if (is_object_type(ret)) exports = ret;
js_set(js, module_obj, "exports", exports);
js_set(js, module_obj, "loaded", js_true);
napi_native_lib_t *node = (napi_native_lib_t *)calloc(1, sizeof(*node));
if (node) {
node->handle = handle;
node->next = g_napi_native_libs;
g_napi_native_libs = node;
}
return exports;
}
jsval_t napi_process_dlopen_js(ant_t *js, jsval_t *args, int nargs) {
if (nargs < 2) return js_mkerr(js, "process.dlopen(module, filename) requires 2 arguments");
if (!is_object_type(args[0])) return js_mkerr(js, "process.dlopen module must be an object");
if (vtype(args[1]) != T_STR) return js_mkerr(js, "process.dlopen filename must be a string");
size_t path_len = 0;
const char *path = js_getstr(js, args[1], &path_len);
if (!path || path_len == 0) return js_mkerr(js, "process.dlopen filename must be non-empty");
jsval_t loaded = napi_dlopen_common(js, args[0], path);
if (is_err(loaded)) return loaded;
return js_mkundef();
}
jsval_t napi_load_native_module(ant_t *js, const char *module_path, jsval_t ns) {
if (!module_path) return js_mkerr(js, "native module path is null");
jsval_t module_obj = js_mkobj(js);
jsval_t exports_obj = js_mkobj(js);
js_set(js, module_obj, "exports", exports_obj);
js_set(js, module_obj, "filename", js_mkstr(js, module_path, strlen(module_path)));
js_set(js, module_obj, "id", js_mkstr(js, module_path, strlen(module_path)));
js_set(js, module_obj, "loaded", js_false);
jsval_t process_obj = js_get(js, js_glob(js), "process");
jsval_t dlopen_fn = is_object_type(process_obj) ? js_get(js, process_obj, "dlopen") : js_mkundef();
if (napi_is_callable(dlopen_fn)) {
jsval_t argv[2] = {module_obj, js_mkstr(js, module_path, strlen(module_path))};
jsval_t dl_res = sv_vm_call(js->vm, js, dlopen_fn, process_obj, argv, 2, NULL, false);
if (is_err(dl_res) || js->thrown_exists) return js_throw(js, js->thrown_value);
} else {
jsval_t load_res = napi_dlopen_common(js, module_obj, module_path);
if (is_err(load_res)) return load_res;
}
jsval_t exports_val = js_get(js, module_obj, "exports");
if (!is_object_type(ns)) return exports_val;
setprop_cstr(js, ns, "default", 7, exports_val);
js_set_slot(js, ns, SLOT_DEFAULT, exports_val);
if (!is_object_type(exports_val)) return exports_val;
ant_iter_t iter = js_prop_iter_begin(js, exports_val);
const char *key = NULL;
size_t key_len = 0;
jsval_t value = js_mkundef();
while (js_prop_iter_next(&iter, &key, &key_len, &value)) {
if (key_len == 7 && memcmp(key, "default", 7) == 0) continue;
setprop_cstr(js, ns, key, key_len, value);
}
js_prop_iter_end(&iter);
return exports_val;
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_last_error_info(
node_api_basic_env env,
const napi_extended_error_info **result
) {
if (!env || !result) return napi_invalid_arg;
*result = &((ant_napi_env_t *)env)->last_error;
return napi_ok;
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_undefined(napi_env env, napi_value *result) {
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = (napi_value)js_mkundef();
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_null(napi_env env, napi_value *result) {
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = (napi_value)js_mknull();
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_global(napi_env env, napi_value *result) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = (napi_value)js_glob(nenv->js);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_boolean(napi_env env, bool value, napi_value *result) {
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = (napi_value)js_bool(value);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_object(napi_env env, napi_value *result) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = (napi_value)js_mkobj(nenv->js);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_array(napi_env env, napi_value *result) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = (napi_value)js_mkarr(nenv->js);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_array_with_length(
napi_env env,
size_t length,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
jsval_t arr = js_mkarr(nenv->js);
jsval_t r = js_setprop(
nenv->js, arr,
js_mkstr(nenv->js, "length", 6),
js_mknum((double)length)
);
if (is_err(r)) return napi_check_pending_from_result(env, r);
*result = (napi_value)arr;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_double(napi_env env, double value, napi_value *result) {
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = (napi_value)js_mknum(value);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_int32(napi_env env, int32_t value, napi_value *result) {
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = (napi_value)js_mknum((double)value);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_uint32(napi_env env, uint32_t value, napi_value *result) {
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = (napi_value)js_mknum((double)value);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_int64(napi_env env, int64_t value, napi_value *result) {
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = (napi_value)js_mknum((double)value);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_latin1(
napi_env env,
const char *str,
size_t length,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result || !str) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = (napi_value)napi_make_string(nenv->js, str, length);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_utf8(
napi_env env,
const char *str,
size_t length,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result || !str) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = (napi_value)napi_make_string(nenv->js, str, length);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_symbol(
napi_env env,
napi_value description,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
const char *desc = NULL;
if (vtype((jsval_t)description) == T_STR) {
desc = js_getstr(nenv->js, (jsval_t)description, NULL);
} else if (!is_undefined((jsval_t)description) && !is_null((jsval_t)description)) {
jsval_t s = coerce_to_str(nenv->js, (jsval_t)description);
if (is_err(s)) return napi_check_pending_from_result(env, s);
desc = js_getstr(nenv->js, s, NULL);
}
*result = (napi_value)js_mksym(nenv->js, desc);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_function(
napi_env env,
const char *utf8name,
size_t length,
napi_callback cb,
void *data,
napi_value *result
) {
return napi_create_function_common(env, utf8name, length, cb, data, result);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_error(
napi_env env,
napi_value code,
napi_value msg,
napi_value *result
) {
(void)code;
return napi_make_error_object(env, "Error", msg, result);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_type_error(
napi_env env,
napi_value code,
napi_value msg,
napi_value *result
) {
(void)code;
return napi_make_error_object(env, "TypeError", msg, result);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_range_error(
napi_env env,
napi_value code,
napi_value msg,
napi_value *result
) {
(void)code;
return napi_make_error_object(env, "RangeError", msg, result);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_external(
napi_env env,
void *data,
node_api_basic_finalize finalize_cb,
void *finalize_hint,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
napi_external_entry_t *entry = (napi_external_entry_t *)calloc(1, sizeof(*entry));
if (!entry) return napi_set_last(env, napi_generic_failure, "out of memory");
entry->id = g_napi_external_next_id++;
entry->data = data;
entry->finalize_cb = finalize_cb;
entry->finalize_hint = finalize_hint;
HASH_ADD(hh, g_napi_externals, id, sizeof(entry->id), entry);
jsval_t obj = js_mkobj(nenv->js);
napi_slot_set_u64(nenv->js, obj, SLOT_NAPI_EXTERNAL_ID, entry->id);
*result = (napi_value)obj;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_promise(
napi_env env,
napi_deferred *deferred,
napi_value *promise
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !deferred || !promise) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
struct napi_deferred__ *def = (struct napi_deferred__ *)calloc(1, sizeof(*def));
if (!def) return napi_set_last(env, napi_generic_failure, "out of memory");
jsval_t p = js_mkpromise(nenv->js);
def->env = nenv;
def->promise_root = js_root(nenv->js, p);
def->settled = false;
*deferred = (napi_deferred)def;
*promise = (napi_value)p;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_resolve_deferred(
napi_env env,
napi_deferred deferred,
napi_value resolution
) {
struct napi_deferred__ *def = (struct napi_deferred__ *)deferred;
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !def || def->settled) {
return napi_set_last(env, napi_invalid_arg, "invalid deferred");
}
jsval_t promise = js_deref(nenv->js, def->promise_root);
js_resolve_promise(nenv->js, promise, (jsval_t)resolution);
def->settled = true;
js_root_update(nenv->js, def->promise_root, js_mkundef());
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_reject_deferred(
napi_env env,
napi_deferred deferred,
napi_value rejection
) {
struct napi_deferred__ *def = (struct napi_deferred__ *)deferred;
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !def || def->settled) {
return napi_set_last(env, napi_invalid_arg, "invalid deferred");
}
jsval_t promise = js_deref(nenv->js, def->promise_root);
js_reject_promise(nenv->js, promise, (jsval_t)rejection);
def->settled = true;
js_root_update(nenv->js, def->promise_root, js_mkundef());
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer(
napi_env env,
size_t length,
void **data,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
ArrayBufferData *buf = create_array_buffer_data(length);
if (!buf) return napi_set_last(env, napi_generic_failure, "allocation failed");
jsval_t value = create_typed_array(nenv->js, TYPED_ARRAY_UINT8, buf, 0, length, "Buffer");
if (is_err(value)) return napi_check_pending_from_result(env, value);
if (data) *data = buf->data;
*result = (napi_value)value;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer_copy(
napi_env env,
size_t length,
const void *data,
void **result_data,
napi_value *result
) {
void *buf_ptr = NULL;
napi_status st = napi_create_buffer(env, length, &buf_ptr, result);
if (st != napi_ok) return st;
if (length > 0 && data && buf_ptr) memcpy(buf_ptr, data, length);
if (result_data) *result_data = buf_ptr;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_external_buffer(
napi_env env,
size_t length,
void *data,
node_api_basic_finalize finalize_cb,
void *finalize_hint,
napi_value *result
) {
(void)finalize_cb;
(void)finalize_hint;
return napi_create_buffer_copy(env, length, data, NULL, result);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_arraybuffer(
napi_env env,
size_t byte_length,
void **data,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
ArrayBufferData *ab = create_array_buffer_data(byte_length);
if (!ab) return napi_set_last(env, napi_generic_failure, "allocation failed");
jsval_t ab_obj = create_arraybuffer_obj(nenv->js, ab);
free_array_buffer_data(ab);
if (data) *data = ab->data;
*result = (napi_value)ab_obj;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_external_arraybuffer(
napi_env env,
void *external_data,
size_t byte_length,
node_api_basic_finalize finalize_cb,
void *finalize_hint,
napi_value *result
) {
(void)finalize_cb;
(void)finalize_hint;
void *out = NULL;
napi_status st = napi_create_arraybuffer(env, byte_length, &out, result);
if (st != napi_ok) return st;
if (external_data && out && byte_length > 0) memcpy(out, external_data, byte_length);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_typedarray(
napi_env env,
napi_typedarray_type type,
size_t length,
napi_value arraybuffer,
size_t byte_offset,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result || !is_object_type((jsval_t)arraybuffer)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
jsval_t slot = js_get_slot(nenv->js, (jsval_t)arraybuffer, SLOT_BUFFER);
if (vtype(slot) != T_NUM) return napi_set_last(env, napi_arraybuffer_expected, "arraybuffer expected");
ArrayBufferData *ab = (ArrayBufferData *)(uintptr_t)js_getnum(slot);
if (!ab || ab->is_detached) return napi_set_last(env, napi_arraybuffer_expected, "invalid arraybuffer");
TypedArrayType ta_type;
if (!napi_to_ant_typedarray_type(type, &ta_type)) {
return napi_set_last(env, napi_invalid_arg, "invalid typedarray type");
}
size_t element_size = 1;
switch (ta_type) {
case TYPED_ARRAY_INT16:
case TYPED_ARRAY_UINT16: element_size = 2; break;
case TYPED_ARRAY_INT32:
case TYPED_ARRAY_UINT32:
case TYPED_ARRAY_FLOAT32: element_size = 4; break;
case TYPED_ARRAY_FLOAT64:
case TYPED_ARRAY_BIGINT64:
case TYPED_ARRAY_BIGUINT64: element_size = 8; break;
default: break;
}
size_t byte_len = length * element_size;
if (byte_offset + byte_len > ab->length) {
return napi_set_last(env, napi_invalid_arg, "typedarray out of bounds");
}
jsval_t out = create_typed_array_with_buffer(
nenv->js,
ta_type,
ab,
byte_offset,
length,
napi_typed_array_name(ta_type),
(jsval_t)arraybuffer
);
if (is_err(out)) return napi_check_pending_from_result(env, out);
*result = (napi_value)out;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_reference(
napi_env env,
napi_value value,
uint32_t initial_refcount,
napi_ref *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
struct napi_ref__ *ref = (struct napi_ref__ *)calloc(1, sizeof(*ref));
if (!ref) return napi_set_last(env, napi_generic_failure, "out of memory");
ref->env = nenv;
ref->value = value;
ref->refcount = initial_refcount;
ref->root = js_root(nenv->js, (jsval_t)value);
if (initial_refcount == 0) js_root_update(nenv->js, ref->root, js_mkundef());
*result = (napi_ref)ref;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_delete_reference(
node_api_basic_env env,
napi_ref ref
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
struct napi_ref__ *r = (struct napi_ref__ *)ref;
if (!nenv || !nenv->js || !r) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
js_root_update(nenv->js, r->root, js_mkundef());
free(r);
return napi_set_last((napi_env)env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_reference_ref(
napi_env env,
napi_ref ref,
uint32_t *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
struct napi_ref__ *r = (struct napi_ref__ *)ref;
if (!nenv || !nenv->js || !r) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (r->refcount == 0) js_root_update(nenv->js, r->root, (jsval_t)r->value);
r->refcount++;
if (result) *result = r->refcount;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_reference_unref(
napi_env env,
napi_ref ref,
uint32_t *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
struct napi_ref__ *r = (struct napi_ref__ *)ref;
if (!nenv || !nenv->js || !r) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (r->refcount == 0) return napi_set_last(env, napi_invalid_arg, "reference count already zero");
r->refcount--;
if (r->refcount == 0) js_root_update(nenv->js, r->root, js_mkundef());
if (result) *result = r->refcount;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_reference_value(
napi_env env,
napi_ref ref,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
struct napi_ref__ *r = (struct napi_ref__ *)ref;
if (!nenv || !nenv->js || !r || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (r->refcount > 0) *result = (napi_value)js_deref(nenv->js, r->root);
else *result = r->value;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_double(
napi_env env,
napi_value value,
double *result
) {
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (vtype((jsval_t)value) != T_NUM) return napi_set_last(env, napi_number_expected, "number expected");
*result = js_getnum((jsval_t)value);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int32(
napi_env env,
napi_value value,
int32_t *result
) {
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (vtype((jsval_t)value) != T_NUM) return napi_set_last(env, napi_number_expected, "number expected");
*result = (int32_t)js_getnum((jsval_t)value);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_uint32(
napi_env env,
napi_value value,
uint32_t *result
) {
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (vtype((jsval_t)value) != T_NUM) return napi_set_last(env, napi_number_expected, "number expected");
*result = (uint32_t)js_getnum((jsval_t)value);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int64(
napi_env env,
napi_value value,
int64_t *result
) {
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (vtype((jsval_t)value) != T_NUM) return napi_set_last(env, napi_number_expected, "number expected");
*result = (int64_t)js_getnum((jsval_t)value);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bool(
napi_env env,
napi_value value,
bool *result
) {
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (vtype((jsval_t)value) != T_BOOL) return napi_set_last(env, napi_boolean_expected, "boolean expected");
*result = ((jsval_t)value == js_true);
return napi_set_last(env, napi_ok, NULL);
}
static napi_status napi_get_string_common(
napi_env env,
napi_value value,
char *buf,
size_t bufsize,
size_t *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
if (vtype((jsval_t)value) != T_STR) return napi_set_last(env, napi_string_expected, "string expected");
size_t len = 0;
const char *str = js_getstr(nenv->js, (jsval_t)value, &len);
if (!str) return napi_set_last(env, napi_string_expected, "string expected");
if (result) *result = len;
if (!buf || bufsize == 0) return napi_set_last(env, napi_ok, NULL);
size_t n = (len < (bufsize - 1)) ? len : (bufsize - 1);
memcpy(buf, str, n);
buf[n] = '\0';
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_utf8(
napi_env env,
napi_value value,
char *buf,
size_t bufsize,
size_t *result
) {
return napi_get_string_common(env, value, buf, bufsize, result);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_latin1(
napi_env env,
napi_value value,
char *buf,
size_t bufsize,
size_t *result
) {
return napi_get_string_common(env, value, buf, bufsize, result);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_external(
napi_env env,
napi_value value,
void **result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
napi_external_entry_t *entry = napi_find_external(nenv->js, value);
if (!entry) return napi_set_last(env, napi_invalid_arg, "not an external");
*result = entry->data;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_cb_info(
napi_env env,
napi_callback_info cbinfo,
size_t *argc,
napi_value *argv,
napi_value *this_arg,
void **data
) {
struct napi_callback_info__ *info = (struct napi_callback_info__ *)cbinfo;
if (!env || !info) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (argc) {
size_t requested = *argc;
if (argv) {
size_t ncopy = requested < info->argc ? requested : info->argc;
if (ncopy > 0) memcpy(argv, info->argv, ncopy * sizeof(napi_value));
}
*argc = info->argc;
}
if (this_arg) *this_arg = info->this_arg;
if (data) *data = info->data;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_new_target(
napi_env env,
napi_callback_info cbinfo,
napi_value *result
) {
struct napi_callback_info__ *info = (struct napi_callback_info__ *)cbinfo;
if (!env || !info || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
jsval_t nt = (jsval_t)info->new_target;
*result = is_undefined(nt) ? (napi_value)0 : info->new_target;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_array_length(
napi_env env,
napi_value value,
uint32_t *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
jsval_t v = (jsval_t)value;
if (vtype(v) == T_ARR) {
*result = (uint32_t)js_arr_len(nenv->js, v);
return napi_set_last(env, napi_ok, NULL);
}
jsval_t len = js_get(nenv->js, v, "length");
if (vtype(len) != T_NUM) return napi_set_last(env, napi_array_expected, "array expected");
*result = (uint32_t)js_getnum(len);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_buffer_info(
napi_env env,
napi_value value,
void **data,
size_t *length
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
TypedArrayData *ta = NULL;
if (!napi_get_typedarray_data(nenv->js, value, &ta)) {
return napi_set_last(env, napi_invalid_arg, "not a buffer");
}
if (data) *data = ta->buffer->data + ta->byte_offset;
if (length) *length = ta->byte_length;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_arraybuffer_info(
napi_env env,
napi_value arraybuffer,
void **data,
size_t *byte_length
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
if (!is_object_type((jsval_t)arraybuffer)) return napi_set_last(env, napi_arraybuffer_expected, "arraybuffer expected");
jsval_t slot = js_get_slot(nenv->js, (jsval_t)arraybuffer, SLOT_BUFFER);
if (vtype(slot) != T_NUM) return napi_set_last(env, napi_arraybuffer_expected, "arraybuffer expected");
ArrayBufferData *ab = (ArrayBufferData *)(uintptr_t)js_getnum(slot);
if (!ab || ab->is_detached) return napi_set_last(env, napi_arraybuffer_expected, "arraybuffer expected");
if (data) *data = ab->data;
if (byte_length) *byte_length = ab->length;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_typedarray_info(
napi_env env,
napi_value typedarray,
napi_typedarray_type *type,
size_t *length,
void **data,
napi_value *arraybuffer,
size_t *byte_offset
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
TypedArrayData *ta = NULL;
if (!napi_get_typedarray_data(nenv->js, typedarray, &ta)) {
return napi_set_last(env, napi_invalid_arg, "typedarray expected");
}
if (type) *type = napi_from_ant_typedarray_type(ta->type);
if (length) *length = ta->length;
if (data) *data = ta->buffer->data + ta->byte_offset;
if (arraybuffer) *arraybuffer = (napi_value)js_get(nenv->js, (jsval_t)typedarray, "buffer");
if (byte_offset) *byte_offset = ta->byte_offset;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_prototype(
napi_env env,
napi_value object,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = (napi_value)js_get_proto(nenv->js, (jsval_t)object);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_property_names(
napi_env env,
napi_value object,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result || !is_object_type((jsval_t)object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
jsval_t out = js_mkarr(nenv->js);
ant_iter_t iter = js_prop_iter_begin(nenv->js, (jsval_t)object);
const char *key = NULL;
size_t key_len = 0;
while (js_prop_iter_next(&iter, &key, &key_len, NULL)) {
js_arr_push(nenv->js, out, js_mkstr(nenv->js, key, key_len));
}
js_prop_iter_end(&iter);
*result = (napi_value)out;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_version(
node_api_basic_env env,
uint32_t *result
) {
if (!env || !result) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
*result = 8;
return napi_set_last((napi_env)env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_node_version(
node_api_basic_env env,
const napi_node_version **version
) {
if (!env || !version) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
*version = &g_napi_node_version;
return napi_set_last((napi_env)env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_set_property(
napi_env env,
napi_value object,
napi_value key,
napi_value value
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !is_object_type((jsval_t)object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
jsval_t r = js_setprop(nenv->js, (jsval_t)object, (jsval_t)key, (jsval_t)value);
if (is_err(r)) return napi_check_pending_from_result(env, r);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_property(
napi_env env,
napi_value object,
napi_value key,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result || !is_object_type((jsval_t)object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
jsval_t k = (jsval_t)key;
if (vtype(k) == T_SYMBOL) {
jsoff_t off = lkp_sym_proto(nenv->js, (jsval_t)object, (jsoff_t)vdata(k));
*result = (napi_value)(off ? resolveprop(nenv->js, mkval(T_PROP, off)) : js_mkundef());
return napi_set_last(env, napi_ok, NULL);
}
jsval_t kstr = coerce_to_str(nenv->js, k);
if (is_err(kstr)) return napi_check_pending_from_result(env, kstr);
size_t klen = 0;
const char *ks = js_getstr(nenv->js, kstr, &klen);
if (!ks) return napi_set_last(env, napi_string_expected, "string expected");
char *name = (char *)malloc(klen + 1);
if (!name) return napi_set_last(env, napi_generic_failure, "out of memory");
memcpy(name, ks, klen);
name[klen] = '\0';
*result = (napi_value)js_getprop_fallback(nenv->js, (jsval_t)object, name);
free(name);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_has_property(
napi_env env,
napi_value object,
napi_value key,
bool *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result || !is_object_type((jsval_t)object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
jsval_t k = (jsval_t)key;
if (vtype(k) == T_SYMBOL) {
*result = lkp_sym_proto(nenv->js, (jsval_t)object, (jsoff_t)vdata(k)) != 0;
return napi_set_last(env, napi_ok, NULL);
}
jsval_t kstr = coerce_to_str(nenv->js, k);
if (is_err(kstr)) return napi_check_pending_from_result(env, kstr);
size_t len = 0;
const char *s = js_getstr(nenv->js, kstr, &len);
*result = s && lkp_proto(nenv->js, (jsval_t)object, s, len) != 0;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_delete_property(
napi_env env,
napi_value object,
napi_value key,
bool *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result || !is_object_type((jsval_t)object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
jsval_t k = (jsval_t)key;
jsval_t del_result = js_mkundef();
if (vtype(k) == T_SYMBOL) {
del_result = js_delete_sym_prop(nenv->js, (jsval_t)object, k);
} else {
jsval_t kstr = coerce_to_str(nenv->js, k);
if (is_err(kstr)) return napi_check_pending_from_result(env, kstr);
size_t len = 0;
const char *s = js_getstr(nenv->js, kstr, &len);
del_result = js_delete_prop(nenv->js, (jsval_t)object, s, len);
}
if (is_err(del_result)) return napi_check_pending_from_result(env, del_result);
*result = js_truthy(nenv->js, del_result);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_set_named_property(
napi_env env,
napi_value object,
const char *utf8name,
napi_value value
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !utf8name || !is_object_type((jsval_t)object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
js_set(nenv->js, (jsval_t)object, utf8name, (jsval_t)value);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_named_property(
napi_env env,
napi_value object,
const char *utf8name,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result || !utf8name || !is_object_type((jsval_t)object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
*result = (napi_value)js_getprop_fallback(nenv->js, (jsval_t)object, utf8name);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_has_named_property(
napi_env env,
napi_value object,
const char *utf8name,
bool *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result || !utf8name || !is_object_type((jsval_t)object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
*result = lkp_proto(nenv->js, (jsval_t)object, utf8name, strlen(utf8name)) != 0;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_set_element(
napi_env env,
napi_value object,
uint32_t index,
napi_value value
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !is_object_type((jsval_t)object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
char idx[32];
int n = snprintf(idx, sizeof(idx), "%u", index);
if (n < 0) return napi_set_last(env, napi_generic_failure, "index conversion failed");
jsval_t key = js_mkstr(nenv->js, idx, (size_t)n);
jsval_t r = js_setprop(
nenv->js, (jsval_t)object,
key, (jsval_t)value
);
if (is_err(r)) return napi_check_pending_from_result(env, r);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_element(
napi_env env,
napi_value object,
uint32_t index,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result || !is_object_type((jsval_t)object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
char idx[32];
snprintf(idx, sizeof(idx), "%u", index);
*result = (napi_value)js_get(nenv->js, (jsval_t)object, idx);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_has_element(
napi_env env,
napi_value object,
uint32_t index,
bool *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result || !is_object_type((jsval_t)object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
char idx[32];
snprintf(idx, sizeof(idx), "%u", index);
*result = lkp_proto(nenv->js, (jsval_t)object, idx, strlen(idx)) != 0;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_delete_element(
napi_env env,
napi_value object,
uint32_t index,
bool *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result || !is_object_type((jsval_t)object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
char idx[32];
snprintf(idx, sizeof(idx), "%u", index);
jsval_t del = js_delete_prop(nenv->js, (jsval_t)object, idx, strlen(idx));
if (is_err(del)) return napi_check_pending_from_result(env, del);
*result = js_truthy(nenv->js, del);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_define_properties(
napi_env env,
napi_value object,
size_t property_count,
const napi_property_descriptor *properties
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !is_object_type((jsval_t)object) || (property_count > 0 && !properties)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
for (size_t i = 0; i < property_count; i++) {
const napi_property_descriptor *p = &properties[i];
jsval_t key = js_mkundef();
const char *key_str = NULL;
size_t key_len = 0;
if (p->utf8name) {
key_str = p->utf8name;
key_len = strlen(p->utf8name);
key = js_mkstr(nenv->js, key_str, key_len);
} else key = (jsval_t)p->name;
bool is_symbol = (vtype(key) == T_SYMBOL);
if (!is_symbol && !key_str) {
if (vtype(key) != T_STR) continue;
key_str = js_getstr(nenv->js, key, &key_len);
}
jsval_t value = js_mkundef();
if (p->method) {
napi_value fn = 0;
napi_status st = napi_create_function_common(
env,
p->utf8name,
NAPI_AUTO_LENGTH,
p->method,
p->data,
&fn
);
if (st != napi_ok) return st;
value = (jsval_t)fn;
} else if (p->getter || p->setter) {
napi_value getter_fn = 0;
napi_value setter_fn = 0;
if (p->getter) {
napi_status st = napi_create_function_common(env, p->utf8name, NAPI_AUTO_LENGTH, p->getter, p->data, &getter_fn);
if (st != napi_ok) return st;
}
if (p->setter) {
napi_status st = napi_create_function_common(env, p->utf8name, NAPI_AUTO_LENGTH, p->setter, p->data, &setter_fn);
if (st != napi_ok) return st;
}
int flags = napi_desc_flags(p->attributes);
if (is_symbol) {
if (p->getter) js_set_sym_getter_desc(nenv->js, (jsval_t)object, key, (jsval_t)getter_fn, flags);
if (p->setter) js_set_sym_setter_desc(nenv->js, (jsval_t)object, key, (jsval_t)setter_fn, flags);
} else {
js_set_accessor_desc(
nenv->js,
(jsval_t)object,
key_str,
key_len,
p->getter ? (jsval_t)getter_fn : js_mkundef(),
p->setter ? (jsval_t)setter_fn : js_mkundef(),
flags
);
}
continue;
} else {
value = (jsval_t)p->value;
}
if (is_symbol) {
js_set_sym(nenv->js, (jsval_t)object, key, value);
} else {
js_set(nenv->js, (jsval_t)object, key_str, value);
js_set_descriptor(nenv->js, (jsval_t)object, key_str, key_len, napi_desc_flags(p->attributes));
}
}
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_define_class(
napi_env env,
const char *utf8name,
size_t length,
napi_callback constructor,
void *data,
size_t property_count,
const napi_property_descriptor *properties,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !constructor || !result) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
napi_status st = napi_create_function_common(
env, utf8name, length, constructor, data, result
);
if (st != napi_ok) return st;
jsval_t ctor = (jsval_t)*result;
jsval_t proto = js_get(nenv->js, ctor, "prototype");
if (!is_object_type(proto)) {
proto = js_mkobj(nenv->js);
js_set(nenv->js, ctor, "prototype", proto);
}
for (size_t i = 0; i < property_count; i++) {
napi_property_descriptor tmp = properties[i];
bool is_static = (tmp.attributes & napi_static) != 0;
tmp.attributes = (napi_property_attributes)(tmp.attributes & ~napi_static);
st = napi_define_properties(env, (napi_value)(is_static ? ctor : proto), 1, &tmp);
if (st != napi_ok) return st;
}
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_has_own_property(
napi_env env,
napi_value object,
napi_value key,
bool *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result || !is_object_type((jsval_t)object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
jsval_t k = (jsval_t)key;
if (vtype(k) == T_SYMBOL) {
*result = lkp_sym(nenv->js, (jsval_t)object, (jsoff_t)vdata(k)) != 0;
return napi_set_last(env, napi_ok, NULL);
}
jsval_t kstr = coerce_to_str(nenv->js, k);
if (is_err(kstr)) return napi_check_pending_from_result(env, kstr);
size_t len = 0;
const char *s = js_getstr(nenv->js, kstr, &len);
*result = s && lkp(nenv->js, (jsval_t)object, s, len) != 0;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_typeof(
napi_env env,
napi_value value,
napi_valuetype *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
jsval_t v = (jsval_t)value;
uint8_t t = vtype(v);
if (napi_find_external(nenv->js, value)) {
*result = napi_external;
return napi_set_last(env, napi_ok, NULL);
}
switch (t) {
case T_UNDEF: *result = napi_undefined; break;
case T_NULL: *result = napi_null; break;
case T_BOOL: *result = napi_boolean; break;
case T_NUM: *result = napi_number; break;
case T_STR: *result = napi_string; break;
case T_SYMBOL: *result = napi_symbol; break;
case T_FUNC:
case T_CFUNC: *result = napi_function; break;
case T_BIGINT: *result = napi_bigint; break;
default: *result = napi_object; break;
}
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_is_array(
napi_env env,
napi_value value,
bool *result
) {
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = vtype((jsval_t)value) == T_ARR;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_is_arraybuffer(
napi_env env,
napi_value value,
bool *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (!is_object_type((jsval_t)value)) { *result = false; return napi_set_last(env, napi_ok, NULL); }
jsval_t slot = js_get_slot(nenv->js, (jsval_t)value, SLOT_BUFFER);
if (vtype(slot) != T_NUM) {
*result = false;
} else {
jsval_t buf_prop = js_get(nenv->js, (jsval_t)value, "buffer");
*result = vtype(buf_prop) == T_UNDEF;
}
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_is_buffer(
napi_env env,
napi_value value,
bool *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
TypedArrayData *ta = NULL;
if (!napi_get_typedarray_data(nenv->js, value, &ta)) {
*result = false;
return napi_set_last(env, napi_ok, NULL);
}
jsval_t buffer_proto = js_get_ctor_proto(nenv->js, "Buffer", 6);
*result = is_object_type(buffer_proto)
&& proto_chain_contains(nenv->js, (jsval_t)value, buffer_proto);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_is_typedarray(
napi_env env,
napi_value value,
bool *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
TypedArrayData *ta = NULL;
*result = napi_get_typedarray_data(nenv->js, value, &ta);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_is_dataview(
napi_env env,
napi_value value,
bool *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (!is_object_type((jsval_t)value)) {
*result = false;
} else {
jsval_t slot = js_get_slot(nenv->js, (jsval_t)value, SLOT_DATA);
jsval_t byte_len = js_get(nenv->js, (jsval_t)value, "byteLength");
*result = vtype(slot) == T_NUM && vtype(byte_len) == T_NUM;
}
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_is_error(
napi_env env,
napi_value value,
bool *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (!is_object_type((jsval_t)value)) {
*result = false;
} else {
jsval_t et = js_get_slot(nenv->js, (jsval_t)value, SLOT_ERR_TYPE);
*result = vtype(et) == T_NUM;
}
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_is_promise(
napi_env env,
napi_value value,
bool *is_promise
) {
if (!env || !is_promise) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*is_promise = vtype((jsval_t)value) == T_PROMISE;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_instanceof(
napi_env env,
napi_value object,
napi_value constructor,
bool *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
jsval_t r = do_instanceof(nenv->js, (jsval_t)object, (jsval_t)constructor);
if (is_err(r)) return napi_check_pending_from_result(env, r);
*result = js_truthy(nenv->js, r);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_strict_equals(
napi_env env,
napi_value lhs,
napi_value rhs,
bool *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = strict_eq_values(nenv->js, (jsval_t)lhs, (jsval_t)rhs);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_call_function(
napi_env env,
napi_value recv,
napi_value func,
size_t argc,
const napi_value *argv,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !napi_is_callable((jsval_t)func)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
jsval_t out = sv_vm_call(
nenv->js->vm,
nenv->js,
(jsval_t)func,
(jsval_t)recv,
(jsval_t *)argv,
(int)argc,
NULL,
false
);
if (is_err(out) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, out);
if (result) *result = (napi_value)out;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_new_instance(
napi_env env,
napi_value constructor,
size_t argc,
const napi_value *argv,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result || !napi_is_callable((jsval_t)constructor)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
jsval_t ctor = (jsval_t)constructor;
jsval_t obj = js_mkobj(nenv->js);
jsval_t proto = js_get(nenv->js, ctor, "prototype");
if (is_object_type(proto)) js_set_proto(nenv->js, obj, proto);
jsval_t saved = nenv->js->new_target;
nenv->js->new_target = ctor;
jsval_t out = sv_vm_call(
nenv->js->vm,
nenv->js,
ctor,
obj,
(jsval_t *)argv,
(int)argc,
NULL,
true
);
nenv->js->new_target = saved;
if (is_err(out) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, out);
*result = (napi_value)(is_object_type(out) ? out : obj);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_bool(
napi_env env,
napi_value value,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = (napi_value)js_bool(js_truthy(nenv->js, (jsval_t)value));
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_number(
napi_env env,
napi_value value,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = (napi_value)js_mknum(js_to_number(nenv->js, (jsval_t)value));
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_object(
napi_env env,
napi_value value,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (is_object_type((jsval_t)value)) {
*result = value;
return napi_set_last(env, napi_ok, NULL);
}
jsval_t obj_ctor = js_get(nenv->js, js_glob(nenv->js), "Object");
if (!napi_is_callable(obj_ctor)) return napi_set_last(env, napi_generic_failure, "Object constructor missing");
jsval_t arg = (jsval_t)value;
jsval_t out = sv_vm_call(nenv->js->vm, nenv->js, obj_ctor, js_mkundef(), &arg, 1, NULL, false);
if (is_err(out) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, out);
*result = (napi_value)out;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_string(
napi_env env,
napi_value value,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
jsval_t out = coerce_to_str(nenv->js, (jsval_t)value);
if (is_err(out) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, out);
*result = (napi_value)out;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_throw(napi_env env, napi_value error) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js) return napi_set_last(env, napi_invalid_arg, "invalid env");
js_throw(nenv->js, (jsval_t)error);
napi_mark_pending_exception(env, error);
return napi_pending_exception;
}
NAPI_EXTERN napi_status NAPI_CDECL napi_throw_error(
napi_env env,
const char *code,
const char *msg
) {
(void)code;
return napi_throw_with_message(env, JS_ERR_GENERIC, msg ? msg : "");
}
NAPI_EXTERN napi_status NAPI_CDECL napi_throw_type_error(
napi_env env,
const char *code,
const char *msg
) {
(void)code;
return napi_throw_with_message(env, JS_ERR_TYPE, msg ? msg : "");
}
NAPI_EXTERN napi_status NAPI_CDECL napi_throw_range_error(
napi_env env,
const char *code,
const char *msg
) {
(void)code;
return napi_throw_with_message(env, JS_ERR_RANGE, msg ? msg : "");
}
NAPI_EXTERN napi_status NAPI_CDECL napi_is_exception_pending(
napi_env env,
bool *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
*result = nenv->has_pending_exception || nenv->js->thrown_exists;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_and_clear_last_exception(
napi_env env,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (nenv->has_pending_exception) {
*result = nenv->pending_exception;
nenv->has_pending_exception = false;
nenv->pending_exception = (napi_value)js_mkundef();
} else if (nenv->js->thrown_exists) {
*result = (napi_value)nenv->js->thrown_value;
nenv->js->thrown_exists = false;
nenv->js->thrown_value = js_mkundef();
nenv->js->thrown_stack = js_mkundef();
} else {
*result = (napi_value)js_mkundef();
}
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN void NAPI_CDECL napi_fatal_error(
const char *location,
size_t location_len,
const char *message,
size_t message_len
) {
fprintf(
stderr,
"N-API fatal error at %.*s: %.*s\n",
(int)location_len,
location ? location : "",
(int)message_len,
message ? message : ""
);
abort();
}
NAPI_EXTERN napi_status NAPI_CDECL napi_fatal_exception(napi_env env, napi_value err) {
return napi_throw(env, err);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_wrap(
napi_env env,
napi_value js_object,
void *native_object,
node_api_basic_finalize finalize_cb,
void *finalize_hint,
napi_ref *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !is_object_type((jsval_t)js_object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
napi_wrap_entry_t *entry = napi_find_wrap(nenv->js, js_object);
if (!entry) {
entry = (napi_wrap_entry_t *)calloc(1, sizeof(*entry));
if (!entry) return napi_set_last(env, napi_generic_failure, "out of memory");
entry->id = g_napi_wrap_next_id++;
HASH_ADD(hh, g_napi_wraps, id, sizeof(entry->id), entry);
napi_slot_set_u64(nenv->js, (jsval_t)js_object, SLOT_NAPI_WRAP_ID, entry->id);
}
entry->native_object = native_object;
entry->finalize_cb = finalize_cb;
entry->finalize_hint = finalize_hint;
if (result) {
return napi_create_reference(env, js_object, 0, result);
}
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_unwrap(
napi_env env,
napi_value js_object,
void **result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result || !is_object_type((jsval_t)js_object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
napi_wrap_entry_t *entry = napi_find_wrap(nenv->js, js_object);
if (!entry) return napi_set_last(env, napi_invalid_arg, "object not wrapped");
*result = entry->native_object;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_remove_wrap(
napi_env env,
napi_value js_object,
void **result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !is_object_type((jsval_t)js_object)) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
napi_wrap_entry_t *entry = napi_find_wrap(nenv->js, js_object);
if (!entry) return napi_set_last(env, napi_invalid_arg, "object not wrapped");
if (result) *result = entry->native_object;
HASH_DEL(g_napi_wraps, entry);
free(entry);
js_set_slot(nenv->js, (jsval_t)js_object, SLOT_NAPI_WRAP_ID, js_mkundef());
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_open_handle_scope(
napi_env env,
napi_handle_scope *result
) {
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
struct napi_handle_scope__ *scope = (struct napi_handle_scope__ *)calloc(1, sizeof(*scope));
if (!scope) return napi_set_last(env, napi_generic_failure, "out of memory");
scope->env = (ant_napi_env_t *)env;
*result = (napi_handle_scope)scope;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_close_handle_scope(
napi_env env,
napi_handle_scope scope
) {
(void)env;
if (!scope) return napi_set_last(env, napi_invalid_arg, "invalid argument");
free(scope);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_open_escapable_handle_scope(
napi_env env,
napi_escapable_handle_scope *result
) {
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
struct napi_escapable_handle_scope__ *scope = (struct napi_escapable_handle_scope__ *)calloc(1, sizeof(*scope));
if (!scope) return napi_set_last(env, napi_generic_failure, "out of memory");
scope->env = (ant_napi_env_t *)env;
scope->escaped = false;
*result = (napi_escapable_handle_scope)scope;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_close_escapable_handle_scope(
napi_env env,
napi_escapable_handle_scope scope
) {
(void)env;
if (!scope) return napi_set_last(env, napi_invalid_arg, "invalid argument");
free(scope);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_escape_handle(
napi_env env,
napi_escapable_handle_scope scope,
napi_value escapee,
napi_value *result
) {
struct napi_escapable_handle_scope__ *esc = (struct napi_escapable_handle_scope__ *)scope;
if (!env || !esc || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (esc->escaped) return napi_set_last(env, napi_escape_called_twice, "escape already called");
esc->escaped = true;
*result = escapee;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_async_work(
napi_env env,
napi_value async_resource,
napi_value async_resource_name,
napi_async_execute_callback execute,
napi_async_complete_callback complete,
void *data,
napi_async_work *result
) {
(void)async_resource;
(void)async_resource_name;
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !execute || !result) {
return napi_set_last(env, napi_invalid_arg, "invalid argument");
}
napi_async_work_impl_t *work = (napi_async_work_impl_t *)calloc(1, sizeof(*work));
if (!work) return napi_set_last(env, napi_generic_failure, "out of memory");
work->env = nenv;
work->execute = execute;
work->complete = complete;
work->data = data;
work->req.data = work;
*result = (napi_async_work)work;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_delete_async_work(
napi_env env,
napi_async_work work
) {
(void)env;
napi_async_work_impl_t *w = (napi_async_work_impl_t *)work;
if (!w) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (w->queued) {
w->delete_after_complete = true;
return napi_set_last(env, napi_ok, NULL);
}
free(w);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_queue_async_work(
node_api_basic_env env,
napi_async_work work
) {
napi_async_work_impl_t *w = (napi_async_work_impl_t *)work;
if (!env || !w) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
if (w->queued) return napi_set_last((napi_env)env, napi_invalid_arg, "already queued");
int rc = uv_queue_work(uv_default_loop(), &w->req, napi_async_work_execute_cb, napi_async_work_after_cb);
if (rc != 0) return napi_set_last((napi_env)env, napi_generic_failure, "uv_queue_work failed");
w->queued = true;
return napi_set_last((napi_env)env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_cancel_async_work(
node_api_basic_env env,
napi_async_work work
) {
napi_async_work_impl_t *w = (napi_async_work_impl_t *)work;
if (!env || !w) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
int rc = uv_cancel((uv_req_t *)&w->req);
if (rc != 0) return napi_set_last((napi_env)env, napi_generic_failure, "uv_cancel failed");
return napi_set_last((napi_env)env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_create_threadsafe_function(
napi_env env,
napi_value func,
napi_value async_resource,
napi_value async_resource_name,
size_t max_queue_size,
size_t initial_thread_count,
void *thread_finalize_data,
napi_finalize thread_finalize_cb,
void *context,
napi_threadsafe_function_call_js call_js_cb,
napi_threadsafe_function *result
) {
(void)async_resource;
(void)async_resource_name;
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
struct napi_threadsafe_function__ *tsfn =
(struct napi_threadsafe_function__ *)calloc(1, sizeof(*tsfn));
if (!tsfn) return napi_set_last(env, napi_generic_failure, "out of memory");
tsfn->env = nenv;
tsfn->call_js_cb = call_js_cb;
tsfn->thread_finalize_cb = thread_finalize_cb;
tsfn->thread_finalize_data = thread_finalize_data;
tsfn->context = context;
tsfn->max_queue_size = max_queue_size;
tsfn->thread_count = initial_thread_count > 0 ? initial_thread_count : 1;
tsfn->func_root = js_root(nenv->js, (jsval_t)func);
uv_mutex_init(&tsfn->mutex);
int rc = uv_async_init(uv_default_loop(), &tsfn->async, napi_tsfn_async_cb);
if (rc != 0) {
uv_mutex_destroy(&tsfn->mutex);
free(tsfn);
return napi_set_last(env, napi_generic_failure, "uv_async_init failed");
}
tsfn->async.data = tsfn;
*result = (napi_threadsafe_function)tsfn;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_call_threadsafe_function(
napi_threadsafe_function func,
void *data,
napi_threadsafe_function_call_mode is_blocking
) {
(void)is_blocking;
struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)func;
if (!tsfn) return napi_invalid_arg;
uv_mutex_lock(&tsfn->mutex);
if (tsfn->closing || tsfn->aborted) {
uv_mutex_unlock(&tsfn->mutex);
return napi_closing;
}
if (tsfn->max_queue_size > 0 && tsfn->queue_size >= tsfn->max_queue_size) {
uv_mutex_unlock(&tsfn->mutex);
return napi_queue_full;
}
napi_tsfn_item_t *item = (napi_tsfn_item_t *)calloc(1, sizeof(*item));
if (!item) {
uv_mutex_unlock(&tsfn->mutex);
return napi_generic_failure;
}
item->data = data;
if (!tsfn->head) tsfn->head = item;
else tsfn->tail->next = item;
tsfn->tail = item;
tsfn->queue_size++;
uv_mutex_unlock(&tsfn->mutex);
uv_async_send(&tsfn->async);
return napi_ok;
}
NAPI_EXTERN napi_status NAPI_CDECL napi_release_threadsafe_function(
napi_threadsafe_function func,
napi_threadsafe_function_release_mode mode
) {
struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)func;
if (!tsfn) return napi_invalid_arg;
uv_mutex_lock(&tsfn->mutex);
if (mode == napi_tsfn_abort) tsfn->aborted = true;
if (tsfn->thread_count > 0) tsfn->thread_count--;
if (tsfn->thread_count == 0 || tsfn->aborted) tsfn->closing = true;
uv_mutex_unlock(&tsfn->mutex);
uv_async_send(&tsfn->async);
return napi_ok;
}
NAPI_EXTERN napi_status NAPI_CDECL napi_acquire_threadsafe_function(
napi_threadsafe_function func
) {
struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)func;
if (!tsfn) return napi_invalid_arg;
uv_mutex_lock(&tsfn->mutex);
if (tsfn->closing) {
uv_mutex_unlock(&tsfn->mutex);
return napi_closing;
}
tsfn->thread_count++;
uv_mutex_unlock(&tsfn->mutex);
return napi_ok;
}
NAPI_EXTERN napi_status NAPI_CDECL napi_ref_threadsafe_function(
node_api_basic_env env,
napi_threadsafe_function func
) {
(void)env;
struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)func;
if (!tsfn) return napi_invalid_arg;
uv_ref((uv_handle_t *)&tsfn->async);
return napi_ok;
}
NAPI_EXTERN napi_status NAPI_CDECL napi_unref_threadsafe_function(
node_api_basic_env env,
napi_threadsafe_function func
) {
(void)env;
struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)func;
if (!tsfn) return napi_invalid_arg;
uv_unref((uv_handle_t *)&tsfn->async);
return napi_ok;
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_threadsafe_function_context(
napi_threadsafe_function func,
void **result
) {
struct napi_threadsafe_function__ *tsfn = (struct napi_threadsafe_function__ *)func;
if (!tsfn || !result) return napi_invalid_arg;
*result = tsfn->context;
return napi_ok;
}
NAPI_EXTERN napi_status NAPI_CDECL napi_run_script(
napi_env env,
napi_value script,
napi_value *result
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !nenv->js || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
if (vtype((jsval_t)script) != T_STR) return napi_set_last(env, napi_string_expected, "script must be string");
size_t len = 0;
const char *src = js_getstr(nenv->js, (jsval_t)script, &len);
if (!src) return napi_set_last(env, napi_string_expected, "script must be string");
jsval_t out = js_eval_bytecode_eval(nenv->js, src, len);
if (is_err(out) || nenv->js->thrown_exists) return napi_check_pending_from_result(env, out);
*result = (napi_value)out;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_adjust_external_memory(
node_api_basic_env env,
int64_t change_in_bytes,
int64_t *adjusted_value
) {
if (!env) return napi_invalid_arg;
g_napi_external_memory += change_in_bytes;
if (adjusted_value) *adjusted_value = g_napi_external_memory;
return napi_set_last((napi_env)env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_add_env_cleanup_hook(
node_api_basic_env env,
napi_cleanup_hook fun,
void *arg
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !fun) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
napi_cleanup_hook_entry_t *entry = (napi_cleanup_hook_entry_t *)calloc(1, sizeof(*entry));
if (!entry) return napi_set_last((napi_env)env, napi_generic_failure, "out of memory");
entry->hook = fun;
entry->arg = arg;
entry->next = nenv->cleanup_hooks;
nenv->cleanup_hooks = entry;
return napi_set_last((napi_env)env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_remove_env_cleanup_hook(
node_api_basic_env env,
napi_cleanup_hook fun,
void *arg
) {
ant_napi_env_t *nenv = (ant_napi_env_t *)env;
if (!nenv || !fun) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
napi_cleanup_hook_entry_t **pp = &nenv->cleanup_hooks;
while (*pp) {
if ((*pp)->hook == fun && (*pp)->arg == arg) {
napi_cleanup_hook_entry_t *victim = *pp;
*pp = victim->next;
free(victim);
return napi_set_last((napi_env)env, napi_ok, NULL);
}
pp = &(*pp)->next;
}
return napi_set_last((napi_env)env, napi_invalid_arg, "cleanup hook not found");
}
NAPI_EXTERN napi_status NAPI_CDECL napi_open_callback_scope(
napi_env env,
napi_value resource_object,
napi_async_context context,
napi_callback_scope *result
) {
(void)resource_object;
(void)context;
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
struct napi_callback_scope__ *scope = (struct napi_callback_scope__ *)calloc(1, sizeof(*scope));
if (!scope) return napi_set_last(env, napi_generic_failure, "out of memory");
scope->env = (ant_napi_env_t *)env;
*result = (napi_callback_scope)scope;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_close_callback_scope(
napi_env env,
napi_callback_scope scope
) {
(void)env;
if (!scope) return napi_set_last(env, napi_invalid_arg, "invalid argument");
free(scope);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_async_init(
napi_env env,
napi_value async_resource,
napi_value async_resource_name,
napi_async_context *result
) {
(void)async_resource;
(void)async_resource_name;
if (!env || !result) return napi_set_last(env, napi_invalid_arg, "invalid argument");
struct napi_async_context__ *ctx = (struct napi_async_context__ *)calloc(1, sizeof(*ctx));
if (!ctx) return napi_set_last(env, napi_generic_failure, "out of memory");
ctx->env = (ant_napi_env_t *)env;
*result = (napi_async_context)ctx;
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_async_destroy(
napi_env env,
napi_async_context async_context
) {
(void)env;
if (!async_context) return napi_set_last(env, napi_invalid_arg, "invalid argument");
free(async_context);
return napi_set_last(env, napi_ok, NULL);
}
NAPI_EXTERN napi_status NAPI_CDECL napi_make_callback(
napi_env env,
napi_async_context async_context,
napi_value recv,
napi_value func,
size_t argc,
const napi_value *argv,
napi_value *result
) {
(void)async_context;
return napi_call_function(env, recv, func, argc, argv, result);
}
NAPI_EXTERN void NAPI_CDECL napi_module_register(napi_module *mod) {
g_pending_napi_module = mod;
}
NAPI_EXTERN napi_status NAPI_CDECL napi_get_uv_event_loop(
node_api_basic_env env,
struct uv_loop_s **loop
) {
if (!env || !loop) return napi_set_last((napi_env)env, napi_invalid_arg, "invalid argument");
*loop = uv_default_loop();
return napi_set_last((napi_env)env, napi_ok, NULL);
}

File Metadata

Mime Type
text/x-c
Expires
Thu, Mar 26, 4:46 PM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
511716
Default Alt Text
napi.c (84 KB)

Event Timeline