Skip to content

Commit

Permalink
Merge branch 'master' of github.com:ffi/ffi; branch 'pass-callback-in…
Browse files Browse the repository at this point in the history
…-varargs' of https://github.com/vincentisambart/ffi into vincentisambart-pass-callback-in-varargs
  • Loading branch information
larskanis committed Feb 27, 2021
2 parents 547397a + 0df6f5c commit ba59d99
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 3 deletions.
15 changes: 13 additions & 2 deletions ext/ffi_c/Variadic.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ variadic_invoke(VALUE self, VALUE parameterTypes, VALUE parameterValues)
ffi_type* ffiReturnType;
Type** paramTypes;
VALUE* argv;
int paramCount = 0, fixedCount = 0, i;
VALUE* callbackParameters = NULL;
int paramCount = 0, fixedCount = 0, callbackCount = 0, i;
ffi_status ffiStatus;
rbffi_frame_t frame = { 0 };

Expand Down Expand Up @@ -211,6 +212,16 @@ variadic_invoke(VALUE self, VALUE parameterTypes, VALUE parameterValues)
Data_Get_Struct(rbType, Type, paramTypes[i]);
break;

case NATIVE_FUNCTION:
case NATIVE_CALLBACK:
if (!rb_obj_is_kind_of(rbType, rbffi_FunctionTypeClass)) {
VALUE typeName = rb_funcall2(rbType, rb_intern("inspect"), 0, NULL);
rb_raise(rb_eTypeError, "Incorrect parameter type (%s)", RSTRING_PTR(typeName));
}
REALLOC_N(callbackParameters, VALUE, callbackCount + 1);
callbackParameters[callbackCount++] = rbType;
break;

default:
break;
}
Expand Down Expand Up @@ -248,7 +259,7 @@ variadic_invoke(VALUE self, VALUE parameterTypes, VALUE parameterValues)
}

rbffi_SetupCallParams(paramCount, argv, -1, paramTypes, params,
ffiValues, NULL, 0, invoker->rbEnums);
ffiValues, callbackParameters, callbackCount, invoker->rbEnums);

rbffi_frame_push(&frame);

Expand Down
8 changes: 7 additions & 1 deletion spec/ffi/callback_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class S8F32S32 < FFI::Struct
callback :cbVrU32, [ ], :uint
callback :cbVrL, [ ], :long
callback :cbVrUL, [ ], :ulong
callback :cbVrD, [ ], :double
callback :cbVrS64, [ ], :long_long
callback :cbVrU64, [ ], :ulong_long
callback :cbVrP, [], :pointer
Expand Down Expand Up @@ -86,7 +87,7 @@ class S8F32S32 < FFI::Struct
attach_variable :pVrS8, :gvar_pointer, :pointer
attach_function :testGVarCallbackVrS8, :testClosureVrB, [ :pointer ], :char
attach_function :testOptionalCallbackCrV, :testOptionalClosureBrV, [ :cbCrV, :char ], :void

attach_function :testCallbackVrDva, :testClosureVrDva, [ :double, :varargs ], :double
end

it "returning :char (0)" do
Expand Down Expand Up @@ -261,6 +262,11 @@ class S8F32S32 < FFI::Struct
expect(LibTest.testCallbackVrZ { true }).to be true
end

it "returning double" do
pr = proc { 42.0 }
expect(LibTest.testCallbackVrDva(3.0, :cbVrD, pr)).to eq(45.0)
end

it "returning :pointer (nil)" do
expect(LibTest.testCallbackVrP { nil }).to be_null
end
Expand Down
12 changes: 12 additions & 0 deletions spec/ffi/fixtures/ClosureTest.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,25 @@

#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
#ifndef _WIN32
# include <pthread.h>
#else
# include <windows.h>
# include <process.h>
#endif

double testClosureVrDva(double d, ...) {
va_list args;
double (*closure)(void);

va_start(args, d);
closure = va_arg(args, double (*)(void));
va_end(args);

return d + closure();
}

#define R(T, rtype) rtype testClosureVr##T(rtype (*closure)(void)) { \
return closure != NULL ? (*closure)() : (rtype) 0; \
}
Expand Down

0 comments on commit ba59d99

Please sign in to comment.