pythoncserialization

How to transfer this part of code from C to Python using dataclass


I have this structure in C:

MAX_NUMBER_OF_ITEMS = 9

typedef struct {   
   uint64_t status;    
   uint8_t serial_number_of_items [MAX_NUMBER_OF_ITEMS];   
   uint8_t version;
} Items_Info_t;

How can I convert it to Python, specifically the part:

uint8_t number_of_items [MAX_NUMBER_OF_ITEMS]

I try to do this way:

class SensorInfo:
    status: int
    serial_number_of_items: List[int] 
    version: int

Also, how can I perform serialization using struct.pack after that?


Solution

  • Create a class to encapsulate Items_Info_t and manage its serialization/deserialization.

    import struct
    from typing import List
    
    
    MAX_NUMBER_OF_ITEMS = 9
    
    class ItemsInfo:
        def __init__(self, status: int, serial_number_of_items: List[int], version: int):
            if len(serial_number_of_items) != MAX_NUMBER_OF_ITEMS:
                raise ValueError(f"serial_number_of_items must have {MAX_NUMBER_OF_ITEMS} elements")
    
            if not all(0 <= item <= 255 for item in serial_number_of_items):
                raise ValueError("All serial numbers must be within the range 0-255 (uint8).")
    
            if not (0 <= version <= 255):
              raise ValueError("version must be within the range 0-255 (uint8).")
    
            if status < 0:
                raise ValueError("Status must be a non-negative integer (uint64).")
    
            self.status = status
            self.serial_number_of_items = serial_number_of_items
            self.version = version
    
    
        def serialize(self, endian: str = '<') -> bytes:
            if endian not in ('<', '>', '!'):
                raise ValueError("Endian must be '<' (little-endian), '>' (big-endian), or '!' (network byte order).")
    
            format_string = f"{endian}Q{'B' * MAX_NUMBER_OF_ITEMS}B"
            return struct.pack(format_string, self.status, *self.serial_number_of_items, self.version)
    
    
        @staticmethod
        def deserialize(data: bytes, endian: str = '<') -> 'ItemsInfo':
            if endian not in ('<', '>', '!'):
                raise ValueError("Endian must be '<' (little-endian), '>' (big-endian), or '!' (network byte order).")
    
            format_string = f"{endian}Q{'B' * MAX_NUMBER_OF_ITEMS}B"
            expected_size = struct.calcsize(format_string)
    
            if len(data) != expected_size:
                raise ValueError(f"Data length is incorrect. Expected {expected_size} bytes, got {len(data)}.")
    
            unpacked_data = struct.unpack(format_string, data)
            status = unpacked_data[0]
            serial_numbers = list(unpacked_data[1:1 + MAX_NUMBER_OF_ITEMS])
            version = unpacked_data[-1]
            return ItemsInfo(status, serial_numbers, version)
    

    Testing

    serial_numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    items_info = ItemsInfo(status=1055, serial_number_of_items=serial_numbers, version=23)
    
    serialized_data_network = items_info.serialize(endian='!')
    print("Serialized Data (network byte order):", serialized_data_network)
    
    print("\nDeserialized Data (network byte order):")
    deserialized_info_network = ItemsInfo.deserialize(serialized_data_network, endian='!')
    print("Status:", deserialized_info_network.status)
    print("Serial Numbers:", deserialized_info_network.serial_number_of_items)
    print("Version:", deserialized_info_network.version)
    

    Output

    Serialized Data (network byte order): b'\x00\x00\x00\x00\x00\x00\x04\x1f\x01\x02\x03\x04\x05\x06\x07\x08\t\x17'
    
    Deserialized Data (network byte order):
    Status: 1055
    Serial Numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9]
    Version: 23