callback.js
2.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/**
* Module dependencies.
*/
var ref = require('ref')
, CIF = require('./cif')
, assert = require('assert')
, debug = require('debug')('ffi:Callback')
, _Callback = require('./bindings').Callback
// Function used to report errors to the current process event loop,
// When user callback function gets gced.
function errorReportCallback (err) {
if (err) {
process.nextTick(function () {
if (typeof err === 'string') {
throw new Error(err)
} else {
throw err
}
})
}
}
/**
* Turns a JavaScript function into a C function pointer.
* The function pointer may be used in other C functions that
* accept C callback functions.
*/
function Callback (retType, argTypes, abi, func) {
debug('creating new Callback')
if (typeof abi === 'function') {
func = abi
abi = void(0)
}
// check args
assert(!!retType, 'expected a return "type" object as the first argument')
assert(Array.isArray(argTypes), 'expected Array of arg "type" objects as the second argument')
assert.equal(typeof func, 'function', 'expected a function as the third argument')
// normalize the "types" (they could be strings, so turn into real type
// instances)
retType = ref.coerceType(retType)
argTypes = argTypes.map(ref.coerceType)
// create the `ffi_cif *` instance
var cif = CIF(retType, argTypes, abi)
var argc = argTypes.length
var callback = _Callback(cif, retType.size, argc, errorReportCallback, function (retval, params) {
debug('Callback function being invoked')
try {
var args = []
for (var i = 0; i < argc; i++) {
var type = argTypes[ i ]
var argPtr = params.readPointer(i * ref.sizeof.pointer, type.size)
argPtr.type = type
args.push(argPtr.deref())
}
// Invoke the user-given function
var result = func.apply(null, args)
try {
ref.set(retval, 0, result, retType)
} catch (e) {
e.message = 'error setting return value - ' + e.message
throw e
}
} catch (e) {
return e
}
})
// store reference to the CIF Buffer so that it doesn't get
// garbage collected before the callback Buffer does
callback._cif = cif;
return callback
}
module.exports = Callback