### Plum Setup for Bit Field Examples Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/structure/bitfields.rst This code block sets up the necessary imports from the plum library for demonstrating bit field structures. It includes imports for IntEnum, uint8, EnumX, Structure, bitfield_member, member, pack, and unpack. ```python from enum import IntEnum from plum.bigendian import uint8 from plum.enum import EnumX from plum.structure import Structure, bitfield_member, member from plum.utilities import pack, unpack class Register(IntEnum): PC = 0 SP = 1 R0 = 2 ``` -------------------------------- ### Setup for plum.enum Examples Source: https://gitlab.com/dangass/plum/-/blob/master/docs/reference/enum.rst This setup code imports necessary classes and functions from the enum and plum libraries, and defines a sample IntEnum class 'Register' to be used in subsequent examples. ```python from enum import IntEnum from plum.enum import EnumX from plum.utilities import pack, unpack class Register(IntEnum): PC = 0 SP = 1 R0 = 2 R1 = 3 ``` -------------------------------- ### Python: Setup for Plum Transforms Source: https://gitlab.com/dangass/plum/-/blob/master/docs/reference/none.rst This code sets up necessary transforms like IntX and NoneX from the plum library. It defines unsigned 8-bit and 16-bit integers for use in subsequent examples. These are foundational for demonstrating data packing and unpacking with conditional member types. ```python from plum.int import IntX from plum.none import NoneX from plum.structure import Structure, member uint8 = IntX(nbytes=1, byteorder="little", signed=False) uint16 = IntX(nbytes=2, byteorder="little", signed=False) ``` -------------------------------- ### Install plum-boost using pip Source: https://gitlab.com/dangass/plum/-/blob/master/boost/README.rst This command installs or upgrades the plum-boost package using pip. It requires Python 3.6 or later and a C/C++ compiler. ```shell python -m pip install --upgrade plum-boost ``` -------------------------------- ### Get Size of Data Store Instance (Plum) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/size.rst Illustrates how the 'nbytes' property, when applied to an instance of a data store (like a Structure), returns the size based on the actual data within that instance. ```python from typing import List from plum.array import ArrayX from plum.structure import Structure, member greedy_array = ArrayX(fmt=uint16) class GreedyStruct(Structure): m1: int = member(fmt=uint8) m2: List[int] = member(fmt=greedy_array) instance = GreedyStruct(m1=1, m2=[1, 2, 3]) print(instance.nbytes) ``` -------------------------------- ### Install Plum Python Package with Pip Source: https://gitlab.com/dangass/plum/-/blob/master/docs/installation.rst This command uses pip to download and install the latest version of the plum-py package. Ensure you have Python 3.7 or higher installed. ```bash python -m pip install --upgrade plum-py ``` -------------------------------- ### Python: Packing and Dumping Structure with None Data Source: https://gitlab.com/dangass/plum/-/blob/master/docs/reference/none.rst This Python example demonstrates packing a Struct instance where 'datatype' is 0 and 'data' is None. It then calls .ipack_and_dump() to get the packed byte buffer and the dump string. The output shows the packed buffer as b'\x00' and the dump confirms 'datatype' is 0 and 'data' is None, validating the packing of a structure with a NoneX field. ```python buffer, dump = Struct(datatype=0, data=None).ipack_and_dump() print(dump) ``` -------------------------------- ### Install Wheel and Twine Packages Source: https://gitlab.com/dangass/plum/-/blob/master/docs/contribute.rst Installs the 'wheel' and 'twine' Python packages, which are necessary for building and distributing Python packages. These commands are typically run using the pip package installer. ```shell python -m pip install wheel twine ``` -------------------------------- ### Array Packing and Unpacking with Dimensions in Plum Source: https://gitlab.com/dangass/plum/-/blob/master/docs/index.rst Shows how to define and use ArrayX from plum.array with specified dimensions for packing and unpacking multi-dimensional arrays. This example demonstrates a 2x2 array of uint8. ```python from plum.array import ArrayX from plum.utilities import pack, unpack from plum.littleendian import uint8 array_2x2 = ArrayX(fmt=uint8, dims=(2, 2)) buffer = array_2x2.pack([[1, 2], [3, 4]]) print(buffer) print(array_2x2.unpack(buffer)) ``` -------------------------------- ### Get Size of Fixed-Size Array (Plum) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/size.rst Demonstrates retrieving the size in bytes of a fixed-size array using the 'nbytes' property. This property is available on Plum's ArrayX transform. ```python from plum.array import ArrayX from plum.bigendian import uint16 fixed_array = ArrayX(fmt=uint16, dims=(3,)) print(fixed_array.nbytes) ``` -------------------------------- ### Python: Using NoneX Transform Source: https://gitlab.com/dangass/plum/-/blob/master/docs/reference/none.rst This example demonstrates the basic instantiation of the NoneX transform. The NoneX transform is named for representation purposes, such as in dump format columns. It's a key component for handling optional or conditional data fields. ```python nil = NoneX() ``` -------------------------------- ### BitFields Integer Indexing and Arithmetic in Python Source: https://gitlab.com/dangass/plum/-/blob/master/docs/reference/bitfields.rst Illustrates how BitFields instances behave like integers, supporting comparisons, arithmetic operations, and bitwise shifts. It also shows how to get and set individual bits or ranges of bits using integer indexing. ```python from plum.bitfields import BitFields, bitfield class Sample(BitFields): reserved: int = bitfield(lsb=6, size=2) nibble: int = bitfield(lsb=2, size=4) integer_flag: int = bitfield(lsb=1, size=1) boolean_flag: bool = bitfield(typ=bool, lsb=0, size=1) sample = Sample.from_int(1) print(sample == 1) print(sample + 1) print(sample << 1) print(int(sample)) sample = Sample(boolean_flag=False, integer_flag=0, nibble=0, reserved=0) print(int(sample)) sample.boolean_flag = True print(sample) print(int(sample)) sample = Sample.from_int(0) print(sample[0]) sample[0] = True print(int(sample)) print(sample[2:8]) sample[2:8] = [False, False, False, False, False, True] print(int(sample)) ``` -------------------------------- ### Structure Definition and Usage in Plum Source: https://gitlab.com/dangass/plum/-/blob/master/docs/index.rst Defines and demonstrates the usage of Structure from plum.structure with custom members. This example creates a structure 'MyStruct' with a byte, a word, and a 2x2 array, showing packing, unpacking, and member access. ```python from plum.structure import Structure, member from plum.array import ArrayX from plum.littleendian import uint8, uint16 from plum.utilities import pack, unpack # Assuming array_2x2 is defined as in the previous example array_2x2 = ArrayX(fmt=uint8, dims=(2, 2)) class MyStruct(Structure): byte: int = member(fmt=uint8) word: int = member(fmt=uint16, default=0) array: list = member(fmt=array_2x2) buffer = pack(MyStruct(byte=2, array=[[1, 2], [3, 4]])) print(buffer) mystruct = unpack(MyStruct, buffer) print(mystruct) # access members via attribute or index print(mystruct.byte) print(mystruct[0]) ``` -------------------------------- ### Instance Pack Method in Python Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/packing.rst Shows the `ipack()` method available on data store instances within Plum. This method simplifies obtaining the byte sequence representation of an instance based on its structure and transform properties. ```python >>> MyStruct(m1=1, m2=2).ipack() b'\x00\x01\x02' ``` -------------------------------- ### Pack and Unpack with a Dictionary of Transforms (Python) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/formats.rst Demonstrates packing a dictionary of values into bytes using a dictionary of transforms and unpacking bytes into a dictionary of Python objects. Requires 'plum.bigendian' and 'plum.utilities'. ```python from plum.bigendian import uint8 from plum.utilities import pack, unpack fmt = {"a": uint8, "b": uint8} buffer = pack({"a": 0, "b": 1}, fmt) print(buffer) print(unpack(fmt, buffer)) ``` -------------------------------- ### Pack and Unpack with Nested Transforms (Python) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/formats.rst Shows packing and unpacking arbitrarily nested dictionaries, lists, and tuples of transforms. Requires 'plum.bigendian' and 'plum.utilities'. ```python from plum.bigendian import uint8 from plum.utilities import pack, unpack fmt = [(uint8, uint8), {"a": uint8, "b": uint8}] buffer = pack([(0, 1), {"a": 2, "b": 3}], fmt) print(buffer) print(unpack(fmt, buffer)) ``` -------------------------------- ### Pack and Unpack with a List of Transforms (Python) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/formats.rst Shows how to pack a list of values into bytes using a list of transforms and unpack bytes back into a list of Python objects. Requires 'plum.bigendian' and 'plum.utilities'. ```python from plum.bigendian import uint8 from plum.utilities import pack, unpack fmt = [uint8, uint8, uint8] buffer = pack([0, 1, 2], fmt) print(buffer) print(unpack(fmt, buffer)) ``` -------------------------------- ### Build and Upload Python Package Simultaneously (Shell) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/contribute.rst Performs both the building of Python package distributions and their subsequent upload to PyPI in a single command. This method uses an older, integrated approach within `setup.py` and may not be as flexible or secure as using `twine` separately. It's a convenient shortcut for simpler workflows. ```shell python setup.py bdist_wheel upload ``` -------------------------------- ### Pack Utility Function in Python Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/packing.rst Demonstrates the basic usage of the `pack()` utility function from the Plum library to convert a Python integer into a bytes sequence according to a specified format (uint16). ```python >>> from plum.bigendian import uint8, uint16 >>> from plum.structure import Structure, member >>> from plum.utilities import pack >>> >>> class MyStruct(Structure): ... m1: int = member(fmt=uint16) ... m2: int = member(fmt=uint8) ... >>> pack(1, uint16) b'\x00\x01' ``` -------------------------------- ### Example Structure Usage in Python Source: https://gitlab.com/dangass/plum/-/blob/master/docs/reference/bitfields.rst A simple example demonstrating the basic structure definition of BitFields. This `TwoNibbles` class defines two 4-bit integer fields, `nibble1` and `nibble2`. ```python class TwoNibbles(BitFields): nibble1: int = bitfield(size=4) nibble2: int = bitfield(size=4) ``` -------------------------------- ### Pack and Dump Structure to Bytes with Summary (Python) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/dumps.rst Demonstrates packing a custom structure into bytes and generating a detailed summary of the transformation using `pack_and_dump`. This is useful for visualizing the byte representation of structured data. ```python from plum.littleendian import uint8 from plum.structure import Structure, member from plum.utilities import pack_and_dump class MyStruct(Structure): m1: int = member(fmt=uint8) m2: int = member(fmt=uint8) buffer, dump = pack_and_dump(MyStruct(m1=1, m2=2)) print(dump) ``` -------------------------------- ### Get Size of Fixed-Size Structure (Plum) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/size.rst Shows how to get the size in bytes of a fixed-size structure using the 'nbytes' property. This property is defined on Plum's Structure classes. ```python from plum.bigendian import uint8, uint16 from plum.structure import Structure, member class FixedStruct(Structure): m1: int = member(fmt=uint8) m2: int = member(fmt=uint16) print(FixedStruct.nbytes) ``` -------------------------------- ### Get BitField Values as Dictionary Source: https://gitlab.com/dangass/plum/-/blob/master/docs/reference/bitfields.rst Shows how to use the `asdict()` method to retrieve the values of all bit fields within an instance as a Python dictionary. ```python >>> sample = Sample(boolean_flag=False, integer_flag=0, nibble=0, reserved=0) >>> sample.asdict() {'reserved': 0, 'nibble': 0, 'integer_flag': 0, 'boolean_flag': False} ``` -------------------------------- ### Pack and Unpack with a Tuple of Transforms (Python) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/formats.rst Illustrates packing a list of values into bytes using a tuple of transforms and unpacking bytes into a tuple of Python objects. Requires 'plum.bigendian' and 'plum.utilities'. ```python from plum.bigendian import uint8 from plum.utilities import pack, unpack fmt = (uint8, uint8, uint8) buffer = pack([0, 1, 2], fmt) print(buffer) print(unpack(fmt, buffer)) ``` -------------------------------- ### Pack and Unpack with a Single Transform (Python) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/formats.rst Demonstrates packing a value into bytes using a single transform format and unpacking bytes back into a Python object. Requires the 'plum.bigendian' and 'plum.utilities' modules. ```python from plum.bigendian import uint8 from plum.utilities import pack, unpack fmt = uint8 buffer = pack(0, fmt) print(buffer) print(unpack(fmt, buffer)) ``` -------------------------------- ### Unpack Bytes to Structure with Summary (Python) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/dumps.rst Shows how to unpack bytes into a custom structure and generate a detailed summary of the unpacking process using `unpack_and_dump`. This helps in verifying the data integrity and understanding the structure's byte layout. ```python from plum.littleendian import uint8 from plum.structure import Structure, member from plum.utilities import unpack_and_dump class MyStruct(Structure): m1: int = member(fmt=uint8) m2: int = member(fmt=uint8) # Assuming 'buffer' contains the packed bytes from a previous operation buffer = b'\x01\x02' # Example buffer items, dump = unpack_and_dump(MyStruct, buffer) print(dump) ``` -------------------------------- ### Handle Variable-Size Array Size Error (Plum) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/size.rst Illustrates the SizeError raised when attempting to get the 'nbytes' property of a variably sized array. This indicates that the size cannot be determined statically. ```python from plum.array import ArrayX from plum.exceptions import SizeError greedy_array = ArrayX(fmt=uint16) try: print(greedy_array.nbytes) except SizeError as e: print(f'Error: {e}') ``` -------------------------------- ### Buffer Offset Management in Plum Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/unpacking.rst Demonstrates how to manage the current position within a bytes sequence using the offset attribute of the Plum Buffer class. This allows manual control over the unpacking process. ```python >>> from plum.buffer import Buffer >>> from plum.bigendian import uint8 >>> buffer = Buffer(b'\x00\x01\x02\x03') >>> buffer.offset 0 >>> buffer.offset = 2 >>> buffer.unpack(uint8) 2 ``` -------------------------------- ### Transform Unpack Method in Plum Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/unpacking.rst Shows how to use the unpack() method available on Plum transforms, both as an instance method and a class method for structures. This allows unpacking directly from a buffer. ```python >>> from plum.bigendian import uint16 >>> uint16.unpack(b'\x00\x01') 1 ``` ```python >>> from plum.structure import Structure, member >>> from plum.bigendian import uint8, uint16 >>> class MyStruct(Structure): ... m1: int = member(fmt=uint16) ... m2: int = member(fmt=uint8) ... >>> MyStruct.unpack(b'\x00\x01\x02') MyStruct(m1=1, m2=2) ``` -------------------------------- ### Build Python Package Distributions (Shell) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/contribute.rst Builds source distributions (sdist) and wheel distributions for a Python package. This command uses `setup.py` with the `bdist_wheel` and `sdist` commands to create distributable archives in the `dist/` directory. The `--formats=gztar` option specifies the archive format for the source distribution. ```shell python setup.py bdist_wheel sdist --formats=gztar ``` -------------------------------- ### Demonstrate Arbitrary Nesting with Plum Data Structures (Python) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/nesting.rst This Python code snippet demonstrates how to create arbitrarily nested data structures using Plum's `ArrayX`, `IntX`, and `Structure` types. It defines nested arrays and structures, then unpacks and dumps binary data to visualize the nesting. The output shows the hierarchical structure and allows access to deeply nested elements. ```python from plum.array import ArrayX from plum.int import IntX from plum.structure import Structure, member from plum.utilities import unpack_and_dump uint8 = IntX(byteorder='little', nbytes=1, signed=False) inner_array = ArrayX(fmt=uint8, dims=(3,)) class MyStruct(Structure): count: int = member(fmt=uint8) array: list = member(fmt=inner_array) outer_array = ArrayX(fmt=MyStruct, dims=(2,)) x, dump = unpack_and_dump(outer_array, bytes(range(8))) print(dump) print(x[1].array[1]) ``` -------------------------------- ### Plum: Signed Bit Field Member Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/structure/bitfields.rst Illustrates how to define a bit field member that stores a signed integer by setting the 'signed' argument to True. This example packs a structure containing a signed bit field and a regular member. ```python class Sample(Structure): nibble1: int = bitfield_member(lsb=0, size=4, signed=True) nibble2: int = bitfield_member(lsb=4, size=4) byte: int = member(fmt=uint8) pack(Sample(nibble1=-1, nibble2=0, byte=3)).hex() ``` -------------------------------- ### Generate BitFields Methods with Plum (Python) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/miscellaneous/custommethods.rst This snippet demonstrates generating implementations for BitFields methods like __init__ and __repr__. By assigning a string of method names to BitFields.implementation, Plum generates the necessary code for initializing and representing BitFields objects. ```Python class MyBitFields(BitFields): m1: int = bitfield(lsb=0, size=4) m2: int = bitfield(lsb=4, size=4) BitFields.implementation = "init,repr" ``` ```Python class MyBitFields(BitFields): m1: int = bitfield(lsb=0, size=4) m2: int = bitfield(lsb=4, size=4) def __init__(self, *, m1: int, m2: int) -> None: self.__value__ = 0 self.m1 = m1 self.m2 = m2 def __repr__(self) -> str: try: return f"{type(self).__name__}(m1={self.m1!r}, m2={self.m2!r})" except Exception: return f"{type(self).__name__}()" ``` -------------------------------- ### Automatic Bit Field Positioning (Least Significant to Most) in Python Source: https://gitlab.com/dangass/plum/-/blob/master/docs/reference/bitfields.rst Shows how to automatically position bit fields from the least significant bit locations to the most by setting `fieldorder="least_to_most"`. This example defines `AutoMix` with fields `f1`, `f2`, and `f3` ordered from LSB to MSB. ```python class AutoMix(BitFields, fieldorder="least_to_most"): f1: int = bitfield(size=2) f2: int = bitfield(size=5) f3: int = bitfield(size=1) AutoMix.from_int(0x8b).dump() ``` -------------------------------- ### Incremental Unpacking with Plum Buffer Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/unpacking.rst Illustrates incremental unpacking using the Plum Buffer class. This method is useful for unpacking multiple objects sequentially from a bytes sequence and ensures all bytes are consumed. ```python >>> from plum.buffer import Buffer >>> from plum.bigendian import uint8 >>> buffer = Buffer(b'\x02\x01\x02\x03') >>> array_length = buffer.unpack(uint8) >>> array_length 2 >>> array = buffer.unpack([uint8] * array_length) >>> array [1, 2] ``` ```python >>> from plum.buffer import Buffer >>> from plum.bigendian import uint8 >>> with Buffer(b'\x02\x01\x02\x03') as buffer: ... array_length = buffer.unpack(uint8) ... array = buffer.unpack([uint8] * array_length) ... Traceback (most recent call last): ... plum.exceptions.ExcessMemoryError: 1 unconsumed bytes ``` -------------------------------- ### Nested BitFields with Python Source: https://gitlab.com/dangass/plum/-/blob/master/docs/reference/bitfields.rst Demonstrates how to define nested BitFields subclasses using `nested=True`. This allows for hierarchical bit field organization. The example shows an `Inner` BitFields class nested within an `Outer` BitFields class, illustrating how to access and manipulate bits in the nested structure. ```python class Inner(BitFields, nested=True): b: int = bitfield(lsb=2, size=2) a: int = bitfield(lsb=0, size=2) class Outer(BitFields): j: int = bitfield(lsb=6, size=2) i: Inner = bitfield(typ=Inner, lsb=2, size=4) h: int = bitfield(lsb=0, size=2) sample = Outer(j=3, i=Inner(a=1, b=2), h=0) print(sample.i) print(sample.i.a) sample.dump() ``` -------------------------------- ### Structure with Sized Member and Offset (Python) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/structure/sizedmember.rst Shows how to use the `offset` argument in `sized_member` to account for overhead bytes, such as the size member itself. This is useful when the size member needs to reflect the total size of the structure including itself. The example uses `ArrayX` for a greedy array. ```python from plum.array import ArrayX from plum.structure import Structure, member, sized_member from plum.uint import uint8 array = ArrayX(fmt=uint8) # greedy array class Struct6(Structure): size: int = member(fmt=uint8, compute=True) array: list = sized_member(fmt=array, size=size, offset=1) print(Struct6(array=[0, 1]).dump()) ``` -------------------------------- ### Call Structure Dump Method (Python) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/dumps.rst Shows that a `Structure` instance in `plum` also has a callable `.dump()` method that prints a byte breakdown summary to standard output. This provides a convenient way to quickly inspect the structure's data. ```python from plum.littleendian import uint8 from plum.structure import Structure, member class MyStruct(Structure): m1: int = member(fmt=uint8) m2: int = member(fmt=uint8) struct = MyStruct(m1=1, m2=2) struct.dump() ``` -------------------------------- ### Automatic Bit Field Positioning (Most Significant to Least) in Python Source: https://gitlab.com/dangass/plum/-/blob/master/docs/reference/bitfields.rst Illustrates automatic bit field positioning when `lsb` is not specified. By default, bit fields are placed in order from the most significant bit locations to the least. This example defines `AutoMix` where `f1`, `f2`, and `f3` are automatically assigned positions. ```python class AutoMix(BitFields): f1: int = bitfield(size=1) f2: int = bitfield(size=5) f3: int = bitfield(size=2) AutoMix.from_int(0x8b).dump() ``` -------------------------------- ### Plum: Define Bit Field Members (Explicit LSB) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/structure/bitfields.rst Illustrates defining structure members as bit fields with explicitly specified least significant bit (LSB) positions. This example packs a sample structure with explicitly positioned bit fields and a regular member. ```python class Sample(Structure): nibble1: int = bitfield_member(size=4, lsb=4) nibble2: int = bitfield_member(size=4, lsb=0) byte: int = member(fmt=uint8) pack(Sample(nibble1=1, nibble2=2, byte=3)).hex() ``` -------------------------------- ### Generate Structure Methods with Plum (Python) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/miscellaneous/custommethods.rst This snippet shows how to generate implementations for Structure methods like __init__, __pack__, and __unpack__. By assigning a string of method names to Structure.implementation, Plum automatically generates the corresponding code. This is useful for IDE support and custom member interactions. ```Python class MyStruct(Structure): m1: int = member(fmt=uint16) m2: int = member(fmt=uint8) Structure.implementation = "init,pack,unpack" ``` ```Python class MyStruct(Structure): m1: int = member(fmt=uint16) m2: int = member(fmt=uint8) def __init__(self, *, m1: int, m2: int) -> None: self[:] = (m1, m2) @classmethod def __pack__(cls, value, pieces: List[bytes], dump: Optional[Record] = None) -> None: if isinstance(value, dict): value = cls._make_structure_from_dict(value) (m_m1, m_m2) = value if dump is None: uint16.__pack__(m_m1, pieces, dump) uint8.__pack__(m_m2, pieces, dump) else: m1_dump = dump.add_record(access="m1", fmt=uint16) uint16.__pack__(m_m1, pieces, m1_dump) m2_dump = dump.add_record(access="m2", fmt=uint8) uint8.__pack__(m_m2, pieces, m2_dump) @classmethod def __unpack__(cls, buffer: bytes, offset: int, dump: Optional[Record] = None) -> Tuple["MyStruct", int]: structure = list.__new__(cls) if dump is None: m_m1, offset = uint16.__unpack__(buffer, offset, dump) m_m2, offset = uint8.__unpack__(buffer, offset, dump) else: m1_dump = dump.add_record(access="m1", fmt=uint16) m_m1, offset = uint16.__unpack__(buffer, offset, m1_dump) m2_dump = dump.add_record(access="m2", fmt=uint8) m_m2, offset = uint8.__unpack__(buffer, offset, m2_dump) structure[:] = (m_m1, m_m2) return structure, offset ``` ```Python class MyStruct(Structure): m1: int = member(fmt=uint16) m2: int = member(fmt=uint8) Structure.implementation = "all" ``` -------------------------------- ### Handle Enumeration Data with EnumX Source: https://gitlab.com/dangass/plum/-/blob/master/docs/index.rst Shows how to use `EnumX` from `plum.enum` to control the format of integer enumeration data within structures. This example defines a `Pet` enumeration and a `Family` structure that uses `EnumX` to pack and unpack the `pet` field, demonstrating the resulting dump and the unpacked enum value. ```python from enum import IntEnum from plum.enum import EnumX from plum.structure import Structure, member from plum.type import uint8, uint16 class Pet(IntEnum): CAT = 0 DOG = 1 class Family(Structure): nkids: int = member(fmt=uint8) pet: Pet = member(fmt=EnumX(enum=Pet, nbytes=1)) family = Family.unpack(b'\x02\x01') print(family.dump()) print(family.pet) ``` -------------------------------- ### IntX Transform API Source: https://gitlab.com/dangass/plum/-/blob/master/docs/reference/int.rst Documentation for the IntX transform, including its constructor arguments and available methods. ```APIDOC ## IntX Transform ### Description The `IntX` transform handles the conversion of integer numbers to bytes and vice versa. It is configurable with byte size, byte order, and signedness. ### Constructor Arguments - **nbytes** (int) - Required - The size of the integer in bytes. - **byteorder** (str) - Optional - The byte order, either 'big' or 'little'. Defaults to 'little'. - **signed** (bool) - Optional - Whether the integer is signed. Defaults to False. - **name** (str) - Optional - A name for the transform, used in representations. ### Methods - **pack(value, fmt)**: Packs a value into bytes according to the specified format. - **pack_and_dump(value, fmt)**: Packs a value and returns it along with a dumped representation. - **unpack(fmt, bindata)**: Unpacks bytes into a value according to the specified format. - **unpack_and_dump(fmt, bindata)**: Unpacks bytes and returns the value along with a dumped representation. ### Attributes - **byteorder**: The byte order of the transform. - **name**: The name of the transform. - **nbytes**: The number of bytes for the integer representation. - **signed**: Indicates if the integer is signed. ``` -------------------------------- ### Create FloatX Transforms and Use Pack/Unpack Source: https://gitlab.com/dangass/plum/-/blob/master/docs/reference/float.rst Demonstrates creating FloatX transforms for different byte sizes and byte orders, and then using the pack and unpack utility functions with these transforms. It shows how to convert lists of floats to bytes and back, and how to use FloatX transforms with ArrayX. ```python from plum.array import ArrayX from plum.float import FloatX from plum.utilities import pack, unpack # Example 1: Basic float to bytes and back float16 = FloatX(nbytes=2, byteorder="big") float32 = FloatX(nbytes=4, byteorder="big") fmt = [float16, float32] bindata = pack([1, -2], fmt) print(bindata.hex()) # Expected output: "3c00c0000000" print(unpack(fmt, bindata)) # Expected output: [1.0, -2.0] # Example 2: Using FloatX with ArrayX array2x2 = ArrayX(fmt=float16, dims=(2, 2)) bindata_array = pack([[1, 2], [3, 4]], fmt=array2x2) print(bindata_array.hex()) # Expected output: "3c00400042004400" print(unpack(array2x2, bindata_array)) # Expected output: [[1.0, 2.0], [3.0, 4.0]] ``` -------------------------------- ### Define Structure with Sized Member (Python) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/structure/sizedmember.rst Defines a structure 'Struct1' using Plum's Structure, member, and sized_member. The 'array' member's size is controlled by the 'size' member, and 'bookend' is a standard member. This setup is useful for handling variable-length data within fixed structures. ```python from plum.array import ArrayX from plum.bigendian import uint8 from plum.structure import member, sized_member, Structure array = ArrayX(fmt=uint8) # greedy array class Struct1(Structure): size: int = member(fmt=uint8, compute=True) array: list = sized_member(size=size, fmt=array) bookend: int = member(fmt=uint8) # Example usage: Struct1.unpack(b'\x02\x01\x02\x99').dump() Struct1(array=[1, 2], bookend=0x99).dump() Struct1(array=[1, 2], bookend=0x99).ipack() struct1 = Struct1(array=[1, 2], bookend=123) struct1.array = [1, 2, 3, 4, 5] ``` -------------------------------- ### Custom Variable Member Type with Plum Factory Functions Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/structure/typedmember.rst This example demonstrates a more advanced use case where the data type is determined by the magnitude of the data itself. It utilizes a property 'data_cls' as a factory function for the 'fmt' argument, allowing the 'datatype' to be inferred and automatically set when the 'data' member is modified. ```python from plum.littleendian import uint8, uint16, uint32 from plum.structure import Structure, member class Sample(Structure): def determine_datatype(self): return 1 if self.data >= 256 else 0 @property def data_cls(self): return uint16 if self.datatype else uint8 datatype: int = member(fmt=uint8, default=determine_datatype) data: int = member(fmt=data_cls) @data.setter def data(self, value): self[1] = value # use index to avoid recursion self.datatype = self.determine_datatype() # Example usage: print(Sample(data=0).dump()) print(Sample(data=256).dump()) ``` -------------------------------- ### Unpack with None Format (Python) Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/formats.rst Demonstrates how the unpack utility function returns the remaining available bytes when the format specifier is None. Requires 'plum.bigendian'. ```python from plum.bigendian import uint8 from plum.utilities import unpack print(unpack(fmt=None, buffer=b'\x00\x01')) fmt = [uint8, None] print(unpack(fmt=fmt, buffer=b'\x00\x01\x02')) ``` -------------------------------- ### Create and Use IntX Transform for Integer Conversion Source: https://gitlab.com/dangass/plum/-/blob/master/docs/reference/int.rst Demonstrates creating IntX transforms with different byte orders and signedness, and then using them with pack() and unpack() functions for data serialization and deserialization. It also shows integration with ArrayX for multi-dimensional data. ```python from plum.array import ArrayX from plum.int import IntX from plum.utilities import pack, unpack # Example 1: Basic integer conversion uint8 = IntX(nbytes=1) sint16 = IntX(nbytes=2, byteorder="big", signed=True) fmt = [uint8, sint16] bindata = pack([1, -2], fmt) print(bindata.hex()) # Expected output: '01fffe' print(unpack(fmt, bindata)) # Expected output: [1, -2] # Example 2: Using IntX with ArrayX array2x2 = ArrayX(fmt=uint8, dims=(2, 2)) bindata = pack([[1, 2], [3, 4]], fmt=array2x2) print(bindata.hex()) # Expected output: '01020304' print(unpack(array2x2, bindata)) # Expected output: [[1, 2], [3, 4]] ``` -------------------------------- ### Controlling Size and Byte Order (Big Endian) in Python Source: https://gitlab.com/dangass/plum/-/blob/master/docs/reference/bitfields.rst Demonstrates how to explicitly control the number of bytes an overall bit field collection occupies using `nbytes` and set the byte order to big endian using `byteorder="big"`. This example defines a `Sample` class with two 4-bit fields. ```python class Sample(BitFields, nbytes=2, byteorder="big"): f1: int = bitfield(size=4) f2: int = bitfield(size=4) Sample.from_int(0x0012).dump() ``` -------------------------------- ### Transform Pack Methods in Python Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/basics/packing.rst Illustrates how Plum transforms, like `uint16` and custom `Structure` classes, have a `pack()` method to convert Python objects into bytes. This method uses the transform's defined format for packing. ```python >>> uint16.pack(1) b'\x00\x01' >>> >>> MyStruct.pack(MyStruct(m1=1, m2=2)) b'\x00\x01\x02' ``` -------------------------------- ### Define Dynamically Typed Structure Member with Plum Source: https://gitlab.com/dangass/plum/-/blob/master/docs/tutorials/structure/typedmember.rst This example shows how to define a Plum structure where the 'data' member's type is dynamically determined by the 'datatype' member. It uses a dictionary mapping to select the appropriate format (uint8, uint16, uint32) based on the 'datatype' value during unpacking and packing. ```python from plum.littleendian import uint8, uint16, uint32 from plum.structure import Structure, member FMT_MAP = {0: uint8, 1: uint16, 2: uint32} class Struct1(Structure): datatype: int = member(fmt=uint8) data: int = member(fmt=FMT_MAP.__getitem__, fmt_arg=datatype) # Example usage: struct1 = Struct1.unpack(b'\x01\x02\x00') print(struct1) print(struct1.dump()) print(Struct1(datatype=0, data=2).ipack()) print(Struct1(datatype=1, data=2).ipack()) ```