diff --git a/src/weakref.cc b/src/weakref.cc index 4eea618..32f0790 100644 --- a/src/weakref.cc +++ b/src/weakref.cc @@ -34,11 +34,24 @@ Nan::Persistent proxyClass; Nan::Callback *globalCallback; +// Field index used to store the container object. +#define FIELD_INDEX_CONTAINER (0) + +// Field index used to store the unique pointer value used to identify objects +// as instances created by this module). +#define FIELD_INDEX_IDENT (1) + +// Count of internal fields used by instances created by this module. +#define FIELD_COUNT (2) + +// The value stored at `FIELD_INDEX_IDENT`, which is designed to be unique to +// this module, barring intentional mischief from other native code. +#define IDENT_VALUE ((void *) &proxyClass) bool IsDead(Local proxy) { - assert(proxy->InternalFieldCount() == 1); + assert(proxy->InternalFieldCount() == FIELD_COUNT); proxy_container *cont = reinterpret_cast( - Nan::GetInternalFieldPointer(proxy, 0) + Nan::GetInternalFieldPointer(proxy, FIELD_INDEX_CONTAINER) ); return cont == NULL || cont->target.IsEmpty(); } @@ -47,7 +60,7 @@ bool IsDead(Local proxy) { Local Unwrap(Local proxy) { assert(!IsDead(proxy)); proxy_container *cont = reinterpret_cast( - Nan::GetInternalFieldPointer(proxy, 0) + Nan::GetInternalFieldPointer(proxy, FIELD_INDEX_CONTAINER) ); Local _target = Nan::New(cont->target); return _target; @@ -55,7 +68,7 @@ Local Unwrap(Local proxy) { Local GetEmitter(Local proxy) { proxy_container *cont = reinterpret_cast( - Nan::GetInternalFieldPointer(proxy, 0) + Nan::GetInternalFieldPointer(proxy, FIELD_INDEX_CONTAINER) ); assert(cont != NULL); Local _emitter = Nan::New(cont->emitter); @@ -68,7 +81,6 @@ Local GetEmitter(Local proxy) { const bool dead = IsDead(info.This()); \ if (!dead) obj = Unwrap(info.This()); \ - NAN_PROPERTY_GETTER(WeakNamedPropertyGetter) { UNWRAP info.GetReturnValue().Set(dead ? Local() : Nan::Get(obj, property).ToLocalChecked()); @@ -148,7 +160,7 @@ static void TargetCallback(const Nan::WeakCallbackInfo &info) { // clean everything up Local proxy = Nan::New(cont->proxy); - Nan::SetInternalFieldPointer(proxy, 0, NULL); + Nan::SetInternalFieldPointer(proxy, FIELD_INDEX_CONTAINER, NULL); cont->proxy.Reset(); cont->emitter.Reset(); delete cont; @@ -169,19 +181,23 @@ NAN_METHOD(Create) { cont->proxy.Reset(proxy); cont->emitter.Reset(_emitter); cont->target.Reset(_target); - Nan::SetInternalFieldPointer(proxy, 0, cont); + Nan::SetInternalFieldPointer(proxy, FIELD_INDEX_CONTAINER, cont); + Nan::SetInternalFieldPointer(proxy, FIELD_INDEX_IDENT, IDENT_VALUE); cont->target.SetWeak(cont, TargetCallback, Nan::WeakCallbackType::kParameter); info.GetReturnValue().Set(proxy); } -/** - * TODO: Make this better. - */ - bool isWeakRef (Local val) { - return val->IsObject() && val.As()->InternalFieldCount() == 1; + if (!val->IsObject()) { + return false; + } + + Local obj = val.As(); + + return obj->InternalFieldCount() == FIELD_COUNT + && Nan::GetInternalFieldPointer(obj, FIELD_INDEX_IDENT) == IDENT_VALUE; } /** @@ -216,7 +232,7 @@ NAN_METHOD(IsNearDeath) { WEAKREF_FIRST_ARG proxy_container *cont = reinterpret_cast( - Nan::GetInternalFieldPointer(proxy, 0) + Nan::GetInternalFieldPointer(proxy, FIELD_INDEX_CONTAINER) ); assert(cont != NULL); @@ -273,7 +289,7 @@ NAN_MODULE_INIT(Initialize) { WeakIndexedPropertyQuery, WeakIndexedPropertyDeleter, WeakPropertyEnumerator); - p->SetInternalFieldCount(1); + p->SetInternalFieldCount(FIELD_COUNT); Nan::SetMethod(target, "get", Get); Nan::SetMethod(target, "isWeakRef", IsWeakRef); diff --git a/test/create.js b/test/create.js index 70b30e2..2889325 100644 --- a/test/create.js +++ b/test/create.js @@ -20,4 +20,9 @@ describe('create()', function () { }) }) + it('should acknowledge the weakness of created values', function () { + var ref = weak.create([]); + assert(weak.isWeakRef(ref)); + }) + }) diff --git a/test/promise.js b/test/promise.js new file mode 100644 index 0000000..55c1812 --- /dev/null +++ b/test/promise.js @@ -0,0 +1,14 @@ +var assert = require('assert'); +var weak = require('../') + +describe('promise', function () { + if (!global.Promise) { + // Version of JS without `Promise`; nothing to do. + return; + } + + it('should not mistake a promise for a weak reference', function () { + var p = new Promise(function () {}); + assert(!weak.isWeakRef(p)); + }); +})