Author: Jeremy Thurgood <fir...@gmail.com> Branch: split-verify Changeset: r1372:ce63a7e3e315 Date: 2013-10-07 13:46 +0200 http://bitbucket.org/cffi/cffi/changeset/ce63a7e3e315/
Log: Experimental serialisation of cffi.model types into Python code that instantiates them. diff --git a/cffi/builder.py b/cffi/builder.py --- a/cffi/builder.py +++ b/cffi/builder.py @@ -1,7 +1,7 @@ import os -import pickle from .api import FFI +from . import model MODULE_BOILERPLATE = """ @@ -10,7 +10,7 @@ ##### ##### import pickle -from cffi import FFI +from cffi import FFI, model _ffi = FFI() @@ -67,6 +67,60 @@ """ +class NotReadyYet(Exception): + pass + + +class DeclarationBuilder(object): + def __init__(self, model_object, built_declarations, our_declarations): + self._model_object = model_object + self._built_declarations = built_declarations + self._our_declarations = our_declarations + + def _format_param(self, param): + if isinstance(param, model.BaseTypeByIdentity): + od = (type(param), getattr(param, 'name', None)) + if od not in self._our_declarations: + return DeclarationBuilder( + param, self._built_declarations, + self._our_declarations).build() + if param not in self._built_declarations: + raise NotReadyYet() + return "declarations[%r]" % self._built_declarations[param] + if isinstance(param, tuple): + return '(%s,)' % ', '.join(self._format_param(p) for p in param) + return repr(param) + + def build(self): + try: + params = [(k, self._format_param(v)) + for k, v in self._model_object._get_items()] + if isinstance(self._model_object, model.StructOrUnion): + params.extend([ + ('fldnames', self._format_param( + self._model_object.fldnames)), + ('fldtypes', self._format_param( + self._model_object.fldtypes)), + ('fldbitsize', self._format_param( + self._model_object.fldbitsize)), + ]) + elif isinstance(self._model_object, model.EnumType): + params.extend([ + ('enumerators', self._format_param( + self._model_object.enumerators)), + ('enumvalues', self._format_param( + self._model_object.enumvalues)), + ('baseinttype', self._format_param( + self._model_object.baseinttype)), + ]) + except NotReadyYet: + return None + + return "model.%s(%s)" % ( + self._model_object.__class__.__name__, ', '.join( + '%s=%s' % param for param in params)) + + class FFIBuilder(object): def __init__(self, module_name, build_path, backend=None): module_package = '' @@ -104,11 +158,47 @@ self.ffi.verifier.make_library(libfile_build_path) self._module_source += MAKELIB_FUNC_TEMPLATE % (libname, barefilename) self._built_files.append(libfile_path) + return self.ffi.verifier._load_library() + + def _write_declarations(self): + self._module_source += "def _make_declarations():\n" + self._module_source += " declarations = {}\n" + + declarations = self.ffi._parser._declarations + our_decls = set((type(obj), getattr(obj, 'name', None)) + for obj in declarations.values()) + built_decls = {} + decls = [(k, DeclarationBuilder(v, built_decls, our_decls)) + for k, v in self.ffi._parser._declarations.items()] + + max_tries = (len(decls) + 1) ** 2 / 2 + + tries = 0 + while decls: + tries += 1 + if tries > max_tries: + raise Exception("Problem serialising declarations.") + name, dbuilder = decls.pop(0) + instantiation = dbuilder.build() + if instantiation is None: + decls.append((name, dbuilder)) + else: + built_decls[dbuilder._model_object] = name + self._module_source += " declarations[%r] = %s\n" % ( + name, instantiation) + if getattr(dbuilder._model_object, 'partial_resolved', None): + self._module_source += ( + " declarations[%r].partial = True\n" % (name,)) + self._module_source += ( + " declarations[%r].partial_resolved = True\n" % ( + name,)) + + self._module_source += " return declarations\n\n" + self._module_source += ( + "_ffi._parser._declarations = _make_declarations()\n") def write_ffi_module(self): - self._module_source += ( - "_ffi._parser._declarations = pickle.loads(%r)\n" % - pickle.dumps(self.ffi._parser._declarations, 2)) + self._write_declarations() try: os.makedirs(self._build_path) except OSError: diff --git a/testing/test_makelib.py b/testing/test_makelib.py --- a/testing/test_makelib.py +++ b/testing/test_makelib.py @@ -119,10 +119,12 @@ def test_ffi_do_some_stuff(tmpdir): builder = FFIBuilder("foo_ffi", str(tmpdir)) builder.cdef(""" + enum ee { EE1, EE2, EE3, ... }; struct foo_s { int x; int y; }; int grid_distance(struct foo_s offset); """) builder.makelib('foo', """ + enum ee { EE1=10, EE2, EE3=-10, EE4 }; struct foo_s { int x; int y; }; int grid_distance(struct foo_s offset) { return offset.x + offset.y; @@ -142,6 +144,8 @@ assert foo_ffi.alignof('struct foo_s') == foo_ffi.sizeof('int') assert foo_ffi.typeof(foo_ffi.cast('long', 42)) == foo_ffi.typeof('long') assert foo_ffi.string(foo_ffi.new('char *', b"\x00")) == b"" + assert foo_ffi.string(foo_ffi.cast('enum ee', 11)) == "EE2" + assert foo_ffi.string(foo_ffi.cast('enum ee', -10)) == "EE3" def cb(n): return n + 1 _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit