Author: Armin Rigo <ar...@tunes.org> Branch: cffi-1.0 Changeset: r76997:94cad98b607c Date: 2015-05-03 10:40 +0200 http://bitbucket.org/pypy/pypy/changeset/94cad98b607c/
Log: Updates to cffi's 47ef4ec2a64c. Add ffi.callback. diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py --- a/pypy/module/_cffi_backend/ffi_obj.py +++ b/pypy/module/_cffi_backend/ffi_obj.py @@ -5,7 +5,7 @@ from rpython.rlib import jit, rgc from pypy.module._cffi_backend import parse_c_type, realize_c_type -from pypy.module._cffi_backend import newtype, cerrno +from pypy.module._cffi_backend import newtype, cerrno, ccallback from pypy.module._cffi_backend.ctypeobj import W_CType from pypy.module._cffi_backend.cdataobj import W_CData @@ -35,24 +35,29 @@ parse_c_type.free_ctxobj(self.ctxobj) @jit.elidable - def parse_string_to_type(self, x): + def parse_string_to_type(self, string, flags): try: - return self.types_dict[x] + x = self.types_dict[string] except KeyError: - pass + index = parse_c_type.parse_c_type(self.ctxobj.info, string) + if index < 0: + xxxx + x = realize_c_type.realize_c_type_or_func( + self, self.ctxobj.info.c_output, index) + self.types_dict[string] = x - index = parse_c_type.parse_c_type(self.ctxobj.info, x) - if index < 0: - xxxx - ct = realize_c_type.realize_c_type(self, self.ctxobj.info.c_output, - index) - self.types_dict[x] = ct - return ct + if isinstance(x, W_CType): + return x + elif flags & CONSIDER_FN_AS_FNPTR: + return realize_c_type.unwrap_fn_as_fnptr(x) + else: + return realize_c_type.unexpected_fn_type(self, x) def ffi_type(self, w_x, accept): space = self.space if (accept & ACCEPT_STRING) and space.isinstance_w(w_x, space.w_str): - return self.parse_string_to_type(space.str_w(w_x)) + return self.parse_string_to_type(space.str_w(w_x), + accept & CONSIDER_FN_AS_FNPTR) if (accept & ACCEPT_CTYPE) and isinstance(w_x, W_CType): return w_x if (accept & ACCEPT_CDATA) and isinstance(w_x, W_CData): @@ -90,6 +95,31 @@ return self.space.wrap(align) + @unwrap_spec(w_python_callable=WrappedDefault(None), + w_error=WrappedDefault(None)) + def descr_callback(self, w_cdecl, w_python_callable, w_error): + """\ +Return a callback object or a decorator making such a callback object. +'cdecl' must name a C function pointer type. The callback invokes the +specified 'python_callable' (which may be provided either directly or +via a decorator). Important: the callback object must be manually +kept alive for as long as the callback may be invoked from the C code.""" + # + w_ctype = self.ffi_type(w_cdecl, ACCEPT_STRING | ACCEPT_CTYPE | + CONSIDER_FN_AS_FNPTR) + space = self.space + if not space.is_none(w_python_callable): + return ccallback.W_CDataCallback(space, w_ctype, + w_python_callable, w_error) + else: + # decorator mode: returns a single-argument function + return space.appexec([w_ctype, w_error], + """(ctype, error): + import _cffi_backend + return lambda python_callable: ( + _cffi_backend.callback(ctype, python_callable, error))""") + + @unwrap_spec(w_init=WrappedDefault(None)) def descr_new(self, w_arg, w_init): """\ @@ -177,6 +207,7 @@ doc=W_FFIObject.doc_errno, cls=W_FFIObject), alignof = interp2app(W_FFIObject.descr_alignof), + callback = interp2app(W_FFIObject.descr_callback), new = interp2app(W_FFIObject.descr_new), sizeof = interp2app(W_FFIObject.descr_sizeof), string = interp2app(W_FFIObject.descr_string), diff --git a/pypy/module/_cffi_backend/realize_c_type.py b/pypy/module/_cffi_backend/realize_c_type.py --- a/pypy/module/_cffi_backend/realize_c_type.py +++ b/pypy/module/_cffi_backend/realize_c_type.py @@ -91,18 +91,34 @@ self.w_ctfuncptr = w_ctfuncptr + +def unwrap_fn_as_fnptr(x): + assert isinstance(x, W_RawFuncType) + return x.w_ctfuncptr + +def unexpected_fn_type(ffi, x): + x = unwrap_fn_as_fnptr(x) + # here, x.name is for example 'int(*)(int)' + # ^ + j = x.name_position - 2 + assert j >= 0 + text1 = x.name[:j] + text2 = x.name[x.name_position+1:] + raise oefmt(ffi.w_FFIError, "the type '%s%s' is a function type, not a " + "pointer-to-function type", text1, text2) + + def realize_c_type(ffi, opcodes, index): """Interpret an opcodes[] array. If opcodes == ffi.ctxobj.ctx.c_types, store all the intermediate types back in the opcodes[]. """ - x = _realize_c_type_or_func(ffi, opcodes, index) - if isinstance(x, W_CType): - return x - else: - xxxx + x = realize_c_type_or_func(ffi, opcodes, index) + if not isinstance(x, W_CType): + unexpected_fn_type(ffi, x) + return x -def _realize_c_type_or_func(ffi, opcodes, index): +def realize_c_type_or_func(ffi, opcodes, index): op = opcodes[index] from_ffi = False @@ -114,7 +130,7 @@ x = get_primitive_type(ffi.space, getarg(op)) elif case == cffi_opcode.OP_POINTER: - y = _realize_c_type_or_func(ffi, opcodes, getarg(op)) + y = realize_c_type_or_func(ffi, opcodes, getarg(op)) if isinstance(y, W_CType): x = newtype.new_pointer_type(ffi.space, y) elif isinstance(y, W_RawFuncType): @@ -143,7 +159,7 @@ x = W_RawFuncType(w_ctfuncptr) elif case == cffi_opcode.OP_NOOP: - x = _realize_c_type_or_func(ffi, opcodes, getarg(op)) + x = realize_c_type_or_func(ffi, opcodes, getarg(op)) else: raise oefmt(ffi.space.w_NotImplementedError, "op=%d", case) diff --git a/pypy/module/_cffi_backend/test/test_ffi_obj.py b/pypy/module/_cffi_backend/test/test_ffi_obj.py --- a/pypy/module/_cffi_backend/test/test_ffi_obj.py +++ b/pypy/module/_cffi_backend/test/test_ffi_obj.py @@ -158,3 +158,10 @@ assert ffi.from_handle(xp) is x yp = ffi.new_handle([6, 4, 2]) assert ffi.from_handle(yp) == [6, 4, 2] + + def test_ffi_cast(self): + import _cffi_backend as _cffi1_backend + ffi = _cffi1_backend.FFI() + assert ffi.cast("int(*)(int)", 0) == ffi.NULL + ffi.callback("int(int)") # side-effect of registering this string + raises(ffi.error, ffi.cast, "int(int)", 0) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit