[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