def complete_struct_or_union()

in functions/source/KeyGen/cffi/backend_ctypes.py [0:0]


    def complete_struct_or_union(self, CTypesStructOrUnion, fields, tp,
                                 totalsize=-1, totalalignment=-1, sflags=0,
                                 pack=0):
        if totalsize >= 0 or totalalignment >= 0:
            raise NotImplementedError("the ctypes backend of CFFI does not support "
                                      "structures completed by verify(); please "
                                      "compile and install the _cffi_backend module.")
        struct_or_union = CTypesStructOrUnion._ctype
        fnames = [fname for (fname, BField, bitsize) in fields]
        btypes = [BField for (fname, BField, bitsize) in fields]
        bitfields = [bitsize for (fname, BField, bitsize) in fields]
        #
        bfield_types = {}
        cfields = []
        for (fname, BField, bitsize) in fields:
            if bitsize < 0:
                cfields.append((fname, BField._ctype))
                bfield_types[fname] = BField
            else:
                cfields.append((fname, BField._ctype, bitsize))
                bfield_types[fname] = Ellipsis
        if sflags & 8:
            struct_or_union._pack_ = 1
        elif pack:
            struct_or_union._pack_ = pack
        struct_or_union._fields_ = cfields
        CTypesStructOrUnion._bfield_types = bfield_types
        #
        @staticmethod
        def _create_ctype_obj(init):
            result = struct_or_union()
            if init is not None:
                initialize(result, init)
            return result
        CTypesStructOrUnion._create_ctype_obj = _create_ctype_obj
        #
        def initialize(blob, init):
            if is_union:
                if len(init) > 1:
                    raise ValueError("union initializer: %d items given, but "
                                    "only one supported (use a dict if needed)"
                                     % (len(init),))
            if not isinstance(init, dict):
                if isinstance(init, (bytes, unicode)):
                    raise TypeError("union initializer: got a str")
                init = tuple(init)
                if len(init) > len(fnames):
                    raise ValueError("too many values for %s initializer" %
                                     CTypesStructOrUnion._get_c_name())
                init = dict(zip(fnames, init))
            addr = ctypes.addressof(blob)
            for fname, value in init.items():
                BField, bitsize = name2fieldtype[fname]
                assert bitsize < 0, \
                       "not implemented: initializer with bit fields"
                offset = CTypesStructOrUnion._offsetof(fname)
                PTR = ctypes.POINTER(BField._ctype)
                p = ctypes.cast(addr + offset, PTR)
                BField._initialize(p.contents, value)
        is_union = CTypesStructOrUnion._kind == 'union'
        name2fieldtype = dict(zip(fnames, zip(btypes, bitfields)))
        #
        for fname, BField, bitsize in fields:
            if fname == '':
                raise NotImplementedError("nested anonymous structs/unions")
            if hasattr(CTypesStructOrUnion, fname):
                raise ValueError("the field name %r conflicts in "
                                 "the ctypes backend" % fname)
            if bitsize < 0:
                def getter(self, fname=fname, BField=BField,
                           offset=CTypesStructOrUnion._offsetof(fname),
                           PTR=ctypes.POINTER(BField._ctype)):
                    addr = ctypes.addressof(self._blob)
                    p = ctypes.cast(addr + offset, PTR)
                    return BField._from_ctypes(p.contents)
                def setter(self, value, fname=fname, BField=BField):
                    setattr(self._blob, fname, BField._to_ctypes(value))
                #
                if issubclass(BField, CTypesGenericArray):
                    setter = None
                    if BField._declared_length == 0:
                        def getter(self, fname=fname, BFieldPtr=BField._CTPtr,
                                   offset=CTypesStructOrUnion._offsetof(fname),
                                   PTR=ctypes.POINTER(BField._ctype)):
                            addr = ctypes.addressof(self._blob)
                            p = ctypes.cast(addr + offset, PTR)
                            return BFieldPtr._from_ctypes(p)
                #
            else:
                def getter(self, fname=fname, BField=BField):
                    return BField._from_ctypes(getattr(self._blob, fname))
                def setter(self, value, fname=fname, BField=BField):
                    # xxx obscure workaround
                    value = BField._to_ctypes(value)
                    oldvalue = getattr(self._blob, fname)
                    setattr(self._blob, fname, value)
                    if value != getattr(self._blob, fname):
                        setattr(self._blob, fname, oldvalue)
                        raise OverflowError("value too large for bitfield")
            setattr(CTypesStructOrUnion, fname, property(getter, setter))
        #
        CTypesPtr = self.ffi._get_cached_btype(model.PointerType(tp))
        for fname in fnames:
            if hasattr(CTypesPtr, fname):
                raise ValueError("the field name %r conflicts in "
                                 "the ctypes backend" % fname)
            def getter(self, fname=fname):
                return getattr(self[0], fname)
            def setter(self, value, fname=fname):
                setattr(self[0], fname, value)
            setattr(CTypesPtr, fname, property(getter, setter))