[pypy-commit] cffi default: Document how to indirectly define callbacks using unsupported
arigo
noreply at buildbot.pypy.org
Fri Dec 14 21:50:08 CET 2012
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r1098:448276ce8477
Date: 2012-12-14 21:49 +0100
http://bitbucket.org/cffi/cffi/changeset/448276ce8477/
Log: Document how to indirectly define callbacks using unsupported
features
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -963,11 +963,36 @@
the callback to remain valid forever, store the object in a fresh global
variable somewhere.)
-Note that callbacks of a variadic function type are not supported.
+Note that callbacks of a variadic function type are not supported. A
+workaround is to add custom C code. In the following example, a
+callback gets a first argument that counts how many extra ``int``
+arguments are passed::
+
+ ffi.cdef("""
+ int (*python_callback)(int how_many, int *values);
+ void *const c_callback; /* pass this ptr to C routines */
+ """)
+ lib = ffi.verify("""
+ #include <stdarg.h>
+ #include <alloca.h>
+ static int (*python_callback)(int how_many, int *values);
+ static int c_callback(int how_many, ...) {
+ va_list ap;
+ /* collect the "..." arguments into the values[] array */
+ int i, *values = alloca(how_many * sizeof(int));
+ va_start(ap, how_many);
+ for (i=0; i<how_many; i++)
+ values[i] = va_arg(ap, int);
+ va_end(ap);
+ return python_callback(how_many, values);
+ }
+ """)
+ lib.python_callback = python_callback
Windows: you can't yet specify the calling convention of callbacks.
(For regular calls, the correct calling convention should be
-automatically inferred by the C backend.)
+automatically inferred by the C backend.) Use an indirection, like
+in the example just above.
Be careful when writing the Python callback function: if it returns an
object of the wrong type, or more generally raises an exception, then
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -1437,3 +1437,39 @@
assert res == ord(b"g")
res = lib.myfunc(ffi.cast("int *", p))
assert res == ord(b"g")
+
+def test_callback_indirection():
+ ffi = FFI()
+ ffi.cdef("""
+ int (*python_callback)(int how_many, int *values);
+ void *const c_callback; /* pass this ptr to C routines */
+ int some_c_function(void *cb);
+ """)
+ lib = ffi.verify("""
+ #include <stdarg.h>
+ #include <alloca.h>
+ static int (*python_callback)(int how_many, int *values);
+ static int c_callback(int how_many, ...) {
+ va_list ap;
+ /* collect the "..." arguments into the values[] array */
+ int i, *values = alloca(how_many * sizeof(int));
+ va_start(ap, how_many);
+ for (i=0; i<how_many; i++)
+ values[i] = va_arg(ap, int);
+ va_end(ap);
+ return python_callback(how_many, values);
+ }
+ int some_c_function(int(*cb)(int,...)) {
+ return cb(2, 10, 20) + cb(3, 30, 40, 50);
+ }
+ """)
+ seen = []
+ @ffi.callback("int(int, int*)")
+ def python_callback(how_many, values):
+ seen.append([values[i] for i in range(how_many)])
+ return 42
+ lib.python_callback = python_callback
+
+ res = lib.some_c_function(lib.c_callback)
+ assert res == 84
+ assert seen == [[10, 20], [30, 40, 50]]
More information about the pypy-commit
mailing list