Armin Rigo avatar Armin Rigo committed a23c187

Share most of the code for structs and unions.

Comments (0)

Files changed (1)

ffi/backend_ctypes.py

         CTypesArray._fix_class()
         return CTypesArray
 
-    def new_struct_type(self, name, fnames, BFieldTypes):
+    def _new_struct_or_union(self, name, fnames, BFieldTypes,
+                             kind, base_ctypes_class, initializer):
         #
-        class struct(ctypes.Structure):
+        class struct_or_union(base_ctypes_class):
             if fnames is not None:
                 _fields_ = [(fname, BField._ctype)
                             for (fname, BField) in zip(fnames, BFieldTypes)]
-        struct.__name__ = 'struct_%s' % name
+        struct_or_union.__name__ = '%s_%s' % (kind, name)
         #
-        class CTypesStruct(CTypesData):
-            _ctype = struct
-            _reftypename = 'struct %s &' % name
+        class CTypesStructOrUnion(CTypesData):
+            _ctype = struct_or_union
+            _reftypename = '%s %s &' % (kind, name)
 
             def __init__(self, init):
                 if fnames is None:
                     raise TypeError("cannot instantiate opaque type %s" % (
-                        CTypesStruct,))
-                self._blob = struct()
+                        CTypesStructOrUnion,))
+                self._blob = struct_or_union()
                 if init is not None:
-                    init = tuple(init)
-                    if len(init) > len(fnames):
-                        raise ValueError("too many values for "
-                                         "struct %s initializer" % name)
-                    for value, fname, BField in zip(init, fnames, BFieldTypes):
-                        setattr(self._blob, fname, BField._to_ctypes(value))
+                    initializer(self, init)
         #
         if fnames is not None:
             for fname, BField in zip(fnames, BFieldTypes):
-                if hasattr(CTypesStruct, fname):
+                if hasattr(CTypesStructOrUnion, fname):
                     raise ValueError("the field name %r conflicts in "
                                      "the ctypes backend" % fname)
                 def getter(self, fname=fname, BField=BField):
                     return BField._from_ctypes(getattr(self._blob, fname))
                 def setter(self, value, fname=fname, BField=BField):
                     setattr(self._blob, fname, BField._to_ctypes(value))
-                setattr(CTypesStruct, fname, property(getter, setter))
+                setattr(CTypesStructOrUnion, fname, property(getter, setter))
         #
-        CTypesStruct._fix_class()
-        return CTypesStruct
+        CTypesStructOrUnion._fix_class()
+        return CTypesStructOrUnion
+
+    def new_struct_type(self, name, fnames, BFieldTypes):
+        def initializer(self, init):
+            init = tuple(init)
+            if len(init) > len(fnames):
+                raise ValueError("too many values for "
+                                 "struct %s initializer" % name)
+            for value, fname, BField in zip(init, fnames, BFieldTypes):
+                setattr(self._blob, fname, BField._to_ctypes(value))
+        return self._new_struct_or_union(name, fnames, BFieldTypes,
+                                         'struct', ctypes.Structure,
+                                         initializer)
 
     def new_union_type(self, name, fnames, BFieldTypes):
-        #
-        class union(ctypes.Union):
-            if fnames is not None:
-                _fields_ = [(fname, BField._ctype)
-                            for (fname, BField) in zip(fnames, BFieldTypes)]
-        union.__name__ = 'union_%s' % name
-        #
-        class CTypesUnion(CTypesData):
-            _ctype = union
-            _reftypename = 'union %s &' % name
-
-            def __init__(self, init):
-                if fnames is None:
-                    raise TypeError("cannot instantiate opaque type %s" % (
-                        CTypesUnion,))
-                self._blob = union()
-                if init is not None:
-                    fname = fnames[0]
-                    BField = BFieldTypes[0]
-                    setattr(self._blob, fname, BField._to_ctypes(init))
-        #
-        if fnames is not None:
-            for fname, BField in zip(fnames, BFieldTypes):
-                if hasattr(CTypesUnion, fname):
-                    raise ValueError("the field name %r conflicts in "
-                                     "the ctypes backend" % fname)
-                def getter(self, fname=fname, BField=BField):
-                    return BField._from_ctypes(getattr(self._blob, fname))
-                def setter(self, value, fname=fname, BField=BField):
-                    setattr(self._blob, fname, BField._to_ctypes(value))
-                setattr(CTypesUnion, fname, property(getter, setter))
-        #
-        CTypesUnion._fix_class()
-        return CTypesUnion
+        def initializer(self, init):
+            fname = fnames[0]
+            BField = BFieldTypes[0]
+            setattr(self._blob, fname, BField._to_ctypes(init))
+        return self._new_struct_or_union(name, fnames, BFieldTypes,
+                                         'union', ctypes.Union,
+                                         initializer)
 
 
 class CTypesLibrary(object):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.