diff options
author | Jason Ginchereau <jasongin@microsoft.com> | 2017-05-26 03:05:21 +0300 |
---|---|---|
committer | Jason Ginchereau <jasongin@microsoft.com> | 2017-06-01 21:46:55 +0300 |
commit | 8ab8c33985b273cd682842a26091da53ce3c3048 (patch) | |
tree | 7fee259a85ecc33139a4dd12b2de7db7a032674c /test/addons-napi/test_object | |
parent | 9b730620a741644d2df7b8c64559a6d2eea7c283 (diff) |
n-api: enable napi_wrap() to work with any object
Previously, napi_wrap() would only work with objects created from a
constructor returned by napi_define_class(). While the N-API team
was aware of this limitation, it was not clearly documented and is
likely to cause confusion anyway. It's much simpler if addons are
allowed to use any JS object. Also, the specific behavior of the
limitation is difficult to reimplement on other VMs that work
differently from V8.
V8 requires object internal fields to be declared on the object
prototype (which napi_define_class() used to do). Since it's too
late to modify the object prototype by the time napi_wrap() is
called, napi_wrap() now inserts a new object (with the internal
field) into the supplied object's prototype chain. Then it can be
retrieved from there later by napi_unwrap().
This change also includes improvements to the documentation for
napi_create_external(), partly to explain how it is different from
napi_wrap().
PR-URL: https://github.com/nodejs/node/pull/13250
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Diffstat (limited to 'test/addons-napi/test_object')
-rw-r--r-- | test/addons-napi/test_object/test.js | 98 | ||||
-rw-r--r-- | test/addons-napi/test_object/test_object.c | 27 |
2 files changed, 95 insertions, 30 deletions
diff --git a/test/addons-napi/test_object/test.js b/test/addons-napi/test_object/test.js index d14a15421fe..4b64fa4b381 100644 --- a/test/addons-napi/test_object/test.js +++ b/test/addons-napi/test_object/test.js @@ -31,35 +31,73 @@ assert(test_object.Has(newObject, 'test_number')); assert.strictEqual(newObject.test_number, 987654321); assert.strictEqual(newObject.test_string, 'test string'); -// test_object.Inflate increases all properties by 1 -const cube = { - x: 10, - y: 10, - z: 10 -}; +{ + // test_object.Inflate increases all properties by 1 + const cube = { + x: 10, + y: 10, + z: 10 + }; -assert.deepStrictEqual(test_object.Inflate(cube), {x: 11, y: 11, z: 11}); -assert.deepStrictEqual(test_object.Inflate(cube), {x: 12, y: 12, z: 12}); -assert.deepStrictEqual(test_object.Inflate(cube), {x: 13, y: 13, z: 13}); -cube.t = 13; -assert.deepStrictEqual(test_object.Inflate(cube), {x: 14, y: 14, z: 14, t: 14}); - -const sym1 = Symbol('1'); -const sym2 = Symbol('2'); -const sym3 = Symbol('3'); -const sym4 = Symbol('4'); -const object2 = { - [sym1]: '@@iterator', - [sym2]: sym3 -}; + assert.deepStrictEqual(test_object.Inflate(cube), {x: 11, y: 11, z: 11}); + assert.deepStrictEqual(test_object.Inflate(cube), {x: 12, y: 12, z: 12}); + assert.deepStrictEqual(test_object.Inflate(cube), {x: 13, y: 13, z: 13}); + cube.t = 13; + assert.deepStrictEqual( + test_object.Inflate(cube), {x: 14, y: 14, z: 14, t: 14}); + + const sym1 = Symbol('1'); + const sym2 = Symbol('2'); + const sym3 = Symbol('3'); + const sym4 = Symbol('4'); + const object2 = { + [sym1]: '@@iterator', + [sym2]: sym3 + }; + + assert(test_object.Has(object2, sym1)); + assert(test_object.Has(object2, sym2)); + assert.strictEqual(test_object.Get(object2, sym1), '@@iterator'); + assert.strictEqual(test_object.Get(object2, sym2), sym3); + assert(test_object.Set(object2, 'string', 'value')); + assert(test_object.Set(object2, sym4, 123)); + assert(test_object.Has(object2, 'string')); + assert(test_object.Has(object2, sym4)); + assert.strictEqual(test_object.Get(object2, 'string'), 'value'); + assert.strictEqual(test_object.Get(object2, sym4), 123); +} + +{ + // Wrap a pointer in a JS object, then verify the pointer can be unwrapped. + const wrapper = {}; + test_object.Wrap(wrapper); + + assert(test_object.Unwrap(wrapper)); +} + +{ + // Verify that wrapping doesn't break an object's prototype chain. + const wrapper = {}; + const protoA = { protoA: true }; + Object.setPrototypeOf(wrapper, protoA); + test_object.Wrap(wrapper); + + assert(test_object.Unwrap(wrapper)); + assert(wrapper.protoA); +} + +{ + // Verify the pointer can be unwrapped after inserting in the prototype chain. + const wrapper = {}; + const protoA = { protoA: true }; + Object.setPrototypeOf(wrapper, protoA); + test_object.Wrap(wrapper); + + const protoB = { protoB: true }; + Object.setPrototypeOf(protoB, Object.getPrototypeOf(wrapper)); + Object.setPrototypeOf(wrapper, protoB); -assert(test_object.Has(object2, sym1)); -assert(test_object.Has(object2, sym2)); -assert.strictEqual(test_object.Get(object2, sym1), '@@iterator'); -assert.strictEqual(test_object.Get(object2, sym2), sym3); -assert(test_object.Set(object2, 'string', 'value')); -assert(test_object.Set(object2, sym4, 123)); -assert(test_object.Has(object2, 'string')); -assert(test_object.Has(object2, sym4)); -assert.strictEqual(test_object.Get(object2, 'string'), 'value'); -assert.strictEqual(test_object.Get(object2, sym4), 123); + assert(test_object.Unwrap(wrapper)); + assert(wrapper.protoA, true); + assert(wrapper.protoB, true); +} diff --git a/test/addons-napi/test_object/test_object.c b/test/addons-napi/test_object/test_object.c index 9e02c1d0bb7..dd2db123f74 100644 --- a/test/addons-napi/test_object/test_object.c +++ b/test/addons-napi/test_object/test_object.c @@ -1,6 +1,7 @@ #include <node_api.h> #include "../common.h" #include <string.h> +#include <stdlib.h> napi_value Get(napi_env env, napi_callback_info info) { size_t argc = 2; @@ -138,6 +139,30 @@ napi_value Inflate(napi_env env, napi_callback_info info) { return obj; } +napi_value Wrap(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value arg; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &arg, NULL, NULL)); + + int32_t* data = malloc(sizeof(int32_t)); + *data = 3; + NAPI_CALL(env, napi_wrap(env, arg, data, NULL, NULL, NULL)); + return NULL; +} + +napi_value Unwrap(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value arg; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &arg, NULL, NULL)); + + int32_t* data; + NAPI_CALL(env, napi_unwrap(env, arg, &data)); + + napi_value result; + NAPI_CALL(env, napi_get_boolean(env, data != NULL && *data == 3, &result)); + return result; +} + void Init(napi_env env, napi_value exports, napi_value module, void* priv) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("Get", Get), @@ -145,6 +170,8 @@ void Init(napi_env env, napi_value exports, napi_value module, void* priv) { DECLARE_NAPI_PROPERTY("Has", Has), DECLARE_NAPI_PROPERTY("New", New), DECLARE_NAPI_PROPERTY("Inflate", Inflate), + DECLARE_NAPI_PROPERTY("Wrap", Wrap), + DECLARE_NAPI_PROPERTY("Unwrap", Unwrap), }; NAPI_CALL_RETURN_VOID(env, napi_define_properties( |