[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