Skip to content

Commit ecbc856

Browse files
authored
Merge pull request #1 from ModernMAK/dunder-magic
Move codebase to dunder-methods, metaclasses, and protocols
2 parents 650b1c1 + 3c2ecaf commit ecbc856

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+4928
-1618
lines changed

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = struct-lib
3-
version = 2022.0-b1
3+
version = 2022.1-b0
44
author = Marcus Kertesz
55
description = An object-oriented alternative to the built-in struct module. Still uses struct under the hood, but allows defining user structures, and packing into/from binaryio/bytesio types.
66
long_description = file: README.md

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from setuptools import setup
22

33
if __name__ == "__main__":
4-
setup()
4+
setup()
5+

src/structlib/abc_/__init__.py

Whitespace-only changes.

src/structlib/abc_/packing.py

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
from abc import ABC, abstractmethod
2+
from typing import Tuple, BinaryIO, Any
3+
from structlib.io import bufferio, streamio
4+
from structlib.protocols.packing import Packable, IterPackable, StructPackable, PrimitivePackable, TPrim, DataclassPackable, DClassType, DClass, ConstPackable
5+
from structlib.protocols.typedef import align_of, size_of, TypeDefAlignable, TypeDefSizable, T
6+
from structlib.typing_ import WritableBuffer, ReadableBuffer, ReadableStream, WritableStream
7+
8+
9+
class PackableABC(Packable, TypeDefSizable, TypeDefAlignable, ABC):
10+
"""
11+
A Packable which uses pack/unpack and a fixed size typedef to perform buffer/stream operations.
12+
"""
13+
14+
def pack_buffer(self, buffer: WritableBuffer, *args: Any, offset: int, origin: int) -> int:
15+
packed = self.pack(*args)
16+
alignment = align_of(self)
17+
return bufferio.write(buffer, packed, alignment, offset, origin)
18+
19+
def unpack_buffer(self, buffer: ReadableBuffer, *, offset: int, origin: int) -> Tuple[int, Any]:
20+
size = size_of(self)
21+
alignment = align_of(self)
22+
read, packed = bufferio.read(buffer, size, alignment, offset, origin)
23+
unpacked = self.unpack(packed)
24+
return read, unpacked
25+
26+
def pack_stream(self, stream: BinaryIO, *args: Any, origin: int) -> int:
27+
packed = self.pack(*args)
28+
alignment = align_of(self)
29+
return streamio.write(stream, packed, alignment, origin)
30+
31+
def unpack_stream(self, stream: BinaryIO, *, origin: int) -> Tuple[int, Any]:
32+
size = size_of(self)
33+
alignment = align_of(self)
34+
read, packed = streamio.read(stream, size, alignment, origin)
35+
unpacked = self.unpack(packed)
36+
return read, unpacked
37+
38+
39+
class ConstPackableABC(ConstPackable, TypeDefSizable, TypeDefAlignable, ABC):
40+
"""
41+
A ConstPackable which uses pack/unpack and a fixed size typedef to perform buffer/stream operations.
42+
"""
43+
44+
def const_pack_buffer(self, buffer: WritableBuffer, offset: int, origin: int) -> int:
45+
packed = self.const_pack()
46+
alignment = align_of(self)
47+
return bufferio.write(buffer, packed, alignment, offset, origin)
48+
49+
def const_unpack_buffer(self, buffer: ReadableBuffer, *, offset: int, origin: int) -> Tuple[int, Any]:
50+
size = size_of(self)
51+
alignment = align_of(self)
52+
read, packed = bufferio.read(buffer, size, alignment, offset, origin)
53+
unpacked = self.const_unpack(packed)
54+
return read, unpacked
55+
56+
def const_pack_stream(self, stream: BinaryIO, *args: Any, origin: int) -> int:
57+
packed = self.const_pack()
58+
alignment = align_of(self)
59+
return streamio.write(stream, packed, alignment, origin)
60+
61+
def const_unpack_stream(self, stream: BinaryIO, *, origin: int) -> Tuple[int, Any]:
62+
size = size_of(self)
63+
alignment = align_of(self)
64+
read, packed = streamio.read(stream, size, alignment, origin)
65+
unpacked = self.const_unpack(packed)
66+
return read, unpacked
67+
68+
69+
class IterPackableABC(IterPackable, TypeDefSizable, TypeDefAlignable, ABC):
70+
"""
71+
An IterPackable which uses iter_pack/iter_unpack to perform buffer/stream operations.
72+
"""
73+
74+
def iter_pack_buffer(self, buffer: WritableBuffer, *args: Any, offset: int, origin: int) -> int:
75+
packed = self.iter_pack(*args)
76+
alignment = align_of(self)
77+
return bufferio.write(buffer, packed, alignment, offset, origin)
78+
79+
def iter_unpack_buffer(self, buffer: ReadableBuffer, iter_count: int, *, offset: int, origin: int) -> Tuple[int, Any]:
80+
size = size_of(self) * iter_count
81+
alignment = align_of(self)
82+
read, packed = bufferio.read(buffer, size, alignment, offset, origin)
83+
unpacked = self.iter_unpack(packed, iter_count)
84+
return read, unpacked
85+
86+
def iter_pack_stream(self, stream: BinaryIO, *args: Any, origin: int) -> int:
87+
packed = self.iter_pack(*args)
88+
alignment = align_of(self)
89+
return streamio.write(stream, packed, alignment, origin)
90+
91+
def iter_unpack_stream(self, stream: BinaryIO, iter_count: int, *, origin: int) -> Tuple[int, Any]:
92+
size = size_of(self) * iter_count
93+
alignment = align_of(self)
94+
read, packed = streamio.read(stream, size, alignment, origin)
95+
unpacked = self.iter_unpack(packed, iter_count)
96+
return read, unpacked
97+
98+
99+
class StructPackableABC(StructPackable, TypeDefSizable, TypeDefAlignable, ABC):
100+
"""
101+
A Packable which uses pack/unpack to perform buffer/stream operations.
102+
"""
103+
104+
def struct_pack_buffer(self, buffer: WritableBuffer, *args: Any, offset: int, origin: int) -> int:
105+
packed = self.struct_pack(*args)
106+
alignment = align_of(self)
107+
return bufferio.write(buffer, packed, alignment, offset, origin)
108+
109+
def struct_unpack_buffer(self, buffer: ReadableBuffer, *, offset: int, origin: int) -> Tuple[int, Any]:
110+
size = size_of(self)
111+
alignment = align_of(self)
112+
read, packed = bufferio.read(buffer, size, alignment, offset, origin)
113+
unpacked = self.struct_unpack(packed)
114+
return read, unpacked
115+
116+
def struct_pack_stream(self, stream: BinaryIO, *args: Any, origin: int) -> int:
117+
packed = self.struct_pack(*args)
118+
alignment = align_of(self)
119+
return streamio.write(stream, packed, alignment, origin)
120+
121+
def struct_unpack_stream(self, stream: BinaryIO, *, origin: int) -> Tuple[int, Any]:
122+
size = size_of(self)
123+
alignment = align_of(self)
124+
read, packed = streamio.read(stream, size, alignment, origin)
125+
unpacked = self.struct_unpack(packed)
126+
return read, unpacked
127+
128+
129+
class PrimitivePackableABC(PrimitivePackable, TypeDefSizable, TypeDefAlignable, ABC):
130+
"""
131+
A Packable which uses pack/unpack to perform buffer/stream operations.
132+
"""
133+
134+
def prim_pack_buffer(self, buffer: WritableBuffer, arg: TPrim, *, offset: int = 0, origin: int = 0) -> int:
135+
packed = self.prim_pack(arg)
136+
alignment = align_of(self)
137+
return bufferio.write(buffer, packed, alignment, offset, origin)
138+
139+
def unpack_prim_buffer(self, buffer: ReadableBuffer, *, offset: int = 0, origin: int = 0) -> Tuple[int, TPrim]:
140+
size = size_of(self)
141+
alignment = align_of(self)
142+
read, packed = bufferio.read(buffer, size, alignment, offset, origin)
143+
unpacked = self.unpack_prim(packed)
144+
return read, unpacked
145+
146+
def prim_pack_stream(self, stream: WritableStream, arg: TPrim, *, origin: int = 0) -> int:
147+
packed = self.prim_pack(arg)
148+
alignment = align_of(self)
149+
return streamio.write(stream, packed, alignment, origin)
150+
151+
def unpack_prim_stream(self, stream: ReadableStream, *, origin: int = 0) -> Tuple[int, TPrim]:
152+
size = size_of(self)
153+
alignment = align_of(self)
154+
read, packed = streamio.read(stream, size, alignment, origin)
155+
unpacked = self.unpack_prim(packed)
156+
return read, unpacked
157+
158+
159+
class DataclassPackableABC(DataclassPackable, TypeDefSizable, TypeDefAlignable, ABC):
160+
"""
161+
A Packable which uses pack/unpack to perform buffer/stream operations.
162+
"""
163+
164+
def dclass_pack_buffer(self, buffer: WritableBuffer, *, offset: int = 0, origin: int = 0) -> int:
165+
packed = self.dclass_pack()
166+
alignment = align_of(self)
167+
return bufferio.write(buffer, packed, alignment, offset, origin)
168+
169+
@classmethod
170+
def dclass_unpack_buffer(cls: DClassType, buffer: ReadableBuffer, *, offset: int = 0, origin: int = 0) -> Tuple[int, DClass]:
171+
size = size_of(cls)
172+
alignment = align_of(cls)
173+
read, packed = bufferio.read(buffer, size, alignment, offset, origin)
174+
unpacked = cls.dclass_unpack(packed)
175+
return read, unpacked
176+
177+
def dclass_pack_stream(self, stream: WritableStream, *, origin: int = 0) -> int:
178+
packed = self.dclass_pack()
179+
alignment = align_of(self)
180+
return streamio.write(stream, packed, alignment, origin)
181+
182+
@classmethod
183+
def dclass_unpack_stream(cls: DClassType, stream: ReadableStream, *, origin: int = 0) -> Tuple[int, DClass]:
184+
size = size_of(cls)
185+
alignment = align_of(cls)
186+
read, packed = streamio.read(stream, size, alignment, origin)
187+
unpacked = cls.dclass_unpack(packed)
188+
return read, unpacked

