summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Kanis <lars@greiz-reinsdorf.de>2021-02-27 08:44:58 +0100
committerLars Kanis <lars@greiz-reinsdorf.de>2021-02-27 08:44:58 +0100
commitba59d99c3ecf756a2a1ac26ab634768ffc452697 (patch)
tree0914377eb298962644a64b399934be6ed6e06e29
parent547397a18e760ad93456a52723a10409a4498af1 (diff)
parent0df6f5c7d8f08bdf6c413ae8e1e3ff9c111f35c5 (diff)
downloadffi-ba59d99c3ecf756a2a1ac26ab634768ffc452697.tar.gz
Merge branch 'master' of github.com:ffi/ffi; branch 'pass-callback-in-varargs' of https://github.com/vincentisambart/ffi into vincentisambart-pass-callback-in-varargs
-rw-r--r--ext/ffi_c/Variadic.c15
-rw-r--r--spec/ffi/callback_spec.rb8
-rw-r--r--spec/ffi/fixtures/ClosureTest.c12
3 files changed, 32 insertions, 3 deletions
diff --git a/ext/ffi_c/Variadic.c b/ext/ffi_c/Variadic.c
index d9d7fd4..d18a143 100644
--- a/ext/ffi_c/Variadic.c
+++ b/ext/ffi_c/Variadic.c
@@ -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 };
@@ -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;
}
@@ -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);
diff --git a/spec/ffi/callback_spec.rb b/spec/ffi/callback_spec.rb
index 58e5c81..53ff1e4 100644
--- a/spec/ffi/callback_spec.rb
+++ b/spec/ffi/callback_spec.rb
@@ -49,6 +49,7 @@ module CallbackSpecs
callback :cbVrU32, [ ], :uint
callback :cbVrL, [ ], :long
callback :cbVrUL, [ ], :ulong
+ callback :cbVrD, [ ], :double
callback :cbVrS64, [ ], :long_long
callback :cbVrU64, [ ], :ulong_long
callback :cbVrP, [], :pointer
@@ -86,7 +87,7 @@ module CallbackSpecs
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
@@ -261,6 +262,11 @@ module CallbackSpecs
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
diff --git a/spec/ffi/fixtures/ClosureTest.c b/spec/ffi/fixtures/ClosureTest.c
index c477be8..daabe0e 100644
--- a/spec/ffi/fixtures/ClosureTest.c
+++ b/spec/ffi/fixtures/ClosureTest.c
@@ -6,6 +6,7 @@
#include <stdlib.h>
#include <stdbool.h>
+#include <stdarg.h>
#ifndef _WIN32
# include <pthread.h>
#else
@@ -13,6 +14,17 @@
# 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; \
}