Author: Antonio Cuni <[email protected]>
Branch: ffistruct
Changeset: r55089:5881f062c4f5
Date: 2012-05-14 21:35 +0200
http://bitbucket.org/pypy/pypy/changeset/5881f062c4f5/

Log:    split the _StructDescr initialization in two phases: instantiation
        and field definition. This allow to get its ffitype before it's
        actually complete, in case it's necessary to take a pointer to it

diff --git a/pypy/module/_ffi/interp_ffitype.py 
b/pypy/module/_ffi/interp_ffitype.py
--- a/pypy/module/_ffi/interp_ffitype.py
+++ b/pypy/module/_ffi/interp_ffitype.py
@@ -4,6 +4,7 @@
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.typedef import TypeDef, interp_attrproperty
 from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.error import OperationError
 
 class W_FFIType(Wrappable):
 
@@ -24,13 +25,22 @@
             raise ValueError("Operation not permitted on an incomplete type")
         return self._ffitype
 
+    def set_ffitype(self, ffitype):
+        if self._ffitype:
+            raise ValueError("The _ffitype is already set")
+        self._ffitype = ffitype
+
     def descr_deref_pointer(self, space):
         if self.w_pointer_to is None:
             return space.w_None
         return self.w_pointer_to
 
     def descr_sizeof(self, space):
-        return space.wrap(self.sizeof())
+        try:
+            return space.wrap(self.sizeof())
+        except ValueError:
+            msg = "Operation not permitted on an incomplete type"
+            raise OperationError(space.w_ValueError, space.wrap(msg))
 
     def sizeof(self):
         return intmask(self.get_ffitype().c_size)
diff --git a/pypy/module/_ffi/interp_struct.py 
b/pypy/module/_ffi/interp_struct.py
--- a/pypy/module/_ffi/interp_struct.py
+++ b/pypy/module/_ffi/interp_struct.py
@@ -41,16 +41,34 @@
 
 class W__StructDescr(Wrappable):
 
-    def __init__(self, space, name, fields_w, ffistruct):
+    def __init__(self, space, name):
         self.space = space
-        self.ffistruct = ffistruct
-        self.w_ffitype = W_FFIType('struct %s' % name, ffistruct.ffistruct, 
None)
+        self.w_ffitype = W_FFIType('struct %s' % name, clibffi.FFI_TYPE_NULL, 
None)
+        self.fields_w = None
+        self.name2w_field = {}
+
+    def define_fields(self, space, w_fields):
+        if self.fields_w is not None:
+            raise operationerrfmt(space.w_ValueError,
+                                  "%s's fields has already been defined",
+                                  self.w_ffitype.name)
+        space = self.space
+        fields_w = space.fixedview(w_fields)
+        # note that the fields_w returned by compute_size_and_alignement has a
+        # different annotation than the original: list(W_Root) vs list(W_Field)
+        size, alignment, fields_w = compute_size_and_alignement(space, 
fields_w)
         self.fields_w = fields_w
-        self.name2w_field = {}
+        field_types = [] # clibffi's types
         for w_field in fields_w:
+            field_types.append(w_field.w_ffitype.get_ffitype())
             self.name2w_field[w_field.name] = w_field
+        self.ffistruct = clibffi.make_struct_ffitype_e(size, alignment, 
field_types)
+        self.w_ffitype.set_ffitype(self.ffistruct.ffistruct)
 
     def allocate(self, space):
+        if self.fields_w is None:
+            raise operationerrfmt(space.w_ValueError, "%s has an incomplete 
type",
+                                  self.w_ffitype.name)
         return W__StructInstance(self)
 
     @jit.elidable_promote('0')
@@ -69,16 +87,11 @@
 
 
 @unwrap_spec(name=str)
-def descr_new_structdescr(space, w_type, name, w_fields):
-    fields_w = space.fixedview(w_fields)
-    # note that the fields_w returned by compute_size_and_alignement has a
-    # different annotation than the original: list(W_Root) vs list(W_Field)
-    size, alignment, fields_w = compute_size_and_alignement(space, fields_w)
-    field_types = [] # clibffi's types
-    for w_field in fields_w:
-        field_types.append(w_field.w_ffitype.get_ffitype())
-    ffistruct = clibffi.make_struct_ffitype_e(size, alignment, field_types)
-    return W__StructDescr(space, name, fields_w, ffistruct)
+def descr_new_structdescr(space, w_type, name, w_fields=None):
+    descr = W__StructDescr(space, name)
+    if w_fields is not space.w_None:
+        descr.define_fields(w_fields)
+    return descr
 
 def round_up(size, alignment):
     return (size + alignment - 1) & -alignment
@@ -106,6 +119,7 @@
     '_StructDescr',
     __new__ = interp2app(descr_new_structdescr),
     ffitype = interp_attrproperty('w_ffitype', W__StructDescr),
+    define_fields = interp2app(W__StructDescr.define_fields),
     allocate = interp2app(W__StructDescr.allocate),
     )
 
diff --git a/pypy/module/_ffi/test/test_struct.py 
b/pypy/module/_ffi/test/test_struct.py
--- a/pypy/module/_ffi/test/test_struct.py
+++ b/pypy/module/_ffi/test/test_struct.py
@@ -228,6 +228,25 @@
         mem = self.read_raw_mem(struct.getaddr(), 'c_float', 1)
         assert mem == [123.5]
 
+    def test_define_fields(self):
+        from _ffi import _StructDescr, Field, types
+        longsize = types.slong.sizeof()
+        fields = [
+            Field('x', types.slong),
+            Field('y', types.slong),
+            ]
+        descr = _StructDescr('foo')
+        assert descr.ffitype.name == 'struct foo'
+        assert repr(descr.ffitype) == '<ffi type struct foo (incomplete)>'
+        raises(ValueError, "descr.ffitype.sizeof()")
+        raises(ValueError, "descr.allocate()")
+        #
+        descr.define_fields(fields)
+        assert repr(descr.ffitype) == '<ffi type struct foo>'
+        assert descr.ffitype.sizeof() == longsize*2
+        raises(ValueError, "descr.define_fields(fields)")
+        
+
     def test_compute_shape(self):
         from _ffi import Structure, Field, types
         class Point(Structure):
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to