[njs] Introduced API to work with external value pointers.
Dmitry Volyntsev
xeioex at nginx.com
Sat Sep 23 00:39:20 UTC 2023
details: https://hg.nginx.org/njs/rev/cf7e8f006bd8
branches:
changeset: 2207:cf7e8f006bd8
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Fri Sep 22 13:00:05 2023 -0700
description:
Introduced API to work with external value pointers.
This allows to allocate the necessary context for external
code on demand.
diffstat:
src/njs.h | 5 +
src/njs_value.c | 25 ++++++++
src/test/njs_externals_test.c | 117 ++++++++++++++++++++++++++++++++++++++++++
src/test/njs_unit_test.c | 16 +++++-
4 files changed, 162 insertions(+), 1 deletions(-)
diffs (265 lines):
diff -r dbb011e433b2 -r cf7e8f006bd8 src/njs.h
--- a/src/njs.h Fri Sep 22 13:00:04 2023 -0700
+++ b/src/njs.h Fri Sep 22 13:00:05 2023 -0700
@@ -532,12 +532,15 @@ NJS_EXPORT void njs_value_boolean_set(nj
NJS_EXPORT void njs_value_number_set(njs_value_t *value, double num);
NJS_EXPORT void njs_value_function_set(njs_value_t *value,
njs_function_t *function);
+NJS_EXPORT void njs_value_external_set(njs_value_t *value,
+ njs_external_ptr_t external);
NJS_EXPORT uint8_t njs_value_bool(const njs_value_t *value);
NJS_EXPORT double njs_value_number(const njs_value_t *value);
NJS_EXPORT njs_function_t *njs_value_function(const njs_value_t *value);
NJS_EXPORT njs_function_native_t njs_value_native_function(
const njs_value_t *value);
+njs_external_ptr_t njs_value_external(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_external_tag(const njs_value_t *value);
NJS_EXPORT uint16_t njs_vm_prop_magic16(njs_object_prop_t *prop);
@@ -555,6 +558,8 @@ NJS_EXPORT njs_int_t njs_value_is_valid_
NJS_EXPORT njs_int_t njs_value_is_string(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_object(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_error(const njs_value_t *value);
+NJS_EXPORT njs_int_t njs_value_is_external(const njs_value_t *value,
+ njs_int_t proto_id);
NJS_EXPORT njs_int_t njs_value_is_array(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_function(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_buffer(const njs_value_t *value);
diff -r dbb011e433b2 -r cf7e8f006bd8 src/njs_value.c
--- a/src/njs_value.c Fri Sep 22 13:00:04 2023 -0700
+++ b/src/njs_value.c Fri Sep 22 13:00:05 2023 -0700
@@ -466,6 +466,15 @@ njs_value_function_set(njs_value_t *valu
}
+void
+njs_value_external_set(njs_value_t *value, njs_external_ptr_t external)
+{
+ njs_assert(njs_value_is_external(value, NJS_PROTO_ID_ANY));
+
+ njs_object_data(value) = external;
+}
+
+
uint8_t
njs_value_bool(const njs_value_t *value)
{
@@ -504,6 +513,15 @@ njs_value_native_function(const njs_valu
}
+njs_external_ptr_t
+njs_value_external(const njs_value_t *value)
+{
+ njs_assert(njs_value_is_external(value, NJS_PROTO_ID_ANY));
+
+ return njs_object_data(value);
+}
+
+
njs_int_t
njs_value_is_null(const njs_value_t *value)
{
@@ -577,6 +595,13 @@ njs_value_is_error(const njs_value_t *va
njs_int_t
+njs_value_is_external(const njs_value_t *value, njs_int_t proto_id)
+{
+ return njs_is_object_data(value, njs_make_tag(proto_id));
+}
+
+
+njs_int_t
njs_value_is_array(const njs_value_t *value)
{
return njs_is_array(value);
diff -r dbb011e433b2 -r cf7e8f006bd8 src/test/njs_externals_test.c
--- a/src/test/njs_externals_test.c Fri Sep 22 13:00:04 2023 -0700
+++ b/src/test/njs_externals_test.c Fri Sep 22 13:00:05 2023 -0700
@@ -33,6 +33,7 @@ njs_int_t njs_array_buffer_detach(njs_vm
static njs_int_t njs_external_r_proto_id;
+static njs_int_t njs_external_null_proto_id;
static njs_int_t njs_external_error_ctor_id;
@@ -556,6 +557,67 @@ njs_unit_test_r_bind(njs_vm_t *vm, njs_v
static njs_int_t
+njs_unit_test_null_get(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused, njs_value_t *retval)
+{
+ double *d;
+ njs_value_t *this;
+
+ this = njs_argument(args, 0);
+
+ if (!njs_value_is_external(this, njs_external_null_proto_id)) {
+ njs_type_error(vm, "\"this\" is not a null external");
+ return NJS_ERROR;
+ }
+
+ d = njs_value_external(this);
+
+ if (d == NULL) {
+ njs_value_undefined_set(retval);
+
+ } else {
+ njs_value_number_set(retval, *d);
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_unit_test_null_set(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused, njs_value_t *retval)
+{
+ double *d;
+ njs_value_t *this;
+
+ this = njs_argument(args, 0);
+
+ if (!njs_value_is_external(this, njs_external_null_proto_id)) {
+ njs_type_error(vm, "\"this\" is not a null external");
+ return NJS_ERROR;
+ }
+
+ d = njs_value_external(this);
+
+ if (d == NULL) {
+ d = njs_mp_alloc(vm->mem_pool, sizeof(double));
+ if (d == NULL) {
+ njs_memory_error(vm);
+ return NJS_ERROR;
+ }
+ }
+
+ *d = njs_value_number(njs_arg(args, nargs, 1));
+
+ njs_value_external_set(this, d);
+
+ njs_value_undefined_set(retval);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
njs_unit_test_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused, njs_value_t *retval)
{
@@ -1043,6 +1105,40 @@ static njs_external_t njs_unit_test_r_e
};
+static njs_external_t njs_unit_test_null_external[] = {
+
+ {
+ .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
+ .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
+ .u.property = {
+ .value = "Null",
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("get"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = njs_unit_test_null_get,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("set"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = njs_unit_test_null_set,
+ }
+ },
+
+};
+
static njs_external_t njs_unit_test_ctor_props[] = {
@@ -1170,6 +1266,7 @@ njs_externals_init_internal(njs_vm_t *vm
njs_unit_test_prop_t *prop;
static const njs_str_t external_ctor = njs_str("ExternalConstructor");
+ static const njs_str_t external_null = njs_str("ExternalNull");
static const njs_str_t external_error = njs_str("ExternalError");
if (shared) {
@@ -1195,6 +1292,26 @@ njs_externals_init_internal(njs_vm_t *vm
return NJS_ERROR;
}
+ njs_external_null_proto_id = njs_vm_external_prototype(vm,
+ njs_unit_test_null_external,
+ njs_nitems(njs_unit_test_null_external));
+ if (njs_slow_path(njs_external_null_proto_id < 0)) {
+ njs_printf("njs_vm_external_prototype() failed\n");
+ return NJS_ERROR;
+ }
+
+ ret = njs_vm_external_create(vm, njs_value_arg(&value),
+ njs_external_null_proto_id, NULL, 1);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ ret = njs_vm_bind(vm, &external_null, njs_value_arg(&value), 1);
+ if (njs_slow_path(ret != NJS_OK)) {
+ njs_printf("njs_vm_bind() failed\n");
+ return NJS_ERROR;
+ }
+
njs_external_error_ctor_id =
njs_vm_external_constructor(vm, &external_error,
njs_error_constructor, njs_unit_test_ctor_props,
diff -r dbb011e433b2 -r cf7e8f006bd8 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c Fri Sep 22 13:00:04 2023 -0700
+++ b/src/test/njs_unit_test.c Fri Sep 22 13:00:05 2023 -0700
@@ -22637,7 +22637,8 @@ static njs_unit_test_t njs_externals_te
#endif
{ njs_str("Object.keys(this).sort()"),
- njs_str("$262,$r,$r2,$r3,$shared,ExternalConstructor,ExternalError," NCRYPTO "global,njs,process") },
+ njs_str("$262,$r,$r2,$r3,$shared,ExternalConstructor,ExternalError,"
+ "ExternalNull," NCRYPTO "global,njs,process") },
{ njs_str("Object.getOwnPropertySymbols($r2)[0] == Symbol.toStringTag"),
njs_str("true") },
@@ -22924,6 +22925,19 @@ static njs_unit_test_t njs_shared_test[
{ njs_str("var sum = new Function('a, b', 'return a + b');"
"sum(2, 4);"),
njs_str("6") },
+
+ { njs_str("ExternalNull.get()"),
+ njs_str("undefined") },
+
+ { njs_str("ExternalNull.set(37); ExternalNull.get()"),
+ njs_str("37") },
+
+ { njs_str("ExternalNull.set(23); ExternalNull.set(37); ExternalNull.get()"),
+ njs_str("37") },
+
+ { njs_str("var v = Math.round(Math.random() * 1000); ExternalNull.set(v);"
+ "ExternalNull.get() == v"),
+ njs_str("true") },
};
More information about the nginx-devel
mailing list