pythonctypesmemmove

How to define C-Enumeration types in python


I have an enumeration data type in C. How should I declare that in python-ctypes? I want this enum variable to be part of a structure and the assignment of the values to this structure would be done through memmove. After assigning, I want to display the values of each variables in the structure, and for the enum types I want to display the enum-string.


Solution

  • The Enumeration class suggested by Raj Kumar was broken in that it required the __init__ to be run to set a new value in a variable, and thus unusable if the value was changed on C side. Here is a fixed version thereof:

    class EnumerationType(type(c_uint)):
        def __new__(metacls, name, bases, dict):
            if not "_members_" in dict:
                _members_ = {}
                for key, value in dict.items():
                    if not key.startswith("_"):
                        _members_[key] = value
    
                dict["_members_"] = _members_
            else:
                _members_ = dict["_members_"]
    
            dict["_reverse_map_"] = { v: k for k, v in _members_.items() }
            cls = type(c_uint).__new__(metacls, name, bases, dict)
            for key,value in cls._members_.items():
                globals()[key] = value
            return cls
    
        def __repr__(self):
            return "<Enumeration %s>" % self.__name__
    
    class CEnumeration(c_uint):
        __metaclass__ = EnumerationType
        _members_     = {}
    
        def __repr__(self):
            value = self.value
            return "<%s.%s: %d>" % (
                self.__class__.__name__,
                self._reverse_map_.get(value, '(unknown)'),
                value
            )
    
        def __eq__(self, other):
            if isinstance(other, (int, long)):
                return self.value == other
    
            return type(self) == type(other) and self.value == other.value
    

    Now one can declare a CEnumeration:

    class EBoolean(CEnumeration):
        FALSE = 0
        TRUE = 1
    

    and use it:

    class HeaderStruct(Structure):
        _fields_ = [("param1", EBoolean), 
                    ("param2", c_uint)]
    

    Examples:

    >>> header = HeaderStruct()
    >>> header.param1
    <EBoolean.FALSE: 0>
    >>> memmove(addressof(header), b'\x01', 1)  # write LSB 0x01 in the boolean
    >>> header.param1
    <EBoolean.TRUE: 1>
    >>> header.param1 == EBoolean.TRUE
    True
    >>> header.param1 == 1   # as a special case compare against ints
    True
    >>> header.param1.value
    1L