Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added promise support #298

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 19 additions & 0 deletions lib/_foreign_function.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
var assert = require('assert')
, debug = require('debug')('ffi:_ForeignFunction')
, ref = require('ref')
, Promise = require('any-promise')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need any-promise? Node 0.10 is extremely old, and standard Promises were introduced in Node 0.12. Could we just deprecate 0.10? Node 6 just came out.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still test 0.10, and also a lot of users use bluebird which has .finally. Our promises should match the user's, that's the point of any-promise.

, bindings = require('./bindings')
, POINTER_SIZE = ref.sizeof.pointer
, FFI_ARG_SIZE = bindings.FFI_ARG_SIZE
Expand Down Expand Up @@ -117,6 +118,24 @@ function ForeignFunction (cif, funcPtr, returnType, argTypes) {
})
}

/**
* A promise based wrapper around .async
*/

proxy.promise = function () {
var args = [].splice.call(arguments, 0)
return new Promise(function (resolve, reject) {
args.push(function (err, res) {
if (err) {
return reject(err)
} else {
return resolve(res)
}
})
proxy.async.apply(undefined, args)
})
}

return proxy
}
module.exports = ForeignFunction
5 changes: 4 additions & 1 deletion lib/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,16 @@ function Library (libfile, funcs, lib) {
, fopts = info[2]
, abi = fopts && fopts.abi
, async = fopts && fopts.async
, promise = fopts && fopts.promise
, varargs = fopts && fopts.varargs

if (varargs) {
lib[func] = VariadicForeignFunction(fptr, resultType, paramTypes, abi)
} else {
var ff = ForeignFunction(fptr, resultType, paramTypes, abi)
lib[func] = async ? ff.async : ff
if (async) lib[func] = ff.async
else if (promise) lib[func] = ff.promise
else lib[func] = ff
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I should have brackets here, let me know.

}
})

Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@
},
"main": "./lib/ffi",
"dependencies": {
"any-promise": "^1.1.0",
"bindings": "~1.2.0",
"debug": "2",
"nan": "2",
"ref": "1",
"ref-struct": "1",
"nan": "2"
"ref-struct": "1"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NPM did reordered nan and ref-struct by itself. I can change it back if you'd like, but NPM seems to want it this way.

},
"devDependencies": {
"bluebird": "^3.3.4",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use standard Promise instead of Bluebird?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We test Node 0.10.

"fs-extra": "^0.23.1",
"mocha": "*",
"ref-array": "1"
Expand Down
7 changes: 7 additions & 0 deletions test/_anyPromise.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Node 0.10 doesn't have a builtin Promise implementation
// Because of that, we use Bluebird for tests
// We need to run this before requiring the project

if (!require('any-promise/implementation')) {
require('any-promise/register')('bluebird')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need this.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes we do, because travis runs on Node 0.10. It's literally in the comment above that (I suppose the fact that we test it wasn't though).

}
26 changes: 26 additions & 0 deletions test/foreign_function.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,30 @@ describe('ForeignFunction', function () {

})

describe('promise', function () {

it('should call the static "abs" bindings asynchronously', function () {
var _abs = bindings.abs
var abs = ffi.ForeignFunction(_abs, 'int', [ 'int' ])
assert.equal('function', typeof abs.async)

return abs.promise(-1234).then(function (res) {
assert.equal(res, 1234)
})
})

it('should invoke the callback with an Error with a meaningful message when type\'s `set()` throws', function () {
var _abs = bindings.abs
var abs = ffi.ForeignFunction(_abs, 'int', [ 'int' ])

return abs.promise(1111111111111111111111).catch(function (err) {
return err;
}).then(function (err) {
assert(err instanceof Error)
assert(/error setting argument 0/.test(err.message))
})
})

})

})
14 changes: 14 additions & 0 deletions test/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,18 @@ describe('Library', function () {

})

describe('promise', function () {

it('should call a function asynchronously and return a promise', function () {
var lib = process.platform == 'win32' ? 'msvcrt' : 'libm'
var libm = new Library(lib, {
'ceil': [ 'double', [ 'double' ], { promise: true } ]
})
return libm.ceil(1.1).then(function (res) {
assert.equal(res, 2)
})
})

})

})