src/structlib/abc_/typedef.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from __future__ import annotations
2+
3+
from copy import copy
4+
from typing import TypeVar
5+
6+
from structlib.byteorder import ByteOrder
7+
from structlib.protocols.typedef import TypeDefAlignable, TypeDefByteOrder, TypeDefSizable
8+
9+
T = TypeVar("T")
10+
11+
12+
class TypeDefAlignableABC(TypeDefAlignable):
13+
def __init__(self, alignment: int):
14+
self.__typedef_alignment__ = alignment
15+
16+
def __typedef_align_as__(self: T, alignment: int) -> T:
17+
if self.__typedef_alignment__ == alignment:
18+
return self
19+
else:
20+
inst = copy(self)
21+
inst.__typedef_alignment__ = alignment
22+
return inst
23+
24+
25+
class TypeDefSizableABC(TypeDefSizable):
26+
def __init__(self, native_size: int):
27+
self.__typedef_native_size__ = native_size
28+
29+
30+
class TypeDefByteOrderABC(TypeDefByteOrder):
31+
def __init__(self, byteorder: ByteOrder):
32+
self.__typedef_byteorder__ = byteorder
33+
34+
def __typedef_byteorder_as__(self: T, byteorder: ByteOrder) -> T:
35+
if self.__typedef_byteorder__ == byteorder:
36+
return self
37+
else:
38+
inst = copy(self)
39+
inst.__typedef_byteorder__ = byteorder
40+
return inst
41+

src/structlib/byteorder.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import sys
2+
from typing import Literal, Optional
3+
4+
ByteOrder = Literal["little", "big"]
5+
6+
LittleEndian: Literal["little"] = "little"
7+
BigEndian: Literal["big"] = "big"
8+
NetworkEndian: ByteOrder = BigEndian
9+
NativeEndian: ByteOrder = sys.byteorder
10+
11+
12+
def resolve_byteorder(*byteorder: Optional[ByteOrder], default: ByteOrder = NativeEndian):
13+
"""
14+
Will resolve to the first non-None byteorder, if all byteorder objects are None, default will be used.
15+
:param byteorder:
16+
:param default:
17+
:return:
18+
"""
19+
for bom in byteorder:
20+
if bom is None:
21+
continue
22+
return bom
23+
return default

0 commit comments

Comments
 (0)