-
Notifications
You must be signed in to change notification settings - Fork 414
/
_foreign_function.js
117 lines (94 loc) · 3.21 KB
/
_foreign_function.js
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/**
* Module dependencies.
*/
var assert = require('assert')
, debug = require('debug')('ffi:_ForeignFunction')
, ref = require('ref')
, bindings = require('./bindings')
, POINTER_SIZE = ref.sizeof.pointer
, FFI_ARG_SIZE = bindings.FFI_ARG_SIZE
function ForeignFunction (cif, funcPtr, returnType, argTypes) {
debug('creating new ForeignFunction', funcPtr)
var numArgs = argTypes.length
var argsArraySize = numArgs * POINTER_SIZE
// "result" must point to storage that is sizeof(long) or larger. For smaller
// return value sizes, the ffi_arg or ffi_sarg integral type must be used to
// hold the return value
var resultSize = returnType.size >= ref.sizeof.long ? returnType.size : FFI_ARG_SIZE
assert(resultSize > 0)
/**
* This is the actual JS function that gets returned.
* It handles marshalling input arguments into C values,
* and unmarshalling the return value back into a JS value
*/
var proxy = function () {
debug('invoking proxy function')
if (arguments.length !== numArgs) {
throw new TypeError('Expected ' + numArgs +
' arguments, got ' + arguments.length)
}
// storage buffers for input arguments and the return value
var result = new Buffer(resultSize)
, argsList = new Buffer(argsArraySize)
// write arguments to storage areas
for (var i = 0; i < numArgs; i++) {
var argType = argTypes[i]
, val = arguments[i]
var valPtr
if (val && typeof val.ref === 'function') {
debug('using the "ref()" function for argument at index', i)
valPtr = val.ref()
} else {
valPtr = ref.alloc(argType, val)
}
argsList.writePointer(valPtr, i * POINTER_SIZE)
}
// invoke the `ffi_call()` function
bindings.ffi_call(cif, funcPtr, result, argsList)
result.type = returnType
return result.deref()
}
/**
* The asynchronous version of the proxy function.
*/
proxy.async = function () {
debug('invoking async proxy function')
var argc = arguments.length
if (argc !== numArgs + 1) {
throw new TypeError('Expected ' + (numArgs + 1) +
' arguments, got ' + argc)
}
var callback = arguments[argc - 1]
if (typeof callback !== 'function') {
throw new TypeError('Expected a callback function as argument number: ' +
(argc - 1))
}
// storage buffers for input arguments and the return value
var result = new Buffer(resultSize)
var argsList = new Buffer(argsArraySize)
// write arguments to storage areas
for (var i = 0; i < numArgs; i++) {
var argType = argTypes[i]
var val = arguments[i]
var valPtr
if (val && typeof val.ref === 'function') {
debug('using the "ref()" function for argument at index', i)
valPtr = val.ref()
} else {
valPtr = ref.alloc(argType, val)
}
argsList.writePointer(valPtr, i * POINTER_SIZE)
}
// invoke the `ffi_call()` function asynchronously
bindings.ffi_call_async(cif, funcPtr, result, argsList, function (err) {
if (err) {
callback(err)
} else {
result.type = returnType
callback(null, result.deref())
}
})
}
return proxy
}
module.exports = ForeignFunction