@@ -130,8 +130,12 @@ def wrapper(name, ret, params, exported):
130130 " raise NotImplementedError('%s is not available with the cffi backend')\n " % (name , name )
131131 )
132132 args = []
133+ setup = []
133134 for i , (ctype , pname ) in enumerate (params ):
134- if ctype == "char*" :
135+ if ctype .startswith ("callback:" ):
136+ setup .append (callback_setup (pname , ctype , i + 1 ))
137+ args .append ("_ffi.cast('void*', _cb_%s)" % pname )
138+ elif ctype == "char*" :
135139 args .append ("_enc(%s, %d)" % (pname , i + 1 ))
136140 elif ctype == "bool" :
137141 args .append ("(1 if %s else 0)" % pname )
@@ -141,7 +145,7 @@ def wrapper(name, ret, params, exported):
141145 args .append ("_index(%s)" % pname )
142146 else :
143147 args .append (pname )
144- body = ["def %s(%s):" % (name , sig ), " _r = _lib.%s(%s)" % (name , ", " .join (args ))]
148+ body = ["def %s(%s):" % (name , sig )] + setup + [ " _r = _lib.%s(%s)" % (name , ", " .join (args ))]
145149 if ret == "char*" :
146150 body .append (" _r = _dec(_r)" )
147151 elif ret == "bool" :
@@ -154,6 +158,34 @@ def wrapper(name, ret, params, exported):
154158 return "\n " .join (body ) + "\n "
155159
156160
161+ def callback_setup (pname , ctype , argn ):
162+ """Returns the python source that wraps the callable pname in an
163+ ffi.callback, for the C signature in ctype ("callback:void(int64_t,char*)",
164+ see cffi_callback.go). The wrapper passes it on to Go as _cb_<pname>,
165+ which is kept referenced by this local variable until the Go call
166+ returns: cffi frees a callback as soon as nothing refers to it.
167+ """
168+ cargs = ctype [len ("callback:void(" ):- 1 ]
169+ ctypes = cargs .split ("," ) if cargs else []
170+ names = ["a%d" % i for i in range (len (ctypes ))]
171+ conv = []
172+ for n , t in zip (names , ctypes ):
173+ if t == "char*" :
174+ conv .append ('_ffi.string(%s).decode("utf-8")' % n )
175+ elif t == "bool" :
176+ conv .append ("bool(%s)" % n )
177+ else :
178+ conv .append (n )
179+ cdecl = "void(%s)" % ", " .join ("unsigned char" if t == "bool" else t for t in ctypes )
180+ return "\n " .join ([
181+ " if not callable(%s):" % pname ,
182+ " raise TypeError('argument %d must be callable, not %%s' %% type(%s).__name__)" % (argn , pname ),
183+ " def _cbfn_%s(%s):" % (pname , ", " .join (names )),
184+ " %s(%s)" % (pname , ", " .join (conv )),
185+ " _cb_%s = _ffi.callback(%r, _cbfn_%s)" % (pname , cdecl , pname ),
186+ ])
187+
188+
157189def complex_wrapper (name , nargs , exported ):
158190 """A plain function whose every argument and return value is
159191 complex64/128 (see genFuncComplexCFFI, gen_func.go): each argument
0 commit comments