From: Dmitry Volyntsev Date: Fri, 22 Sep 2023 20:00:05 +0000 (-0700) Subject: Introduced API to work with external value pointers. X-Git-Tag: 0.8.2~18 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=4dc53be1f4d7627821cdcb388daeaf86b854f988;p=njs.git Introduced API to work with external value pointers. This allows to allocate the necessary context for external code on demand. --- diff --git a/src/njs.h b/src/njs.h index ce3d81eb..d019036f 100644 --- a/src/njs.h +++ b/src/njs.h @@ -532,12 +532,15 @@ NJS_EXPORT void njs_value_boolean_set(njs_value_t *value, int yn); 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_number(const njs_value_t *value); 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 --git a/src/njs_value.c b/src/njs_value.c index 407baed9..6d3af8e0 100644 --- a/src/njs_value.c +++ b/src/njs_value.c @@ -466,6 +466,15 @@ njs_value_function_set(njs_value_t *value, njs_function_t *function) } +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_value_t *value) } +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) { @@ -576,6 +594,13 @@ njs_value_is_error(const njs_value_t *value) } +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) { diff --git a/src/test/njs_externals_test.c b/src/test/njs_externals_test.c index c4230877..4238fa35 100644 --- a/src/test/njs_externals_test.c +++ b/src/test/njs_externals_test.c @@ -33,6 +33,7 @@ njs_int_t njs_array_buffer_detach(njs_vm_t *vm, njs_value_t *args, 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; @@ -555,6 +556,67 @@ njs_unit_test_r_bind(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } +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_external[] = { }; +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_req_init_t *init, 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, njs_unit_test_req_init_t *init, 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 --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index b94e8391..1078f763 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -22637,7 +22637,8 @@ static njs_unit_test_t njs_externals_test[] = #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") }, };