tsrkit-types 0.1.2__py3-none-any.whl → 0.1.3__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.
- tsrkit_types/__init__.py +95 -76
- tsrkit_types/bits.py +39 -20
- tsrkit_types/bool.py +4 -8
- tsrkit_types/bytearray.py +37 -0
- tsrkit_types/bytes.py +22 -52
- tsrkit_types/bytes_common.py +68 -0
- tsrkit_types/choice.py +4 -4
- tsrkit_types/dictionary.py +1 -1
- tsrkit_types/integers.py +17 -0
- tsrkit_types/itf/codable.py +2 -1
- tsrkit_types/option.py +20 -2
- tsrkit_types/sequences.py +3 -3
- tsrkit_types/struct.py +16 -10
- {tsrkit_types-0.1.2.dist-info → tsrkit_types-0.1.3.dist-info}/METADATA +100 -20
- tsrkit_types-0.1.3.dist-info/RECORD +21 -0
- tsrkit_types-0.1.2.dist-info/RECORD +0 -19
- {tsrkit_types-0.1.2.dist-info → tsrkit_types-0.1.3.dist-info}/WHEEL +0 -0
- {tsrkit_types-0.1.2.dist-info → tsrkit_types-0.1.3.dist-info}/licenses/LICENSE +0 -0
- {tsrkit_types-0.1.2.dist-info → tsrkit_types-0.1.3.dist-info}/top_level.txt +0 -0
tsrkit_types/__init__.py
CHANGED
|
@@ -1,76 +1,95 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
#
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
#
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
#
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
#
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
#
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
#
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
#
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
#
|
|
51
|
-
|
|
52
|
-
#
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
#
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
#
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
#
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
#
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
#
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
#
|
|
76
|
-
|
|
1
|
+
"""
|
|
2
|
+
TSRKit Types - Performant Python types for binary serialization and JSON encoding.
|
|
3
|
+
|
|
4
|
+
This module provides a comprehensive set of typed data structures with built-in
|
|
5
|
+
serialization capabilities, including integers, strings, containers, and more.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# Core interfaces
|
|
9
|
+
from .itf.codable import Codable
|
|
10
|
+
|
|
11
|
+
# Integer types
|
|
12
|
+
from .integers import Uint, U8, U16, U32, U64
|
|
13
|
+
|
|
14
|
+
# String types
|
|
15
|
+
from .string import String
|
|
16
|
+
|
|
17
|
+
# Boolean types
|
|
18
|
+
from .bool import Bool
|
|
19
|
+
|
|
20
|
+
# Null types
|
|
21
|
+
from .null import Null, NullType
|
|
22
|
+
|
|
23
|
+
# Choice and Option types
|
|
24
|
+
from .choice import Choice
|
|
25
|
+
from .option import Option
|
|
26
|
+
|
|
27
|
+
# Container types
|
|
28
|
+
from .sequences import (
|
|
29
|
+
Seq, Vector, Array,
|
|
30
|
+
TypedVector, TypedArray,
|
|
31
|
+
BoundedVector, TypedBoundedVector
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# Dictionary types
|
|
35
|
+
from .dictionary import Dictionary
|
|
36
|
+
|
|
37
|
+
# Bytes types
|
|
38
|
+
from .bytes import Bytes, ByteArray16, ByteArray32, ByteArray64, ByteArray128, ByteArray256, ByteArray512, ByteArray1024
|
|
39
|
+
from .bytearray import ByteArray
|
|
40
|
+
|
|
41
|
+
# Bit types
|
|
42
|
+
from .bits import Bits
|
|
43
|
+
|
|
44
|
+
# Enum types
|
|
45
|
+
from .enum import Enum
|
|
46
|
+
|
|
47
|
+
# Structure decorator
|
|
48
|
+
from .struct import structure, struct
|
|
49
|
+
|
|
50
|
+
# Export all public types
|
|
51
|
+
__all__ = [
|
|
52
|
+
# Core interfaces
|
|
53
|
+
"Codable",
|
|
54
|
+
|
|
55
|
+
# Integer types
|
|
56
|
+
"Uint", "U8", "U16", "U32", "U64",
|
|
57
|
+
|
|
58
|
+
# String types
|
|
59
|
+
"String",
|
|
60
|
+
|
|
61
|
+
# Boolean types
|
|
62
|
+
"Bool",
|
|
63
|
+
|
|
64
|
+
# Null types
|
|
65
|
+
"Null", "NullType",
|
|
66
|
+
|
|
67
|
+
# Choice and Option types
|
|
68
|
+
"Choice", "Option",
|
|
69
|
+
|
|
70
|
+
# Container types
|
|
71
|
+
"Seq", "Vector", "Array",
|
|
72
|
+
"TypedVector", "TypedArray",
|
|
73
|
+
"BoundedVector", "TypedBoundedVector",
|
|
74
|
+
|
|
75
|
+
# Dictionary types
|
|
76
|
+
"Dictionary",
|
|
77
|
+
|
|
78
|
+
# Bytes types
|
|
79
|
+
"Bytes", "ByteArray16", "ByteArray32", "ByteArray64", "ByteArray128", "ByteArray256", "ByteArray512", "ByteArray1024",
|
|
80
|
+
"ByteArray",
|
|
81
|
+
|
|
82
|
+
# Bit types
|
|
83
|
+
"Bits",
|
|
84
|
+
|
|
85
|
+
# Enum types
|
|
86
|
+
"Enum",
|
|
87
|
+
|
|
88
|
+
# Structure decorator
|
|
89
|
+
"structure", "struct",
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
# Version information
|
|
93
|
+
__version__ = "1.0.0"
|
|
94
|
+
__author__ = "TSRKit Team"
|
|
95
|
+
__license__ = "MIT"
|
tsrkit_types/bits.py
CHANGED
|
@@ -34,7 +34,13 @@ class Bits(Seq):
|
|
|
34
34
|
|
|
35
35
|
@classmethod
|
|
36
36
|
def from_json(cls, json_str: str) -> "Bits":
|
|
37
|
-
|
|
37
|
+
bits = Bytes.from_json(json_str).to_bits(bit_order=cls._order)
|
|
38
|
+
|
|
39
|
+
# For fixed-length types, trim to exact size
|
|
40
|
+
if cls._min_length == cls._max_length and cls._min_length > 0:
|
|
41
|
+
bits = bits[:cls._min_length]
|
|
42
|
+
|
|
43
|
+
return cls(bits)
|
|
38
44
|
|
|
39
45
|
# ---------------------------------------------------------------------------- #
|
|
40
46
|
# Serialization #
|
|
@@ -43,7 +49,9 @@ class Bits(Seq):
|
|
|
43
49
|
def encode_size(self) -> int:
|
|
44
50
|
# Calculate the number of bytes needed
|
|
45
51
|
bit_enc = 0
|
|
46
|
-
if
|
|
52
|
+
# Check if this is a variable-length type (needs length prefix)
|
|
53
|
+
is_fixed_length = (self._min_length == self._max_length and self._min_length > 0)
|
|
54
|
+
if not is_fixed_length:
|
|
47
55
|
bit_enc = Uint(len(self)).encode_size()
|
|
48
56
|
|
|
49
57
|
return bit_enc + ((len(self) + 7) // 8)
|
|
@@ -54,17 +62,18 @@ class Bits(Seq):
|
|
|
54
62
|
total_size = self.encode_size()
|
|
55
63
|
self._check_buffer_size(buffer, total_size, offset)
|
|
56
64
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
65
|
+
current_offset = offset
|
|
66
|
+
|
|
67
|
+
# Check if this is a variable-length type (needs length prefix)
|
|
68
|
+
is_fixed_length = (self._min_length == self._max_length and self._min_length > 0)
|
|
69
|
+
|
|
70
|
+
if not is_fixed_length:
|
|
62
71
|
# Encode the bit length first
|
|
63
|
-
|
|
72
|
+
current_offset += Uint(len(self)).encode_into(buffer, current_offset)
|
|
64
73
|
else:
|
|
65
|
-
# Ensure bit length
|
|
66
|
-
if len(self) != self.
|
|
67
|
-
raise ValueError("Bit sequence length mismatch")
|
|
74
|
+
# Ensure bit length matches expected size for fixed-length types
|
|
75
|
+
if len(self) != self._min_length:
|
|
76
|
+
raise ValueError(f"Bit sequence length mismatch: expected {self._min_length}, got {len(self)}")
|
|
68
77
|
|
|
69
78
|
if not all(
|
|
70
79
|
isinstance(bit, (bool, int)) and bit in (0, 1, True, False)
|
|
@@ -72,9 +81,9 @@ class Bits(Seq):
|
|
|
72
81
|
):
|
|
73
82
|
raise ValueError(f"Bit sequence must contain only 0s and 1s, got an sequence of {self}")
|
|
74
83
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
)
|
|
84
|
+
# Convert bits to bytes and write to buffer
|
|
85
|
+
bit_bytes = Bytes.from_bits(self, bit_order=self._order)
|
|
86
|
+
buffer[current_offset : current_offset + len(bit_bytes)] = bit_bytes
|
|
78
87
|
|
|
79
88
|
return total_size
|
|
80
89
|
|
|
@@ -98,18 +107,28 @@ class Bits(Seq):
|
|
|
98
107
|
Raises:
|
|
99
108
|
DecodeError: If buffer too small or bit_length not specified
|
|
100
109
|
"""
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
110
|
+
# Check if this is a fixed-length Bits type
|
|
111
|
+
is_fixed_length = (cls._min_length == cls._max_length and cls._min_length > 0)
|
|
112
|
+
|
|
113
|
+
original_offset = offset
|
|
114
|
+
|
|
115
|
+
if is_fixed_length:
|
|
116
|
+
_len = cls._min_length
|
|
117
|
+
else:
|
|
118
|
+
# Variable length - decode length from buffer
|
|
104
119
|
_len, size = Uint.decode_from(buffer, offset)
|
|
105
120
|
offset += size
|
|
106
121
|
|
|
107
122
|
if _len == 0:
|
|
108
|
-
return [],
|
|
123
|
+
return cls([]), offset - original_offset
|
|
109
124
|
|
|
110
125
|
# Calculate required bytes
|
|
111
126
|
byte_count = (_len + 7) // 8
|
|
112
127
|
cls._check_buffer_size(buffer, byte_count, offset)
|
|
113
128
|
|
|
114
|
-
|
|
115
|
-
|
|
129
|
+
result_bits = Bytes(buffer[offset : offset + byte_count]).to_bits(bit_order=cls._order)
|
|
130
|
+
# Trim to exact bit length
|
|
131
|
+
result_bits = result_bits[:_len]
|
|
132
|
+
|
|
133
|
+
total_bytes_read = offset + byte_count - original_offset
|
|
134
|
+
return cls(result_bits), total_bytes_read
|
tsrkit_types/bool.py
CHANGED
|
@@ -29,13 +29,9 @@ class Bool(Codable):
|
|
|
29
29
|
# JSON Parse #
|
|
30
30
|
# ---------------------------------------------------------------------------- #
|
|
31
31
|
|
|
32
|
-
def to_json(self) ->
|
|
33
|
-
return
|
|
32
|
+
def to_json(self) -> bool:
|
|
33
|
+
return bool(self)
|
|
34
34
|
|
|
35
35
|
@classmethod
|
|
36
|
-
def from_json(cls,
|
|
37
|
-
|
|
38
|
-
return cls(True)
|
|
39
|
-
if json_str == "false":
|
|
40
|
-
return cls(False)
|
|
41
|
-
raise ValueError("Invalid JSON string for Bool")
|
|
36
|
+
def from_json(cls, data: bool) -> "Bool":
|
|
37
|
+
return cls(data)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from typing import Tuple, Union
|
|
2
|
+
from tsrkit_types.integers import Uint
|
|
3
|
+
from tsrkit_types.itf.codable import Codable
|
|
4
|
+
from tsrkit_types.bytes_common import BytesMixin
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ByteArray(bytearray, Codable, BytesMixin):
|
|
8
|
+
"""Variable Size ByteArray"""
|
|
9
|
+
|
|
10
|
+
# Bit conversion and JSON methods inherited from BytesMixin
|
|
11
|
+
|
|
12
|
+
# ---------------------------------------------------------------------------- #
|
|
13
|
+
# Serialization #
|
|
14
|
+
# ---------------------------------------------------------------------------- #
|
|
15
|
+
def encode_size(self) -> int:
|
|
16
|
+
return Uint(len(self)).encode_size() + len(self)
|
|
17
|
+
|
|
18
|
+
def encode_into(self, buf: bytearray, offset: int = 0) -> int:
|
|
19
|
+
current_offset = offset
|
|
20
|
+
_len = len(self)
|
|
21
|
+
current_offset += Uint(_len).encode_into(buf, current_offset)
|
|
22
|
+
buf[current_offset:current_offset+_len] = self
|
|
23
|
+
current_offset += _len
|
|
24
|
+
return current_offset - offset
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def decode_from(cls, buffer: Union[bytes, bytearray, memoryview], offset: int = 0) -> Tuple["ByteArray", int]:
|
|
28
|
+
current_offset = offset
|
|
29
|
+
_len, _inc_offset = Uint.decode_from(buffer, offset)
|
|
30
|
+
current_offset += _inc_offset
|
|
31
|
+
return cls(buffer[current_offset:current_offset+_len]), current_offset + _len - offset
|
|
32
|
+
|
|
33
|
+
# ---------------------------------------------------------------------------- #
|
|
34
|
+
# JSON Serialization #
|
|
35
|
+
# ---------------------------------------------------------------------------- #
|
|
36
|
+
# JSON methods inherited from BytesMixin
|
|
37
|
+
|
tsrkit_types/bytes.py
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
|
+
import abc
|
|
1
2
|
from typing import Tuple, Union, ClassVar
|
|
2
3
|
from tsrkit_types.integers import Uint
|
|
3
4
|
from tsrkit_types.itf.codable import Codable
|
|
5
|
+
from tsrkit_types.bytes_common import BytesMixin
|
|
4
6
|
|
|
5
|
-
class
|
|
7
|
+
class BytesCheckMeta(abc.ABCMeta):
|
|
8
|
+
"""Meta class to check if the instance is a bytes with the same key and value types"""
|
|
9
|
+
def __instancecheck__(cls, instance):
|
|
10
|
+
# TODO - This needs more false positive testing
|
|
11
|
+
_matches_length = str(getattr(cls, "_length", None)) == str(getattr(instance, "_length", None))
|
|
12
|
+
return isinstance(instance, bytes) and _matches_length
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Bytes(bytes, Codable, BytesMixin, metaclass=BytesCheckMeta):
|
|
16
|
+
"""Fixed Size Bytes"""
|
|
6
17
|
|
|
7
18
|
_length: ClassVar[Union[None, int]] = None
|
|
8
19
|
|
|
@@ -16,47 +27,7 @@ class Bytes(bytes, Codable):
|
|
|
16
27
|
"_length": _len,
|
|
17
28
|
})
|
|
18
29
|
|
|
19
|
-
|
|
20
|
-
return f"{self.__class__.__name__}({self.hex()})"
|
|
21
|
-
|
|
22
|
-
@classmethod
|
|
23
|
-
def from_bits(cls, bits: list[bool], bit_order = "msb") -> "Bytes":
|
|
24
|
-
# Sanitize input: make sure bits are 0 or 1
|
|
25
|
-
bits = [int(bool(b)) for b in bits]
|
|
26
|
-
n = len(bits)
|
|
27
|
-
# Pad with zeros to multiple of 8
|
|
28
|
-
pad = (8 - n % 8) % 8
|
|
29
|
-
bits += [0] * pad
|
|
30
|
-
|
|
31
|
-
byte_arr = []
|
|
32
|
-
for i in range(0, len(bits), 8):
|
|
33
|
-
byte_bits = bits[i:i + 8]
|
|
34
|
-
if bit_order == "msb":
|
|
35
|
-
# Most significant bit first
|
|
36
|
-
val = 0
|
|
37
|
-
for bit in byte_bits:
|
|
38
|
-
val = (val << 1) | bit
|
|
39
|
-
elif bit_order == "lsb":
|
|
40
|
-
# Least significant bit first
|
|
41
|
-
val = 0
|
|
42
|
-
for bit in reversed(byte_bits):
|
|
43
|
-
val = (val << 1) | bit
|
|
44
|
-
else:
|
|
45
|
-
raise ValueError(f"Unknown bit_order: {bit_order}")
|
|
46
|
-
# noinspection PyUnreachableCode
|
|
47
|
-
byte_arr.append(val)
|
|
48
|
-
return cls(bytes(byte_arr))
|
|
49
|
-
|
|
50
|
-
def to_bits(self, bit_order="msb") -> list[bool]:
|
|
51
|
-
bits = []
|
|
52
|
-
for byte in self:
|
|
53
|
-
if bit_order == "msb":
|
|
54
|
-
bits.extend([(byte >> i) & 1 for i in reversed(range(8))])
|
|
55
|
-
elif bit_order == "lsb":
|
|
56
|
-
bits.extend([(byte >> i) & 1 for i in range(8)])
|
|
57
|
-
else:
|
|
58
|
-
raise ValueError(f"Unknown bit_order: {bit_order}")
|
|
59
|
-
return bits
|
|
30
|
+
# Bit conversion methods inherited from BytesMixin
|
|
60
31
|
|
|
61
32
|
# ---------------------------------------------------------------------------- #
|
|
62
33
|
# Serialization #
|
|
@@ -88,13 +59,12 @@ class Bytes(bytes, Codable):
|
|
|
88
59
|
# ---------------------------------------------------------------------------- #
|
|
89
60
|
# JSON Serialization #
|
|
90
61
|
# ---------------------------------------------------------------------------- #
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
62
|
+
# JSON methods inherited from BytesMixin
|
|
63
|
+
|
|
64
|
+
ByteArray16 = Bytes[16]
|
|
65
|
+
ByteArray32 = Bytes[32]
|
|
66
|
+
ByteArray64 = Bytes[64]
|
|
67
|
+
ByteArray128 = Bytes[128]
|
|
68
|
+
ByteArray256 = Bytes[256]
|
|
69
|
+
ByteArray512 = Bytes[512]
|
|
70
|
+
ByteArray1024 = Bytes[1024]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Common functionality for Bytes and ByteArray types.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Union
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BytesMixin:
|
|
9
|
+
"""Mixin providing common functionality for bytes-like types."""
|
|
10
|
+
|
|
11
|
+
@classmethod
|
|
12
|
+
def from_bits(cls, bits: list[bool], bit_order: str = "msb"):
|
|
13
|
+
"""Convert a list of bits to bytes with specified bit order."""
|
|
14
|
+
# Sanitize input: make sure bits are 0 or 1
|
|
15
|
+
bits = [int(bool(b)) for b in bits]
|
|
16
|
+
n = len(bits)
|
|
17
|
+
# Pad with zeros to multiple of 8
|
|
18
|
+
pad = (8 - n % 8) % 8
|
|
19
|
+
bits += [0] * pad
|
|
20
|
+
|
|
21
|
+
byte_arr = []
|
|
22
|
+
for i in range(0, len(bits), 8):
|
|
23
|
+
byte_bits = bits[i:i + 8]
|
|
24
|
+
if bit_order == "msb":
|
|
25
|
+
# Most significant bit first
|
|
26
|
+
val = 0
|
|
27
|
+
for bit in byte_bits:
|
|
28
|
+
val = (val << 1) | bit
|
|
29
|
+
elif bit_order == "lsb":
|
|
30
|
+
# Least significant bit first
|
|
31
|
+
val = 0
|
|
32
|
+
for bit in reversed(byte_bits):
|
|
33
|
+
val = (val << 1) | bit
|
|
34
|
+
else:
|
|
35
|
+
raise ValueError(f"Unknown bit_order: {bit_order}")
|
|
36
|
+
byte_arr.append(val)
|
|
37
|
+
return cls(bytes(byte_arr))
|
|
38
|
+
|
|
39
|
+
def to_bits(self, bit_order: str = "msb") -> list[bool]:
|
|
40
|
+
"""Convert bytes to a list of bits with specified bit order."""
|
|
41
|
+
bits = []
|
|
42
|
+
for byte in self:
|
|
43
|
+
if bit_order == "msb":
|
|
44
|
+
bits.extend([bool((byte >> i) & 1) for i in reversed(range(8))])
|
|
45
|
+
elif bit_order == "lsb":
|
|
46
|
+
bits.extend([bool((byte >> i) & 1) for i in range(8)])
|
|
47
|
+
else:
|
|
48
|
+
raise ValueError(f"Unknown bit_order: {bit_order}")
|
|
49
|
+
return bits
|
|
50
|
+
|
|
51
|
+
def to_json(self):
|
|
52
|
+
"""Convert bytes to hex string for JSON serialization."""
|
|
53
|
+
return self.hex()
|
|
54
|
+
|
|
55
|
+
@classmethod
|
|
56
|
+
def from_json(cls, data: str):
|
|
57
|
+
"""Create instance from hex string."""
|
|
58
|
+
data = data.replace("0x", "")
|
|
59
|
+
return cls(bytes.fromhex(data))
|
|
60
|
+
|
|
61
|
+
def __str__(self):
|
|
62
|
+
return f"{self.__class__.__name__}({self.hex()})"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def validate_bit_order(bit_order: str) -> None:
|
|
66
|
+
"""Validate bit order parameter."""
|
|
67
|
+
if bit_order not in ("msb", "lsb"):
|
|
68
|
+
raise ValueError(f"Unknown bit_order: {bit_order}. Must be 'msb' or 'lsb'")
|
tsrkit_types/choice.py
CHANGED
|
@@ -112,13 +112,13 @@ class Choice(Codable):
|
|
|
112
112
|
|
|
113
113
|
def encode_into(self, buf: bytearray, offset: int = 0) -> int:
|
|
114
114
|
current_offset = offset
|
|
115
|
-
# Find the
|
|
116
|
-
for i,
|
|
117
|
-
if isinstance(self._value,
|
|
115
|
+
# Find the index of the (key, type) pair that matches our current choice
|
|
116
|
+
for i, (key, choice_type) in enumerate(self._opt_types):
|
|
117
|
+
if self._choice_key == key and isinstance(self._value, choice_type):
|
|
118
118
|
current_offset += Uint(i).encode_into(buf, current_offset)
|
|
119
119
|
break
|
|
120
120
|
else:
|
|
121
|
-
raise ValueError(f"Value {self._value} is not a valid choice")
|
|
121
|
+
raise ValueError(f"Value {self._value} with key {self._choice_key} is not a valid choice")
|
|
122
122
|
current_offset += self._value.encode_into(buf, current_offset)
|
|
123
123
|
return current_offset - offset
|
|
124
124
|
|
tsrkit_types/dictionary.py
CHANGED
|
@@ -102,7 +102,7 @@ class Dictionary(dict, Codable, Generic[K, V], metaclass=DictCheckMeta):
|
|
|
102
102
|
if not isinstance(data, dict):
|
|
103
103
|
_value = cls({})
|
|
104
104
|
for val in data:
|
|
105
|
-
_value[cls.
|
|
105
|
+
_value[cls._key_type.from_json(val[cls._key_name])] = cls._value_type.from_json(val[cls._value_name])
|
|
106
106
|
return _value
|
|
107
107
|
else:
|
|
108
108
|
return cls(
|
tsrkit_types/integers.py
CHANGED
|
@@ -195,6 +195,23 @@ class Uint(int, Codable, metaclass=IntCheckMeta):
|
|
|
195
195
|
beta = int.from_bytes(buffer[offset + 1 : offset + 1 + _l], "little")
|
|
196
196
|
value = alpha * 2 ** (_l * 8) + beta
|
|
197
197
|
return cls(value), _l + 1
|
|
198
|
+
|
|
199
|
+
def to_bits(self, bit_order: str = "msb") -> list[bool]:
|
|
200
|
+
"""Convert an int to bits"""
|
|
201
|
+
if bit_order == "msb":
|
|
202
|
+
return [bool((self >> i) & 1) for i in reversed(range(self.byte_size * 8 if self.byte_size > 0 else 64))]
|
|
203
|
+
elif bit_order == "lsb":
|
|
204
|
+
return [bool((self >> i) & 1) for i in range(self.byte_size * 8 if self.byte_size > 0 else 64)]
|
|
205
|
+
else:
|
|
206
|
+
raise ValueError(f"Invalid bit order: {bit_order}")
|
|
207
|
+
|
|
208
|
+
@classmethod
|
|
209
|
+
def from_bits(cls, bits: list[bool], bit_order: str = "msb") -> "Uint":
|
|
210
|
+
"""Convert bits to an int"""
|
|
211
|
+
if bit_order == "msb":
|
|
212
|
+
return cls(int("".join(str(int(b)) for b in bits), 2))
|
|
213
|
+
elif bit_order == "lsb":
|
|
214
|
+
return cls(int("".join(str(int(b)) for b in reversed(bits)), 2))
|
|
198
215
|
|
|
199
216
|
|
|
200
217
|
U8 = Uint[8]
|
tsrkit_types/itf/codable.py
CHANGED
|
@@ -69,7 +69,8 @@ class Codable(ABC, Generic[T]):
|
|
|
69
69
|
value, bytes_read = cls.decode_from(buffer, offset)
|
|
70
70
|
return value
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
@classmethod
|
|
73
|
+
def _check_buffer_size(cls, buffer: bytearray, size: int, offset: int) -> None:
|
|
73
74
|
"""
|
|
74
75
|
Check if the buffer has enough space to encode the value.
|
|
75
76
|
|
tsrkit_types/option.py
CHANGED
|
@@ -16,7 +16,7 @@ class Option(Choice, Generic[T]):
|
|
|
16
16
|
name = f"Option[{opt_t.__class__.__name__}]"
|
|
17
17
|
return type(name,
|
|
18
18
|
(Option,),
|
|
19
|
-
{"_opt_types": ((None,
|
|
19
|
+
{"_opt_types": ((None, NullType), (None, opt_t))})
|
|
20
20
|
|
|
21
21
|
def __init__(self, val: T|NullType = Null):
|
|
22
22
|
super().__init__(val)
|
|
@@ -27,4 +27,22 @@ class Option(Choice, Generic[T]):
|
|
|
27
27
|
super().set(value, key)
|
|
28
28
|
|
|
29
29
|
def __bool__(self):
|
|
30
|
-
return self._value != Null
|
|
30
|
+
return self._value != Null
|
|
31
|
+
|
|
32
|
+
# ---------------------------------------------------------------------------- #
|
|
33
|
+
# JSON Serde #
|
|
34
|
+
# ---------------------------------------------------------------------------- #
|
|
35
|
+
|
|
36
|
+
def to_json(self):
|
|
37
|
+
"""Convert Option to JSON. Returns None for empty Options."""
|
|
38
|
+
if self._value == Null:
|
|
39
|
+
return None
|
|
40
|
+
return self._value.to_json()
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def from_json(cls, data):
|
|
44
|
+
"""Create Option from JSON data. None creates empty Option."""
|
|
45
|
+
if data is None:
|
|
46
|
+
return cls() # Empty Option
|
|
47
|
+
# Try to create the wrapped type from the data
|
|
48
|
+
return cls(cls._opt_types[1][1].from_json(data))
|
tsrkit_types/sequences.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import abc
|
|
2
|
-
from typing import TypeVar, Type, ClassVar, Tuple, Generic
|
|
2
|
+
from typing import TypeVar, Type, ClassVar, Tuple, Generic, Optional
|
|
3
3
|
from tsrkit_types.integers import Uint
|
|
4
4
|
from tsrkit_types.itf.codable import Codable
|
|
5
5
|
|
|
@@ -118,7 +118,7 @@ class Seq(list, Codable, Generic[T], metaclass=SeqCheckMeta):
|
|
|
118
118
|
return f"{self.__class__.__name__}({list(self)})"
|
|
119
119
|
|
|
120
120
|
@property
|
|
121
|
-
def _length(self):
|
|
121
|
+
def _length(self) -> Optional[int]:
|
|
122
122
|
if self._min_length == self._max_length:
|
|
123
123
|
return self._min_length
|
|
124
124
|
return None
|
|
@@ -143,7 +143,7 @@ class Seq(list, Codable, Generic[T], metaclass=SeqCheckMeta):
|
|
|
143
143
|
def encode_into(self, buffer: bytearray, offset: int = 0) -> int:
|
|
144
144
|
current_offset = offset
|
|
145
145
|
# If length is not defined
|
|
146
|
-
if(self._min_length !=
|
|
146
|
+
if(self._min_length != self._max_length):
|
|
147
147
|
current_offset += Uint(len(self)).encode_into(buffer, current_offset)
|
|
148
148
|
|
|
149
149
|
for item in self:
|
tsrkit_types/struct.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from dataclasses import dataclass, fields
|
|
2
2
|
from typing import Any, Tuple, Union
|
|
3
3
|
from tsrkit_types.itf.codable import Codable
|
|
4
|
+
from tsrkit_types.null import NullType
|
|
5
|
+
from tsrkit_types.option import Option
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
def structure(_cls=None, *, frozen=False, **kwargs):
|
|
@@ -58,22 +60,26 @@ def structure(_cls=None, *, frozen=False, **kwargs):
|
|
|
58
60
|
for field in fields(cls):
|
|
59
61
|
k = field.metadata.get("name", field.name)
|
|
60
62
|
v = data.get(k)
|
|
61
|
-
if v is None:
|
|
62
|
-
|
|
63
|
-
init_data[field.name] = field.metadata.get("default")
|
|
64
|
-
else:
|
|
65
|
-
raise ValueError(f"Field {k} not found in {cls}")
|
|
63
|
+
if v is None and field.metadata.get("default") is not None:
|
|
64
|
+
init_data[field.name] = field.metadata.get("default")
|
|
66
65
|
else:
|
|
67
66
|
init_data[field.name] = field.type.from_json(v)
|
|
68
67
|
return cls(**init_data)
|
|
69
68
|
|
|
70
69
|
|
|
71
70
|
new_cls.__init__ = __init__
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
new_cls.
|
|
75
|
-
|
|
76
|
-
new_cls.
|
|
71
|
+
|
|
72
|
+
# Only overwrite if the method is not already defined
|
|
73
|
+
if not new_cls.__dict__.get("encode_size"):
|
|
74
|
+
new_cls.encode_size = encode_size
|
|
75
|
+
if not new_cls.__dict__.get("decode_from"):
|
|
76
|
+
new_cls.decode_from = decode_from
|
|
77
|
+
if not new_cls.__dict__.get("encode_into"):
|
|
78
|
+
new_cls.encode_into = encode_into
|
|
79
|
+
if not new_cls.__dict__.get("to_json"):
|
|
80
|
+
new_cls.to_json = to_json
|
|
81
|
+
if not new_cls.__dict__.get("from_json"):
|
|
82
|
+
new_cls.from_json = from_json
|
|
77
83
|
|
|
78
84
|
new_cls = type(new_cls.__name__, (Codable, new_cls), dict(new_cls.__dict__))
|
|
79
85
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tsrkit-types
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Performant Python Typings library for type-safe binary serialization, JSON encoding, and data validation with zero dependencies
|
|
5
5
|
Author-email: chainscore-labs <hello@chainscore.finance>, prasad-kumkar <prasad@chainscore.finance>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -299,7 +299,9 @@ restored = StringToInt.from_json(json_data)
|
|
|
299
299
|
|
|
300
300
|
### Bytes Types
|
|
301
301
|
|
|
302
|
-
|
|
302
|
+
The library provides two complementary byte array types: immutable `Bytes` (extending Python's built-in `bytes`) and mutable `ByteArray` (extending Python's `bytearray`). Both types share common functionality through a mixin architecture for bit conversion, JSON serialization, and binary encoding.
|
|
303
|
+
|
|
304
|
+
#### Bytes (Immutable - extension of Python bytes)
|
|
303
305
|
|
|
304
306
|
```python
|
|
305
307
|
from tsrkit_types.bytes import Bytes
|
|
@@ -307,47 +309,115 @@ from tsrkit_types.bytes import Bytes
|
|
|
307
309
|
# Creation
|
|
308
310
|
data = Bytes(b"Hello, binary world!")
|
|
309
311
|
data = Bytes([0x01, 0x02, 0x03, 0x04])
|
|
312
|
+
data = Bytes("48656c6c6f") # From hex string
|
|
310
313
|
|
|
311
|
-
#
|
|
312
|
-
data.to_bits()
|
|
313
|
-
Bytes.from_bits(
|
|
314
|
+
# Shared Operations (via BytesMixin)
|
|
315
|
+
bits = data.to_bits() # Convert to bit list [True, False, True, ...]
|
|
316
|
+
data2 = Bytes.from_bits(bits) # Create from bit list
|
|
314
317
|
|
|
315
|
-
#
|
|
318
|
+
# Properties
|
|
316
319
|
length = len(data) # Byte length
|
|
317
320
|
raw_bytes = bytes(data) # Convert to Python bytes
|
|
318
321
|
|
|
319
|
-
# Encoding
|
|
322
|
+
# Encoding/Decoding
|
|
320
323
|
encoded = data.encode() # [length][raw_bytes]
|
|
321
324
|
decoded = Bytes.decode(encoded)
|
|
322
325
|
|
|
323
326
|
# JSON serialization (hex encoded)
|
|
324
327
|
json_str = data.to_json() # "48656c6c6f2c2062696e61727920776f726c6421"
|
|
325
328
|
restored = Bytes.from_json(json_str)
|
|
329
|
+
restored2 = Bytes.from_json("0x48656c6c6f") # Supports 0x prefix
|
|
326
330
|
```
|
|
327
331
|
|
|
328
|
-
####
|
|
332
|
+
#### ByteArray (Mutable - extension of Python bytearray)
|
|
329
333
|
|
|
330
334
|
```python
|
|
331
|
-
from tsrkit_types.
|
|
335
|
+
from tsrkit_types.bytearray import ByteArray
|
|
332
336
|
|
|
333
337
|
# Creation
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
338
|
+
data = ByteArray(b"Hello, binary world!")
|
|
339
|
+
data = ByteArray([0x01, 0x02, 0x03, 0x04])
|
|
340
|
+
data = ByteArray("48656c6c6f") # From hex string
|
|
341
|
+
|
|
342
|
+
# Mutable Operations
|
|
343
|
+
data.append(0xFF) # Add single byte
|
|
344
|
+
data.extend([0xAB, 0xCD]) # Add multiple bytes
|
|
345
|
+
data.insert(0, 0x00) # Insert byte at position
|
|
346
|
+
data.pop() # Remove and return last byte
|
|
347
|
+
data.remove(0xFF) # Remove first occurrence
|
|
348
|
+
data.clear() # Remove all bytes
|
|
349
|
+
data.reverse() # Reverse in-place
|
|
350
|
+
|
|
351
|
+
# Indexing and Slicing (mutable)
|
|
352
|
+
data[0] = 0x42 # Set byte at index
|
|
353
|
+
data[1:3] = [0x43, 0x44] # Set slice
|
|
354
|
+
del data[0] # Delete byte at index
|
|
355
|
+
|
|
356
|
+
# Shared Operations (via BytesMixin) - same as Bytes
|
|
357
|
+
bits = data.to_bits() # Convert to bit list
|
|
358
|
+
data2 = ByteArray.from_bits(bits) # Create from bit list
|
|
359
|
+
|
|
360
|
+
# Properties and Conversion
|
|
361
|
+
length = len(data) # Byte length
|
|
362
|
+
raw_bytes = bytes(data) # Convert to immutable bytes
|
|
363
|
+
immutable = Bytes(data) # Convert to immutable Bytes
|
|
364
|
+
|
|
365
|
+
# Encoding/Decoding (same interface as Bytes)
|
|
366
|
+
encoded = data.encode() # [length][raw_bytes]
|
|
367
|
+
decoded = ByteArray.decode(encoded)
|
|
368
|
+
|
|
369
|
+
# JSON serialization (same interface as Bytes)
|
|
370
|
+
json_str = data.to_json() # "48656c6c6f..."
|
|
371
|
+
restored = ByteArray.from_json(json_str)
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**Key Differences:**
|
|
375
|
+
- **Bytes**: Immutable, extends `bytes`, memory-efficient for read-only data
|
|
376
|
+
- **ByteArray**: Mutable, extends `bytearray`, suitable for dynamic byte manipulation
|
|
377
|
+
- **Shared Functionality**: Both support identical bit conversion, JSON serialization, and binary encoding through `BytesMixin`
|
|
378
|
+
|
|
379
|
+
**Common Features (Both Types):**
|
|
380
|
+
- Bit-level conversion with MSB/LSB support
|
|
381
|
+
- Hex string JSON serialization with 0x prefix support
|
|
382
|
+
- Efficient binary encoding with length prefix
|
|
383
|
+
- String representation and validation
|
|
384
|
+
- Memory-efficient operations
|
|
385
|
+
|
|
386
|
+
#### Bits (Bit Arrays - Sequence of bool)
|
|
387
|
+
|
|
388
|
+
```python
|
|
389
|
+
from tsrkit_types.bits import Bits
|
|
390
|
+
|
|
391
|
+
# Creation
|
|
392
|
+
bits = Bits([True, False, True, True, False])
|
|
393
|
+
bits = Bits.from_hex("1A3F") # From hex string
|
|
394
|
+
bits = Bits.from_int(42, 8) # From integer with bit width
|
|
395
|
+
|
|
396
|
+
# Fixed-size parameterized bits
|
|
397
|
+
FixedBits = Bits[8] # Exactly 8 bits
|
|
398
|
+
fixed = FixedBits([True, False, True, True, False, False, True, False])
|
|
337
399
|
|
|
338
400
|
# Operations
|
|
339
|
-
bit_val = bits[0]
|
|
340
|
-
bits[1] = True
|
|
341
|
-
bits.append(False)
|
|
342
|
-
bits.extend([True, False])
|
|
401
|
+
bit_val = bits[0] # Get bit at index
|
|
402
|
+
bits[1] = True # Set bit at index
|
|
403
|
+
bits.append(False) # Add bit
|
|
404
|
+
bits.extend([True, False]) # Add multiple bits
|
|
343
405
|
|
|
344
406
|
# Conversion
|
|
345
|
-
hex_str = bits.to_hex()
|
|
346
|
-
int_val = bits.to_int()
|
|
407
|
+
hex_str = bits.to_hex() # Convert to hex string
|
|
408
|
+
int_val = bits.to_int() # Convert to integer
|
|
409
|
+
|
|
410
|
+
# Bit order specification
|
|
411
|
+
bits_msb = Bits([True, False], bit_order="MSB") # Most significant bit first
|
|
412
|
+
bits_lsb = Bits([True, False], bit_order="LSB") # Least significant bit first
|
|
347
413
|
|
|
348
414
|
# Encoding
|
|
349
|
-
encoded = bits.encode()
|
|
350
|
-
decoded =
|
|
415
|
+
encoded = bits.encode() # [length][packed_bits]
|
|
416
|
+
decoded = Bits.decode(encoded)
|
|
417
|
+
|
|
418
|
+
# JSON serialization
|
|
419
|
+
json_str = bits.to_json() # Hex string representation
|
|
420
|
+
restored = Bits.from_json(json_str)
|
|
351
421
|
```
|
|
352
422
|
|
|
353
423
|
### Enum (Extension of Python Enum, with Codable + JSON support)
|
|
@@ -558,6 +628,16 @@ buffer = bytearray(1024)
|
|
|
558
628
|
offset = 0
|
|
559
629
|
offset += value1.encode_into(buffer, offset)
|
|
560
630
|
offset += value2.encode_into(buffer, offset)
|
|
631
|
+
|
|
632
|
+
# Choose appropriate byte type for your use case
|
|
633
|
+
# Use Bytes for immutable binary data (memory efficient, read-only)
|
|
634
|
+
config_data = Bytes(b"static configuration")
|
|
635
|
+
|
|
636
|
+
# Use ByteArray for dynamic binary buffers (mutable, growing data)
|
|
637
|
+
dynamic_buffer = ByteArray()
|
|
638
|
+
dynamic_buffer.extend([0x01, 0x02])
|
|
639
|
+
dynamic_buffer.append(0x03)
|
|
640
|
+
dynamic_buffer.insert(0, 0x00) # Result: [0x00, 0x01, 0x02, 0x03]
|
|
561
641
|
```
|
|
562
642
|
|
|
563
643
|
## Examples
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
tsrkit_types/__init__.py,sha256=dPiakZ3q_YZLcj3nW5CLjI8CA9rE8umqtv2camWl3Cs,1956
|
|
2
|
+
tsrkit_types/bits.py,sha256=33WLfuUYdzGscoc-E3InTYdbJRIDeixoe_pG0XAv71c,4213
|
|
3
|
+
tsrkit_types/bool.py,sha256=Veu6KLIeiRFnIW1sbawJ0haF0veyaL-As5mBiypq-uE,1280
|
|
4
|
+
tsrkit_types/bytearray.py,sha256=DaMnACq-7pzEW-pRO2f_IAny_8ldhSt3G5D24Soywk4,1662
|
|
5
|
+
tsrkit_types/bytes.py,sha256=ayuD8AUTbZ4LFnceG8TBzAGAYXGht0pYQcmX-7ZtwyI,2762
|
|
6
|
+
tsrkit_types/bytes_common.py,sha256=b1Zqh_NhkCX718QaZC52J3nEzKAi1Fe8E0nefWVwwmo,2301
|
|
7
|
+
tsrkit_types/choice.py,sha256=zNLvB1jSZERot6Qo9cxxkPcY84DAJss8o0ULyp9D--4,5196
|
|
8
|
+
tsrkit_types/dictionary.py,sha256=GcUvaHC1VOEc3OzUVAH0id--ncLqTJ6ZRz-lucMNRdY,5618
|
|
9
|
+
tsrkit_types/enum.py,sha256=3MyLW15_ToQQdctJjcMY8Xb3OsS_Ad997OOEo8FjVeA,4256
|
|
10
|
+
tsrkit_types/integers.py,sha256=w8WCbzzQP0YX3ky4iP-fbNeOBHsIydsU0Tady8iGQPQ,8026
|
|
11
|
+
tsrkit_types/null.py,sha256=OwHVhWLdazaFLXXR8iHPaHe67NPmYHDCavBxUfcZ53s,1318
|
|
12
|
+
tsrkit_types/option.py,sha256=xwtaAFN20GjaGqzYZAAo1fZqqUZnCYHdy2bjshhY620,1631
|
|
13
|
+
tsrkit_types/sequences.py,sha256=KOT5-4mia5Lc0CMjIF7Yqe34Sei92ZQ2s6GaP13soUg,8090
|
|
14
|
+
tsrkit_types/string.py,sha256=8rvg0BwvyhQnbMW3qornmBFTQHeTQFUfwD7OC0eVgcY,2575
|
|
15
|
+
tsrkit_types/struct.py,sha256=GoXWFc1OqO9CXnxFS7Xkms7J-rtZe8h32LkAIBlzdSM,3497
|
|
16
|
+
tsrkit_types/itf/codable.py,sha256=agx8YSVWGBeEiLrU9eqh3ZoeTgpJsmmIlW622xIKqPI,2810
|
|
17
|
+
tsrkit_types-0.1.3.dist-info/licenses/LICENSE,sha256=TwnDvVCPwHadHWLUuY1sPx03XNw1jzh_ZmoDBNai9Uc,1072
|
|
18
|
+
tsrkit_types-0.1.3.dist-info/METADATA,sha256=W_kNQJPjZnMV4wh3tqG7ggWcec8tL1d6gLWx2K4jvVM,22755
|
|
19
|
+
tsrkit_types-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
20
|
+
tsrkit_types-0.1.3.dist-info/top_level.txt,sha256=pnVhnUsnZ_A0FIj1zHwDw3suMGrfMJwusp-4GPVY1CM,13
|
|
21
|
+
tsrkit_types-0.1.3.dist-info/RECORD,,
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
tsrkit_types/__init__.py,sha256=Vw03Fv9RnfmZGqzBpFhuglyewh4MxKR8T5bdWdal1VU,1870
|
|
2
|
-
tsrkit_types/bits.py,sha256=ggx2lDRWtBBIYQBtKEx-XirwYTJdajctCEpd3VmuXrc,3275
|
|
3
|
-
tsrkit_types/bool.py,sha256=anu5RquxV8xdDMj7aIwOOCP3WnK6vMNst4WUPlfeKm4,1460
|
|
4
|
-
tsrkit_types/bytes.py,sha256=rw0sjw1fO9bOElftWehs8oLCZFMXWeajjCyOH-5kChU,3756
|
|
5
|
-
tsrkit_types/choice.py,sha256=L4Pb0ZBvaoCW2h9VBLclmmgIJvfO0Yeb2khPniFN2Xo,5113
|
|
6
|
-
tsrkit_types/dictionary.py,sha256=EktyMKH27HVoR1xNhrkV8fW6KfcxpbHiiYPYoCrFdoI,5614
|
|
7
|
-
tsrkit_types/enum.py,sha256=3MyLW15_ToQQdctJjcMY8Xb3OsS_Ad997OOEo8FjVeA,4256
|
|
8
|
-
tsrkit_types/integers.py,sha256=GT9xVZYBNMcPpShJIlSazwiZYGhoBowhR0MA_cGO5Q0,7200
|
|
9
|
-
tsrkit_types/null.py,sha256=OwHVhWLdazaFLXXR8iHPaHe67NPmYHDCavBxUfcZ53s,1318
|
|
10
|
-
tsrkit_types/option.py,sha256=V4J8SmhUDjINqMM6Ml3ho0YwTy2UT-avrjoYh32Swyg,879
|
|
11
|
-
tsrkit_types/sequences.py,sha256=6aseAdoAkD3RG20ag6CTzVZPR_YlJfLHo82JrNZY3dE,8092
|
|
12
|
-
tsrkit_types/string.py,sha256=8rvg0BwvyhQnbMW3qornmBFTQHeTQFUfwD7OC0eVgcY,2575
|
|
13
|
-
tsrkit_types/struct.py,sha256=ni8jwZlfT_wehardfImBJ0AsvnO-oCW-3APplLXsqGY,3206
|
|
14
|
-
tsrkit_types/itf/codable.py,sha256=jWfoYZ31MZ6k3nlHb2IwJdjD3G0pVPyZWlF0Sv9MAWs,2794
|
|
15
|
-
tsrkit_types-0.1.2.dist-info/licenses/LICENSE,sha256=TwnDvVCPwHadHWLUuY1sPx03XNw1jzh_ZmoDBNai9Uc,1072
|
|
16
|
-
tsrkit_types-0.1.2.dist-info/METADATA,sha256=Yt9wxA4VDq7jhjzPGrrpcQ4rhjgMUQN3hoTl9rjT3ec,19353
|
|
17
|
-
tsrkit_types-0.1.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
18
|
-
tsrkit_types-0.1.2.dist-info/top_level.txt,sha256=pnVhnUsnZ_A0FIj1zHwDw3suMGrfMJwusp-4GPVY1CM,13
|
|
19
|
-
tsrkit_types-0.1.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|