rombob 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
rombob/__init__.py ADDED
@@ -0,0 +1,153 @@
1
+ """rombob: binary serialization using type hints and annotations."""
2
+
3
+ from .aliases import F16_B as F16_B
4
+ from .aliases import F16_L as F16_L
5
+ from .aliases import F32_B as F32_B
6
+ from .aliases import F32_L as F32_L
7
+ from .aliases import F64_B as F64_B
8
+ from .aliases import F64_L as F64_L
9
+ from .aliases import I8_B as I8_B
10
+ from .aliases import I8_L as I8_L
11
+ from .aliases import I16_B as I16_B
12
+ from .aliases import I16_L as I16_L
13
+ from .aliases import I24_B as I24_B
14
+ from .aliases import I24_L as I24_L
15
+ from .aliases import I32_B as I32_B
16
+ from .aliases import I32_L as I32_L
17
+ from .aliases import I48_B as I48_B
18
+ from .aliases import I48_L as I48_L
19
+ from .aliases import I64_B as I64_B
20
+ from .aliases import I64_L as I64_L
21
+ from .aliases import U8_B as U8_B
22
+ from .aliases import U8_L as U8_L
23
+ from .aliases import U16_B as U16_B
24
+ from .aliases import U16_L as U16_L
25
+ from .aliases import U24_B as U24_B
26
+ from .aliases import U24_L as U24_L
27
+ from .aliases import U32_B as U32_B
28
+ from .aliases import U32_L as U32_L
29
+ from .aliases import U48_B as U48_B
30
+ from .aliases import U48_L as U48_L
31
+ from .aliases import U64_B as U64_B
32
+ from .aliases import U64_L as U64_L
33
+ from .aliases import IVInt as IVInt
34
+ from .aliases import Raw as Raw
35
+ from .aliases import UVInt as UVInt
36
+ from .buffers import Reader as Reader
37
+ from .buffers import Writer as Writer
38
+ from .codecs import BytesCodec as BytesCodec
39
+ from .codecs import Codec as Codec
40
+ from .codecs import CollectionCodec as CollectionCodec
41
+ from .codecs import EnumCodec as EnumCodec
42
+ from .codecs import IntCodec as IntCodec
43
+ from .codecs import LiteralCodec as LiteralCodec
44
+ from .codecs import NamedCodec as NamedCodec
45
+ from .codecs import OptionalCodec as OptionalCodec
46
+ from .codecs import RawCodec as RawCodec
47
+ from .codecs import RefLenCodec as RefLenCodec
48
+ from .codecs import StringCodec as StringCodec
49
+ from .codecs import StructCodec as StructCodec
50
+ from .codecs import ValidatorCodec as ValidatorCodec
51
+ from .codecs import VarIntCodec as VarIntCodec
52
+ from .compiler import ClassCodec as ClassCodec
53
+ from .compiler import DynamicSegment as DynamicSegment
54
+ from .compiler import OptionalSegment as OptionalSegment
55
+ from .compiler import StructSegment as StructSegment
56
+ from .errors import BytesOperationError as BytesOperationError
57
+ from .factory import Factory as Factory
58
+ from .factory import decode as decode
59
+ from .factory import encode as encode
60
+ from .metadata import Ge as Ge
61
+ from .metadata import Gt as Gt
62
+ from .metadata import Le as Le
63
+ from .metadata import Len as Len
64
+ from .metadata import Lt as Lt
65
+ from .metadata import Named as Named
66
+ from .metadata import Predicate as Predicate
67
+ from .metadata import Prefix as Prefix
68
+ from .metadata import Range as Range
69
+ from .metadata import Skip as Skip
70
+ from .metadata import When as When
71
+ from .parser import get_codec as get_codec
72
+ from .typing import BE as BE
73
+ from .typing import LE as LE
74
+ from .typing import Args as Args
75
+ from .typing import ByteOrder as ByteOrder
76
+ from .typing import ParserContext as ParserContext
77
+
78
+ __all__ = [
79
+ "Named",
80
+ "Skip",
81
+ "Len",
82
+ "Prefix",
83
+ "Gt",
84
+ "Ge",
85
+ "Lt",
86
+ "Le",
87
+ "Range",
88
+ "Predicate",
89
+ "When",
90
+ "RefLenCodec",
91
+ "BytesOperationError",
92
+ "Reader",
93
+ "Writer",
94
+ "ByteOrder",
95
+ "LE",
96
+ "BE",
97
+ "Codec",
98
+ "StructCodec",
99
+ "IntCodec",
100
+ "VarIntCodec",
101
+ "StringCodec",
102
+ "BytesCodec",
103
+ "CollectionCodec",
104
+ "RawCodec",
105
+ "OptionalCodec",
106
+ "ValidatorCodec",
107
+ "EnumCodec",
108
+ "Factory",
109
+ "LiteralCodec",
110
+ "NamedCodec",
111
+ "ClassCodec",
112
+ "StructSegment",
113
+ "DynamicSegment",
114
+ "OptionalSegment",
115
+ "I8_L",
116
+ "I8_B",
117
+ "U8_L",
118
+ "U8_B",
119
+ "I16_L",
120
+ "I16_B",
121
+ "U16_L",
122
+ "U16_B",
123
+ "I24_L",
124
+ "I24_B",
125
+ "U24_L",
126
+ "U24_B",
127
+ "I32_L",
128
+ "I32_B",
129
+ "U32_L",
130
+ "U32_B",
131
+ "I48_L",
132
+ "I48_B",
133
+ "U48_L",
134
+ "U48_B",
135
+ "I64_L",
136
+ "I64_B",
137
+ "U64_L",
138
+ "U64_B",
139
+ "F16_L",
140
+ "F16_B",
141
+ "F32_L",
142
+ "F32_B",
143
+ "F64_L",
144
+ "F64_B",
145
+ "IVInt",
146
+ "UVInt",
147
+ "Raw",
148
+ "ParserContext",
149
+ "Args",
150
+ "get_codec",
151
+ "encode",
152
+ "decode",
153
+ ]
rombob/aliases.py ADDED
@@ -0,0 +1,42 @@
1
+ """
2
+ Public `Annotated` aliases for the common binary types.
3
+ """
4
+
5
+ import typing as t
6
+
7
+ from .codecs import IntCodec, RawCodec, StructCodec, VarIntCodec
8
+ from .typing import BE, LE
9
+
10
+ I8_L = t.Annotated[int, StructCodec("<b")]
11
+ I8_B = t.Annotated[int, StructCodec(">b")]
12
+ U8_L = t.Annotated[int, StructCodec("<B")]
13
+ U8_B = t.Annotated[int, StructCodec(">B")]
14
+ I16_L = t.Annotated[int, StructCodec("<h")]
15
+ I16_B = t.Annotated[int, StructCodec(">h")]
16
+ U16_L = t.Annotated[int, StructCodec("<H")]
17
+ U16_B = t.Annotated[int, StructCodec(">H")]
18
+ I24_L = t.Annotated[int, IntCodec(length=3, byteorder=LE, signed=True)]
19
+ I24_B = t.Annotated[int, IntCodec(length=3, byteorder=BE, signed=True)]
20
+ U24_L = t.Annotated[int, IntCodec(length=3, byteorder=LE, signed=False)]
21
+ U24_B = t.Annotated[int, IntCodec(length=3, byteorder=BE, signed=False)]
22
+ I32_L = t.Annotated[int, StructCodec("<i")]
23
+ I32_B = t.Annotated[int, StructCodec(">i")]
24
+ U32_L = t.Annotated[int, StructCodec("<I")]
25
+ U32_B = t.Annotated[int, StructCodec(">I")]
26
+ I48_L = t.Annotated[int, IntCodec(length=6, byteorder=LE, signed=True)]
27
+ I48_B = t.Annotated[int, IntCodec(length=6, byteorder=BE, signed=True)]
28
+ U48_L = t.Annotated[int, IntCodec(length=6, byteorder=LE, signed=False)]
29
+ U48_B = t.Annotated[int, IntCodec(length=6, byteorder=BE, signed=False)]
30
+ I64_L = t.Annotated[int, StructCodec("<q")]
31
+ I64_B = t.Annotated[int, StructCodec(">q")]
32
+ U64_L = t.Annotated[int, StructCodec("<Q")]
33
+ U64_B = t.Annotated[int, StructCodec(">Q")]
34
+ F16_L = t.Annotated[float, StructCodec("<e")]
35
+ F16_B = t.Annotated[float, StructCodec(">e")]
36
+ F32_L = t.Annotated[float, StructCodec("<f")]
37
+ F32_B = t.Annotated[float, StructCodec(">f")]
38
+ F64_L = t.Annotated[float, StructCodec("<d")]
39
+ F64_B = t.Annotated[float, StructCodec(">d")]
40
+ IVInt = t.Annotated[int, VarIntCodec(signed=True)]
41
+ UVInt = t.Annotated[int, VarIntCodec(signed=False)]
42
+ Raw = t.Annotated[bytes, RawCodec()]
rombob/buffers.py ADDED
@@ -0,0 +1,109 @@
1
+ import struct as s
2
+ import typing as t
3
+
4
+ from .errors import BytesOperationError
5
+ from .typing import Buffer
6
+
7
+
8
+ class Reader:
9
+ """
10
+ Cursor over an input buffer.
11
+
12
+ The reader never slices-and-reassigns the buffer: the position is the
13
+ `offset` only. All values handed out by codecs are copies.
14
+ """
15
+
16
+ __slots__ = ("view", "offset", "data")
17
+
18
+ def __init__(
19
+ self,
20
+ data: Buffer,
21
+ offset: int = 0,
22
+ shared: dict[str, t.Any] | None = None,
23
+ ) -> None:
24
+ view = memoryview(data)
25
+ if view.format != "B" or view.ndim != 1:
26
+ view = view.cast("B")
27
+ self.view = view
28
+ self.offset = offset
29
+ self.data: dict[str, t.Any] = {} if shared is None else shared
30
+
31
+ def __repr__(self) -> str:
32
+ return f"Reader(offset={self.offset}, size={len(self.view)})"
33
+
34
+ @property
35
+ def remaining(self) -> int:
36
+ return len(self.view) - self.offset
37
+
38
+ def take(self, n: int) -> memoryview:
39
+ "Return a view of the next n bytes and advance"
40
+ start = self.offset
41
+ end = start + n
42
+ if n < 0 or end > len(self.view):
43
+ raise BytesOperationError(
44
+ f"Not enough data: need {n} bytes at offset {start}, "
45
+ f"only {len(self.view) - start} left"
46
+ )
47
+ self.offset = end
48
+ return self.view[start:end]
49
+
50
+ def peek(self, n: int, skip: int = 0) -> memoryview:
51
+ "Return a view of n bytes starting `skip` bytes ahead, don't advance"
52
+ start = self.offset + skip
53
+ end = start + n
54
+ if n < 0 or skip < 0 or end > len(self.view):
55
+ raise BytesOperationError(
56
+ f"Not enough data: need {n} bytes at offset {start}, "
57
+ f"only {max(len(self.view) - start, 0)} left"
58
+ )
59
+ return self.view[start:end]
60
+
61
+ def rest(self) -> bytes:
62
+ "Copy of everything left; advances to the end"
63
+ rv = bytes(self.view[self.offset :])
64
+ self.offset = len(self.view)
65
+ return rv
66
+
67
+ def unpack(self, st: s.Struct) -> tuple:
68
+ rv = st.unpack_from(self.view, self.offset)
69
+ self.offset += st.size
70
+ return rv
71
+
72
+ def to_writer(self) -> "Writer":
73
+ return Writer(shared=self.data)
74
+
75
+ def release(self) -> None:
76
+ try:
77
+ self.view.release()
78
+ except BufferError:
79
+ pass
80
+
81
+
82
+ class Writer:
83
+ "Append-only output buffer. `buffer` is always a bytearray."
84
+
85
+ __slots__ = ("buffer", "data")
86
+
87
+ def __init__(
88
+ self,
89
+ buffer: bytearray | None = None,
90
+ shared: dict[str, t.Any] | None = None,
91
+ ) -> None:
92
+ self.buffer = bytearray() if buffer is None else buffer
93
+ self.data: dict[str, t.Any] = {} if shared is None else shared
94
+
95
+ def __repr__(self) -> str:
96
+ return f"Writer(length={len(self.buffer)})"
97
+
98
+ def write(self, b: Buffer) -> None:
99
+ self.buffer += b
100
+
101
+ def pack(self, st: s.Struct, *values: t.Any) -> None:
102
+ self.buffer += st.pack(*values)
103
+
104
+ def getvalue(self) -> bytes:
105
+ return bytes(self.buffer)
106
+
107
+ def to_reader(self) -> Reader:
108
+ "Reader over a snapshot of the buffer, sharing `data`"
109
+ return Reader(bytes(self.buffer), shared=self.data)