}
@JRubyMethod(name = { "new" }, meta = true, required = 2, optional = 2)
public static IRubyObject newInstance(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
DirectMemoryIO fptr = null;
RubyHash options = null;
Object proc = null;
int optionsIndex = 2;
Type returnType = FFIUtil.resolveType(context, args[0]);
if (!(args[1] instanceof RubyArray)) {
throw context.getRuntime().newTypeError("Invalid parameter array "
+ args[1].getMetaClass().getName() + " (expected Array)");
}
RubyArray paramTypes = (RubyArray) args[1];
Type[] parameterTypes = new Type[paramTypes.size()];
for (int i = 0; i < parameterTypes.length; ++i) {
parameterTypes[i] = FFIUtil.resolveType(context, paramTypes.entry(i));
}
if (args.length > 2 && args[2] instanceof Pointer) {
fptr = new CodeMemoryIO(context.getRuntime(), (Pointer) args[2]);
optionsIndex = 3;
} else if (args.length > 2 && (args[2] instanceof RubyProc || args[2].respondsTo("call"))) {
proc = args[2];
optionsIndex = 3;
} else if (block.isGiven()) {
proc = block;
optionsIndex = 2;
} else {
throw context.getRuntime().newTypeError("Invalid function address "
+ args[0].getMetaClass().getName() + " (expected FFI::Pointer)");
}
// Get the convention from the options hash
String convention = "default";
IRubyObject enums = null;
if (args.length > optionsIndex && args[optionsIndex] instanceof RubyHash) {
options = (RubyHash) args[optionsIndex];
IRubyObject rbConvention = options.fastARef(context.getRuntime().newSymbol("convention"));
if (rbConvention != null && !rbConvention.isNil()) {
convention = rbConvention.asJavaString();
}
enums = options.fastARef(context.getRuntime().newSymbol("enums"));
if (enums != null && !enums.isNil() && !(enums instanceof RubyHash)) {
throw context.getRuntime().newTypeError("wrong type for options[:enum] "
+ enums.getMetaClass().getName() + " (expected Hash)");
}