'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); };