├── .gitignore ├── binding.gyp ├── test ├── create.js ├── buffer.js ├── exports.js ├── weakref.js └── callback.js ├── .travis.yml ├── LICENSE ├── package.json ├── appveyor.yml ├── History.md ├── lib └── weak.js ├── README.md └── src └── weakref.cc /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /build 3 | /.lock-wscript 4 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'targets': [{ 3 | 'target_name': 'weakref', 4 | 'sources': [ 'src/weakref.cc' ], 5 | 'include_dirs': [ 6 | ' 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Ben Noordhuis ", 3 | "contributors": [ 4 | "Nathan Rajlich (http://tootallnate.net)" 5 | ], 6 | "name": "weak", 7 | "license": "MIT", 8 | "description": "Make weak references to JavaScript Objects.", 9 | "keywords": [ 10 | "weak", 11 | "reference", 12 | "js", 13 | "javascript", 14 | "object", 15 | "function", 16 | "callback" 17 | ], 18 | "version": "1.0.2", 19 | "repository": { 20 | "type": "git", 21 | "url": "git://github.com/kriszyp/node-weak.git" 22 | }, 23 | "main": "lib/weak.js", 24 | "scripts": { 25 | "test": "mocha -gc --reporter spec" 26 | }, 27 | "dependencies": { 28 | "bindings": "^1.2.1", 29 | "nan": "^2.0.5" 30 | }, 31 | "devDependencies": { 32 | "mocha": "~2.1.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/exports.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var weak = require('../') 3 | 4 | function checkFunction (prop) { 5 | it('should have a function "' + prop + '"', function () { 6 | assert('function' == typeof weak[prop]); 7 | }) 8 | } 9 | 10 | describe('exports', function () { 11 | 12 | afterEach(gc) 13 | 14 | it('should be a function', function () { 15 | assert('function' == typeof weak); 16 | }) 17 | 18 | checkFunction('get') 19 | checkFunction('create') 20 | checkFunction('isWeakRef') 21 | checkFunction('isNearDeath') 22 | checkFunction('isDead') 23 | checkFunction('callbacks') 24 | checkFunction('addCallback') 25 | checkFunction('removeCallback') 26 | checkFunction('removeCallbacks') 27 | 28 | it('should be a circular reference to "create"', function () { 29 | assert(weak === weak.create); 30 | }) 31 | 32 | }) 33 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # http://www.appveyor.com/docs/appveyor-yml 2 | 3 | # Test against these versions of Node.js. 4 | environment: 5 | # Visual Studio Version 6 | MSVS_VERSION: 2013 7 | # Test against these versions of Node.js and io.js 8 | matrix: 9 | # node.js 10 | - nodejs_version: "0.8" 11 | - nodejs_version: "0.10" 12 | - nodejs_version: "0.12" 13 | # io.js 14 | - nodejs_version: "2" 15 | - nodejs_version: "3" 16 | - nodejs_version: "4" 17 | - nodejs_version: "5" 18 | 19 | platform: 20 | - x86 21 | - x64 22 | 23 | # Install scripts. (runs after repo cloning) 24 | install: 25 | # Get the latest stable version of Node 0.STABLE.latest 26 | - ps: if($env:nodejs_version -eq "0.8") {Install-Product node $env:nodejs_version} 27 | - ps: if($env:nodejs_version -ne "0.8") {Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version)} 28 | # Node 0.8 comes with a too obsolete npm 29 | - IF %nodejs_version% == 0.8 (npm install -g npm@1.4.28) 30 | # Install latest NPM only for node.js versions until built in node-gyp adds io.js support 31 | # Update is required for node.js 0.8 because built in npm(node-gyp) does not know VS2013 32 | - IF %nodejs_version% LSS 1 (npm install -g npm@2) 33 | - IF %nodejs_version% LSS 1 set PATH=%APPDATA%\npm;%PATH% 34 | # Typical npm stuff. 35 | - npm install --msvs_version=%MSVS_VERSION% 36 | 37 | # Post-install test scripts. 38 | test_script: 39 | # Output useful info for debugging. 40 | - node --version 41 | - npm --version 42 | # run tests 43 | - npm test 44 | 45 | # Don't actually build. 46 | build: off 47 | 48 | # Set build version format here instead of in the admin panel. 49 | version: "{build}" 50 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 1.0.1 / 2016-01-03 3 | ================== 4 | 5 | * add missing HandleScope in callback (#67, @laverdet) 6 | * add Travis support for v4.x, v5.x (#60, @robcolburn) 7 | * appveyor: place .bin into the $PATH 8 | 9 | 1.0.0 / 2015-08-17 10 | ================== 11 | 12 | * added `removeCallback()` and `removeCallbacks()` 13 | * appveyor: attempt to fix node v0.8 14 | * appveyor: test x86 and x64 15 | * travis: attempt to fix node v0.8 16 | * travis: test "iojs" 17 | * travis: run on new infrastructure 18 | * package: update to NAN 2.0 (@kkoopa) 19 | * package: stricter "bindings" version number 20 | * package: specify "MIT" license 21 | * README: update for API change 22 | 23 | 0.4.1 / 2015-05-09 24 | ================== 25 | 26 | * Update to nan ~1.8.4 (#47, @imyller) 27 | * appveyor: test node v0.12 instead of v0.11 28 | 29 | 0.4.0 / 2015-02-18 30 | ================== 31 | 32 | * travis: test node v0.12 33 | * package: update "nan" to v1.6.2 for Node v0.12 compatibility (#40, @GitStarInc) 34 | * src: call callback directly to avoid unwanted preemption (#36) 35 | 36 | 0.3.4 / 2015-01-27 37 | ================== 38 | 39 | * Update dependencies to also work with IO.js #39 (#40, @GitStarInc) 40 | * Revert "appveyor: attempt to test x86 and x64, Debug and Release configs" 41 | * appveyor: attempt to test x86 and x64, Debug and Release configs 42 | 43 | 0.3.3 / 2014-06-04 44 | ================== 45 | 46 | * appveyor: more generic comment 47 | * package: update "mocha" to v1.20.1 48 | * package: update "nan" to v1.2.0 49 | 50 | 0.3.2 / 2014-05-25 51 | ================== 52 | 53 | * add appveyor.yml file for Windows testing 54 | * README: use SVG Travis badge 55 | * README: add appveyor build badge 56 | * README: correct docs for the callback (#29, @metamatt) 57 | * .travis: don't test node v0.9.x 58 | * weakref: fix deprecation warning after nan upgrade 59 | * weakref: remove "printf()" calls 60 | * weakref: update for nan v1 API changes 61 | -------------------------------------------------------------------------------- /test/weakref.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | var weak = require('../') 3 | 4 | describe('Weakref', function () { 5 | 6 | afterEach(gc) 7 | 8 | it('weak() should return a `Weakref` instance', function () { 9 | var ref = weak({}) 10 | assert(weak.isWeakRef(ref)) 11 | }) 12 | 13 | it('should proxy named gets to the target', function () { 14 | var o = { foo: 'bar' } 15 | , r = weak(o) 16 | assert.equal(r.foo, 'bar') 17 | }) 18 | 19 | it('should proxy named sets to the target', function () { 20 | var o = {} 21 | , r = weak(o) 22 | r.foo = 'bar' 23 | assert.equal(r.foo, 'bar') 24 | }) 25 | 26 | it('should proxy named deletes to the target', function () { 27 | var o = { foo: 'bar' } 28 | , r = weak(o) 29 | delete r.foo 30 | assert(!r.foo) 31 | }) 32 | 33 | it('should proxy indexed gets to the target', function () { 34 | var a = [ 'foo' ] 35 | , r = weak(a) 36 | assert.equal(1, a.length) 37 | assert.equal(1, r.length) 38 | assert.equal('foo', r[0]) 39 | }) 40 | 41 | it('should proxy indexed sets to the target', function () { 42 | var a = [] 43 | , r = weak(a) 44 | assert.equal(0, a.length) 45 | assert.equal(0, r.length) 46 | r[0] = 'foo' 47 | assert.equal(1, a.length) 48 | assert.equal('foo', a[0]) 49 | r.push('bar') 50 | assert.equal(2, a.length) 51 | assert.equal('bar', a[1]) 52 | }) 53 | 54 | it('should proxy indexed deletes to the target', function () { 55 | var a = [ 'foo' ] 56 | , r = weak(a) 57 | delete r[0] 58 | assert.equal('undefined', typeof a[0]) 59 | }) 60 | 61 | it('should proxy enumeration', function () { 62 | var o = { a: 'a', b: 'b', c: 'c', d: 'd' } 63 | , r = weak(o) 64 | assert.deepEqual(Object.keys(o), Object.keys(r)) 65 | }) 66 | 67 | it('should act like an empty object after target is gc\'d' 68 | , function () { 69 | var o = { foo: 'bar' } 70 | , r = weak(o) 71 | o = null 72 | assert.equal('bar', r.foo) 73 | gc() 74 | assert(!r.foo) 75 | assert.equal(0,Object.keys(r).length) 76 | }) 77 | 78 | }) 79 | -------------------------------------------------------------------------------- /lib/weak.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Module dependencies. 4 | */ 5 | 6 | var Emitter = require('events').EventEmitter; 7 | var bindings = require('bindings')('weakref.node'); 8 | 9 | /** 10 | * Module exports. 11 | */ 12 | 13 | exports = module.exports = create; 14 | exports.addCallback = exports.addListener = addCallback; 15 | exports.removeCallback = exports.removeListener = removeCallback; 16 | exports.removeCallbacks = exports.removeListeners = removeCallbacks; 17 | exports.callbacks = exports.listeners = callbacks; 18 | 19 | // backwards-compat with node-weakref 20 | exports.weaken = exports.create = exports; 21 | 22 | // re-export all the binding functions onto the exports 23 | Object.keys(bindings).forEach(function (name) { 24 | exports[name] = bindings[name]; 25 | }); 26 | 27 | /** 28 | * Internal emitter event name. 29 | * This is completely arbitrary... 30 | * Could be any value.... 31 | */ 32 | 33 | var CB = '_CB'; 34 | 35 | /** 36 | * Creates and returns a new Weakref instance. Optionally attaches 37 | * a weak callback to invoke when the Object gets garbage collected. 38 | * 39 | * @api public 40 | */ 41 | 42 | function create (obj, fn) { 43 | var weakref = bindings._create(obj); 44 | if ('function' == typeof fn) { 45 | exports.addCallback(weakref, fn); 46 | } 47 | return weakref; 48 | } 49 | 50 | /** 51 | * Adds a weak callback function to the Weakref instance. 52 | * 53 | * @api public 54 | */ 55 | 56 | function addCallback (weakref, fn) { 57 | var emitter = bindings._getEmitter(weakref); 58 | return emitter.on(CB, fn); 59 | } 60 | 61 | /** 62 | * Removes a weak callback function from the Weakref instance. 63 | * 64 | * @api public 65 | */ 66 | 67 | function removeCallback (weakref, fn) { 68 | var emitter = bindings._getEmitter(weakref); 69 | return emitter.removeListener(CB, fn); 70 | } 71 | 72 | /** 73 | * Returns a copy of the listeners on the Weakref instance. 74 | * 75 | * @api public 76 | */ 77 | 78 | function callbacks (weakref) { 79 | var emitter = bindings._getEmitter(weakref); 80 | return emitter.listeners(CB); 81 | } 82 | 83 | 84 | /** 85 | * Removes all callbacks on the Weakref instance. 86 | * 87 | * @api public 88 | */ 89 | 90 | function removeCallbacks (weakref) { 91 | var emitter = bindings._getEmitter(weakref); 92 | return emitter.removeAllListeners(CB); 93 | } 94 | 95 | /** 96 | * Common weak callback function. 97 | * 98 | * @api private 99 | */ 100 | 101 | function callback (emitter) { 102 | emitter.emit(CB); 103 | emitter = null; 104 | } 105 | -------------------------------------------------------------------------------- /test/callback.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | var weak = require('../') 3 | 4 | describe('weak()', function () { 5 | 6 | afterEach(gc) 7 | 8 | describe('garbage collection callback', function () { 9 | 10 | it('should accept a function as second argument', function () { 11 | var r = weak({}, function () {}) 12 | assert.equal(1, weak.callbacks(r).length) 13 | }) 14 | 15 | it('should invoke the callback before the target is gc\'d', function () { 16 | var called = false 17 | weak({}, function () { 18 | called = true 19 | }) 20 | assert(!called) 21 | gc() 22 | assert(called) 23 | }) 24 | 25 | it('should invoke *all* callbacks in the internal "callback" Array' 26 | , function () { 27 | var r = weak({}) 28 | , called1 = false 29 | , called2 = false 30 | weak.addCallback(r, function () { 31 | called1 = true 32 | }) 33 | weak.addCallback(r, function () { 34 | called2 = true 35 | }) 36 | gc() 37 | assert(called1) 38 | assert(called2) 39 | }) 40 | 41 | it('should preempt code for GC callback but not nextTick callbacks' 42 | , function(done) { 43 | var calledGcCallback = false 44 | , calledTickCallback = false 45 | weak({}, function() { 46 | calledGcCallback = true 47 | }) 48 | 49 | process.nextTick(function() { 50 | calledTickCallback = true 51 | }); 52 | 53 | assert(!calledGcCallback) 54 | assert(!calledTickCallback) 55 | gc() 56 | assert(calledGcCallback) 57 | assert(!calledTickCallback) 58 | setTimeout(function() { 59 | assert(calledTickCallback); 60 | done(); 61 | }, 0) 62 | }) 63 | 64 | }) 65 | }) 66 | 67 | describe('callbacks()', function () { 68 | 69 | it('should return the Weakref\'s "callback" Array', function () { 70 | var r = weak({}, function() {}) 71 | , callbacks = weak.callbacks(r) 72 | assert(Array.isArray(callbacks)) 73 | assert.equal(1, callbacks.length) 74 | }) 75 | 76 | }) 77 | 78 | describe('removeCallback()', function() { 79 | 80 | it('removed callbacks should not be called', function() { 81 | var called = false 82 | , fn = function() { called = true } 83 | , r = weak({}, fn) 84 | weak.removeCallback(r, fn) 85 | gc() 86 | assert(!called) 87 | }) 88 | 89 | }) 90 | 91 | describe('removeCallbacks()', function() { 92 | 93 | it('removed callbacks should not be called', function() { 94 | var called = false 95 | , fn = function() { called = true } 96 | , r = weak({}, fn) 97 | weak.removeCallbacks(r) 98 | gc() 99 | assert(!called) 100 | }) 101 | 102 | }) 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | node-weak 2 | ========= 3 | ### Make weak references to JavaScript Objects. 4 | [![Build Status](https://travis-ci.org/TooTallNate/node-weak.svg?branch=master)](https://travis-ci.org/TooTallNate/node-weak) 5 | [![Build Status](https://ci.appveyor.com/api/projects/status/09lf09d1a5hm24bq?svg=true)](https://ci.appveyor.com/project/TooTallNate/node-weak) 6 | 7 | On certain rarer occasions, you run into the need to be notified when a JavaScript 8 | object is going to be garbage collected. This feature is exposed to V8's C++ API, 9 | but not to JavaScript. 10 | 11 | That's where `node-weak` comes in! This module exports V8's `Persistent` 12 | functionality to JavaScript. This allows you to create weak references, and 13 | optionally attach a callback function to any arbitrary JS object. The callback 14 | function will be invoked right before the Object is garbage collected (i.e. after 15 | there are no more remaining references to the Object in JS-land). 16 | 17 | This module can, for example, be used for debugging; to determine whether or not 18 | an Object is being garbage collected as it should. 19 | Take a look at the example below for commented walkthrough scenario. 20 | 21 | 22 | Installation 23 | ------------ 24 | 25 | Install with `npm`: 26 | 27 | ``` bash 28 | $ npm install weak 29 | ``` 30 | 31 | 32 | Example 33 | ------- 34 | 35 | Here's an example of calling a `cleanup()` function on a Object before it gets 36 | garbage collected: 37 | 38 | ``` js 39 | var weak = require('weak') 40 | 41 | // we are going to "monitor" this Object and invoke "cleanup" 42 | // before the object is garbage collected 43 | var obj = { 44 | a: true 45 | , foo: 'bar' 46 | } 47 | 48 | // Here's where we set up the weak reference 49 | var ref = weak(obj, function () { 50 | // `this` inside the callback is the EventEmitter. 51 | console.log('"obj" has been garbage collected!') 52 | }) 53 | 54 | // While `obj` is alive, `ref` proxies everything to it, so: 55 | ref.a === obj.a 56 | ref.foo === obj.foo 57 | 58 | // Clear out any references to the object, so that it will be GC'd at some point... 59 | obj = null 60 | 61 | // 62 | //// Time passes, and the garbage collector is run 63 | // 64 | 65 | // `callback()` above is called, and `ref` now acts like an empty object. 66 | typeof ref.foo === 'undefined' 67 | ``` 68 | 69 | 70 | Weak Callback Function "Best Practices" 71 | --------------------------------------- 72 | 73 | It's important to be careful when using the "callbacks" feature of `node-weak`, 74 | otherwise you can end up in a situation where the watched object will never 75 | be garbage collected. 76 | 77 | You _should **not**_ define the callback function in the same scope as the 78 | object that is being watched. It's often best to define the callback function 79 | at the highest scope possible (top-level being the best). Named functions 80 | work really well for this: 81 | 82 | ``` js 83 | var http = require('http') 84 | , weak = require('weak') 85 | 86 | http.createServer(function (req, res) { 87 | weak(req, gcReq) 88 | weak(res, gcRes) 89 | res.end('Hello World\n') 90 | }).listen(3000) 91 | 92 | function gcReq () { 93 | console.log('GC\'d `req` object') 94 | } 95 | 96 | function gcRes () { 97 | console.log('GC\'d `res` object') 98 | } 99 | ``` 100 | 101 | 102 | API 103 | --- 104 | 105 | ### Weakref weak(Object obj [, Function callback]) 106 | 107 | The main exports is the function that creates the weak reference. 108 | The first argument is the Object that should be monitored. 109 | The Object can be a regular Object, an Array, a Function, a RegExp, or any of 110 | the primitive types or constructor function created with `new`. 111 | 112 | Optionally, you can set a callback function to be invoked 113 | before the object is garbage collected. 114 | 115 | 116 | ### Object weak.get(Weakref ref) 117 | 118 | `get()` returns the actual reference to the Object that this weak reference was 119 | created with. If this is called with a dead reference, `undefined` is returned. 120 | 121 | 122 | ### Boolean weak.isDead(Weakref ref) 123 | 124 | Checks to see if `ref` is a dead reference. Returns `true` if the original Object 125 | has already been GC'd, `false` otherwise. 126 | 127 | 128 | ### Boolean weak.isNearDeath(Weakref ref) 129 | 130 | Checks to see if `ref` is "near death". This will be `true` exactly during the 131 | weak reference callback function, and `false` any other time. 132 | 133 | 134 | ### Boolean weak.isWeakRef(Object obj) 135 | 136 | Checks to see if `obj` is "weak reference" instance. Returns `true` if the 137 | passed in object is a "weak reference", `false` otherwise. 138 | 139 | 140 | ### EventEmitter weak.addCallback(Weakref ref, Function callback) 141 | 142 | Adds `callback` to the Array of callback functions that will be invoked before the 143 | Object gets garbage collected. The callbacks get executed in the order that they 144 | are added. 145 | 146 | 147 | ### EventEmitter weak.removeCallback(Weakref ref, Function callback) 148 | 149 | Removes `callback` from the Array of callback functions that will be invoked before 150 | the Object gets garbage collected. 151 | 152 | 153 | ### EventEmitter weak.removeCallbacks(Weakref ref) 154 | 155 | Empties the Array of callback functions that will be invoked before the Object gets 156 | garbage collected. 157 | 158 | 159 | ### Array weak.callbacks(Weakref ref) 160 | 161 | Returns an Array that `ref` iterates through to invoke the GC callbacks. This 162 | utilizes node's `EventEmitter#listeners()` function and therefore returns a copy 163 | in node 0.10 and newer. 164 | -------------------------------------------------------------------------------- /src/weakref.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Ben Noordhuis 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | using namespace v8; 22 | 23 | namespace { 24 | 25 | 26 | class proxy_container { 27 | public: 28 | Nan::Persistent proxy; 29 | Nan::Persistent target; 30 | }; 31 | 32 | 33 | Nan::Persistent proxyClass; 34 | 35 | Nan::Callback *globalCallback; 36 | 37 | 38 | bool IsDead(Local proxy) { 39 | assert(proxy->InternalFieldCount() == 1); 40 | Nan::Persistent *target = reinterpret_cast*>( 41 | Nan::GetInternalFieldPointer(proxy, 1) 42 | ); 43 | return target == NULL || target->IsEmpty(); 44 | } 45 | 46 | 47 | Local Unwrap(Local proxy) { 48 | assert(!IsDead(proxy)); 49 | Nan::Persistent *targetPersistent = reinterpret_cast*>( 50 | Nan::GetInternalFieldPointer(proxy, 1) 51 | ); 52 | Local _target = Nan::New(*targetPersistent); 53 | return _target; 54 | } 55 | 56 | 57 | #define UNWRAP \ 58 | Local obj; \ 59 | const bool dead = IsDead(info.This()); \ 60 | if (!dead) obj = Unwrap(info.This()); \ 61 | 62 | /** 63 | * Weakref callback function. Invokes the "global" callback function. 64 | */ 65 | 66 | static void TargetCallback(const Nan::WeakCallbackInfo> &info) { 67 | std::cout << "target callback\n"; 68 | /*Nan::HandleScope scope; 69 | proxy_container *cont = info.GetParameter(); 70 | std::cout << "doing cleanup\n"; 71 | 72 | // clean everything up 73 | Local proxy = Nan::New(cont->proxy); 74 | Nan::SetInternalFieldPointer(proxy, 0, NULL); 75 | cont->proxy.Reset(); 76 | std::cout << "finished reset\n"; 77 | //delete cont; 78 | std::cout << "deleted container\n";*/ 79 | } 80 | 81 | /** 82 | * `_create(obj)` JS function. 83 | */ 84 | 85 | NAN_METHOD(Create) {\ 86 | if (!info[0]->IsObject()) return Nan::ThrowTypeError("Object expected"); 87 | 88 | Local _target = info[0].As(); 89 | Local proxy = Nan::New(proxyClass)->NewInstance(); 90 | Nan::Persistent *targetPersistent = new Nan::Persistent(); 91 | targetPersistent->Reset(_target); 92 | Nan::SetInternalFieldPointer(proxy, 1, targetPersistent); 93 | //Nan::SetInternalFieldPointer(&targetPersistent, 0, proxy); 94 | 95 | targetPersistent->SetWeak(targetPersistent, TargetCallback, Nan::WeakCallbackType::kParameter); 96 | //targetPersistent->MarkIndependent(); 97 | 98 | info.GetReturnValue().Set(proxy); 99 | } 100 | 101 | /** 102 | * TODO: Make this better. 103 | */ 104 | 105 | bool isWeakRef (Local val) { 106 | return val->IsObject() && val.As()->InternalFieldCount() == 1; 107 | } 108 | 109 | /** 110 | * `isWeakRef()` JS function. 111 | */ 112 | 113 | NAN_METHOD(IsWeakRef) { 114 | info.GetReturnValue().Set(isWeakRef(info[0])); 115 | } 116 | 117 | #define WEAKREF_FIRST_ARG \ 118 | if (!isWeakRef(info[0])) { \ 119 | return Nan::ThrowTypeError("Weakref instance expected"); \ 120 | } \ 121 | Local proxy = info[0].As(); 122 | 123 | /** 124 | * `get(weakref)` JS function. 125 | */ 126 | 127 | NAN_METHOD(Get) { 128 | std::cout << "start get\n"; 129 | WEAKREF_FIRST_ARG 130 | if (!IsDead(proxy)) 131 | info.GetReturnValue().Set(Unwrap(proxy)); 132 | std::cout << "finished get\n"; 133 | } 134 | 135 | /** 136 | * `isNearDeath(weakref)` JS function. 137 | */ 138 | 139 | NAN_METHOD(IsNearDeath) { 140 | WEAKREF_FIRST_ARG 141 | 142 | proxy_container *cont = reinterpret_cast( 143 | Nan::GetInternalFieldPointer(proxy, 0) 144 | ); 145 | assert(cont != NULL); 146 | 147 | Local rtn = Nan::New(cont->target.IsNearDeath()); 148 | 149 | info.GetReturnValue().Set(rtn); 150 | } 151 | 152 | /** 153 | * `isDead(weakref)` JS function. 154 | */ 155 | 156 | NAN_METHOD(IsDead) { 157 | WEAKREF_FIRST_ARG 158 | info.GetReturnValue().Set(IsDead(proxy)); 159 | } 160 | 161 | 162 | 163 | /** 164 | * Init function. 165 | */ 166 | 167 | NAN_MODULE_INIT(Initialize) { 168 | Nan::HandleScope scope; 169 | 170 | Local p = Nan::New(); 171 | proxyClass.Reset(p); 172 | p->SetInternalFieldCount(1); 173 | 174 | Nan::SetMethod(target, "get", Get); 175 | Nan::SetMethod(target, "isWeakRef", IsWeakRef); 176 | Nan::SetMethod(target, "isNearDeath", IsNearDeath); 177 | Nan::SetMethod(target, "isDead", IsDead); 178 | Nan::SetMethod(target, "_create", Create); 179 | } 180 | 181 | } // anonymous namespace 182 | 183 | NODE_MODULE(weakref, Initialize) 184 | --------------------------------------------------------------------------------