111 lines
2.6 KiB
JavaScript
Raw Normal View History

2025-04-28 12:25:20 +08:00
'use strict';
/**
* Module dependencies.
*/
const ref = require('ref-napi');
const assert = require('assert');
const bindings = require('./bindings');
const Callback = require('./callback');
const ForeignFunction = require('./foreign_function');
const debug = require('debug')('ffi:FunctionType');
/**
* Module exports.
*/
module.exports = Function;
/**
* Creates and returns a "type" object for a C "function pointer".
*
* @api public
*/
function Function (retType, argTypes, abi) {
if (!(this instanceof Function)) {
return new Function(retType, argTypes, abi);
}
debug('creating new FunctionType');
// 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');
// normalize the "types" (they could be strings, so turn into real type
// instances)
this.retType = ref.coerceType(retType);
this.argTypes = argTypes.map(ref.coerceType);
this.abi = null == abi ? bindings.FFI_DEFAULT_ABI : abi;
}
/**
* The "ffi_type" is set for node-ffi functions.
*/
Function.prototype.ffi_type = bindings.FFI_TYPES.pointer;
/**
* The "size" is always pointer-sized.
*/
Function.prototype.size = ref.sizeof.pointer;
/**
* The "alignment" is always pointer-aligned.
*/
Function.prototype.alignment = ref.alignof.pointer;
/**
* The "indirection" is always 1 to ensure that our get()/set() get called.
*/
Function.prototype.indirection = 1;
/**
* Returns a ffi.Callback pointer (Buffer) of this function type for the
* given `fn` Function.
*/
Function.prototype.toPointer = function toPointer (fn) {
return Callback(this.retType, this.argTypes, this.abi, fn);
};
/**
* Returns a ffi.ForeignFunction (Function) of this function type for the
* given `buf` Buffer.
*/
Function.prototype.toFunction = function toFunction (buf) {
return ForeignFunction(buf, this.retType, this.argTypes, this.abi);
};
/**
* get function; return a ForeignFunction instance.
*/
Function.prototype.get = function get (buffer, offset) {
debug('ffi FunctionType "get" function');
const ptr = buffer.readPointer(offset);
return this.toFunction(ptr);
};
/**
* set function; return a Callback buffer.
*/
Function.prototype.set = function set (buffer, offset, value) {
debug('ffi FunctionType "set" function');
let ptr;
if ('function' == typeof value) {
ptr = this.toPointer(value);
} else if (Buffer.isBuffer(value)) {
ptr = value;
} else {
throw new Error('don\'t know how to set callback function for: ' + value);
}
buffer.writePointer(ptr, offset);
};