api.py 1.6 KB

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