[pypy-commit] pypy cffi-1.0: Updates to cffi's 47ef4ec2a64c. Add ffi.callback.

arigo noreply at buildbot.pypy.org
Sun May 3 10:40:22 CEST 2015


Author: Armin Rigo <arigo at 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)


More information about the pypy-commit mailing list