• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import cffi
2from cffi import FFI
3
4class PythonFFI(FFI):
5
6    def __init__(self, backend=None):
7        FFI.__init__(self, backend=backend)
8        self._pyexports = {}
9
10    def pyexport(self, signature):
11        tp = self._typeof(signature, consider_function_as_funcptr=True)
12        def decorator(func):
13            name = func.__name__
14            if name in self._pyexports:
15                raise cffi.CDefError("duplicate pyexport'ed function %r"
16                                     % (name,))
17            callback_var = self.getctype(tp, name)
18            self.cdef("%s;" % callback_var)
19            self._pyexports[name] = _PyExport(tp, func)
20        return decorator
21
22    def verify(self, source='', **kwargs):
23        extras = []
24        pyexports = sorted(self._pyexports.items())
25        for name, export in pyexports:
26            callback_var = self.getctype(export.tp, name)
27            extras.append("%s;" % callback_var)
28        extras.append(source)
29        source = '\n'.join(extras)
30        lib = FFI.verify(self, source, **kwargs)
31        for name, export in pyexports:
32            cb = self.callback(export.tp, export.func)
33            export.cb = cb
34            setattr(lib, name, cb)
35        return lib
36
37
38class _PyExport(object):
39    def __init__(self, tp, func):
40        self.tp = tp
41        self.func = func
42
43
44if __name__ == '__main__':
45    ffi = PythonFFI()
46
47    @ffi.pyexport("int(int)")
48    def add1(n):
49        print n
50        return n + 1
51
52    ffi.cdef("""
53        int f(int);
54    """)
55
56    lib = ffi.verify("""
57        int f(int x) {
58            return add1(add1(x));
59        }
60    """)
61
62    assert lib.f(5) == 7
63