ltcodecs 0.2.0__tar.gz → 1.0.0__tar.gz
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.
- {ltcodecs-0.2.0 → ltcodecs-1.0.0}/PKG-INFO +18 -18
- {ltcodecs-0.2.0 → ltcodecs-1.0.0}/setup.cfg +30 -30
- ltcodecs-1.0.0/src/ltcodecs/__init__.py +67 -0
- ltcodecs-1.0.0/src/ltcodecs/bool_codec.py +47 -0
- ltcodecs-1.0.0/src/ltcodecs/bytes_codec.py +57 -0
- ltcodecs-1.0.0/src/ltcodecs/ccl_latlon_bcd_codec.py +56 -0
- ltcodecs-1.0.0/src/ltcodecs/ccl_latlon_codec.py +51 -0
- ltcodecs-1.0.0/src/ltcodecs/exceptions.py +16 -0
- ltcodecs-1.0.0/src/ltcodecs/field_codec.py +45 -0
- ltcodecs-1.0.0/src/ltcodecs/fixed_len_array_codec.py +70 -0
- {ltcodecs-0.2.0 → ltcodecs-1.0.0}/src/ltcodecs/fixedint_codec.py +54 -9
- ltcodecs-1.0.0/src/ltcodecs/float_codec.py +73 -0
- ltcodecs-1.0.0/src/ltcodecs/ieee_float_codec.py +71 -0
- ltcodecs-1.0.0/src/ltcodecs/linspace_float_codec.py +90 -0
- ltcodecs-1.0.0/src/ltcodecs/lzma_codec.py +77 -0
- ltcodecs-1.0.0/src/ltcodecs/padding_codec.py +44 -0
- {ltcodecs-0.2.0 → ltcodecs-1.0.0}/src/ltcodecs/ros_message_codec.py +53 -26
- {ltcodecs-0.2.0 → ltcodecs-1.0.0}/src/ltcodecs/ros_msg_field_codec.py +92 -46
- ltcodecs-1.0.0/src/ltcodecs/rostime_codec.py +82 -0
- ltcodecs-1.0.0/src/ltcodecs/string_codecs.py +124 -0
- {ltcodecs-0.2.0 → ltcodecs-1.0.0}/src/ltcodecs/string_enum_codec.py +43 -8
- {ltcodecs-0.2.0 → ltcodecs-1.0.0}/src/ltcodecs/variable_len_array_codec.py +41 -11
- {ltcodecs-0.2.0 → ltcodecs-1.0.0}/src/ltcodecs/varint_codec.py +44 -14
- {ltcodecs-0.2.0 → ltcodecs-1.0.0}/src/ltcodecs.egg-info/PKG-INFO +18 -18
- {ltcodecs-0.2.0 → ltcodecs-1.0.0}/src/ltcodecs.egg-info/SOURCES.txt +4 -1
- ltcodecs-1.0.0/tests/test_codecs.py +362 -0
- ltcodecs-0.2.0/src/ltcodecs/__init__.py +0 -63
- ltcodecs-0.2.0/src/ltcodecs/bool_codec.py +0 -22
- ltcodecs-0.2.0/src/ltcodecs/bytes_codec.py +0 -27
- ltcodecs-0.2.0/src/ltcodecs/ccl_latlon_bcd_codec.py +0 -48
- ltcodecs-0.2.0/src/ltcodecs/ccl_latlon_codec.py +0 -27
- ltcodecs-0.2.0/src/ltcodecs/field_codec.py +0 -23
- ltcodecs-0.2.0/src/ltcodecs/fixed_len_array_codec.py +0 -38
- ltcodecs-0.2.0/src/ltcodecs/float_codec.py +0 -41
- ltcodecs-0.2.0/src/ltcodecs/ieee_float_codec.py +0 -39
- ltcodecs-0.2.0/src/ltcodecs/linspace_float_codec.py +0 -57
- ltcodecs-0.2.0/src/ltcodecs/padding_codec.py +0 -22
- ltcodecs-0.2.0/src/ltcodecs/rostime_codec.py +0 -42
- ltcodecs-0.2.0/src/ltcodecs/string_codecs.py +0 -92
- {ltcodecs-0.2.0 → ltcodecs-1.0.0}/LICENSE +0 -0
- {ltcodecs-0.2.0 → ltcodecs-1.0.0}/README.md +0 -0
- {ltcodecs-0.2.0 → ltcodecs-1.0.0}/pyproject.toml +0 -0
- {ltcodecs-0.2.0 → ltcodecs-1.0.0}/src/ltcodecs.egg-info/dependency_links.txt +0 -0
- {ltcodecs-0.2.0 → ltcodecs-1.0.0}/src/ltcodecs.egg-info/top_level.txt +0 -0
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: ltcodecs
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: LT Codecs
|
|
5
|
-
Home-page: https://git.whoi.edu/acomms/ros_acomms/tree/master/src/acomms_codecs
|
|
6
|
-
Author: whoi
|
|
7
|
-
Author-email: egallimore@whoi.edu
|
|
8
|
-
Project-URL: Bug Tracker, https://git.whoi.edu/acomms/ros_acomms/tree/master/src/acomms_codecs
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.6
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
|
|
16
|
-
# LT Codecs
|
|
17
|
-
|
|
18
|
-
The package was original part of ros_acomms under the field_codecs directory.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: ltcodecs
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: LT Codecs
|
|
5
|
+
Home-page: https://git.whoi.edu/acomms/ros_acomms/tree/master/src/acomms_codecs
|
|
6
|
+
Author: whoi
|
|
7
|
+
Author-email: egallimore@whoi.edu
|
|
8
|
+
Project-URL: Bug Tracker, https://git.whoi.edu/acomms/ros_acomms/tree/master/src/acomms_codecs
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.6
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
|
|
16
|
+
# LT Codecs
|
|
17
|
+
|
|
18
|
+
The package was original part of ros_acomms under the field_codecs directory.
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
[metadata]
|
|
2
|
-
name = ltcodecs
|
|
3
|
-
version = 0.
|
|
4
|
-
author = whoi
|
|
5
|
-
author_email = egallimore@whoi.edu
|
|
6
|
-
description = LT Codecs
|
|
7
|
-
long_description = file: README.md
|
|
8
|
-
long_description_content_type = text/markdown
|
|
9
|
-
url = https://git.whoi.edu/acomms/ros_acomms/tree/master/src/acomms_codecs
|
|
10
|
-
project_urls =
|
|
11
|
-
Bug Tracker = https://git.whoi.edu/acomms/ros_acomms/tree/master/src/acomms_codecs
|
|
12
|
-
classifiers =
|
|
13
|
-
Programming Language :: Python :: 3
|
|
14
|
-
License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
|
|
15
|
-
Operating System :: OS Independent
|
|
16
|
-
|
|
17
|
-
[options]
|
|
18
|
-
package_dir =
|
|
19
|
-
= src
|
|
20
|
-
packages = find:
|
|
21
|
-
python_requires = >=3.6
|
|
22
|
-
include_package_data = True
|
|
23
|
-
|
|
24
|
-
[options.packages.find]
|
|
25
|
-
where = src
|
|
26
|
-
|
|
27
|
-
[egg_info]
|
|
28
|
-
tag_build =
|
|
29
|
-
tag_date = 0
|
|
30
|
-
|
|
1
|
+
[metadata]
|
|
2
|
+
name = ltcodecs
|
|
3
|
+
version = 1.0.0
|
|
4
|
+
author = whoi
|
|
5
|
+
author_email = egallimore@whoi.edu
|
|
6
|
+
description = LT Codecs
|
|
7
|
+
long_description = file: README.md
|
|
8
|
+
long_description_content_type = text/markdown
|
|
9
|
+
url = https://git.whoi.edu/acomms/ros_acomms/tree/master/src/acomms_codecs
|
|
10
|
+
project_urls =
|
|
11
|
+
Bug Tracker = https://git.whoi.edu/acomms/ros_acomms/tree/master/src/acomms_codecs
|
|
12
|
+
classifiers =
|
|
13
|
+
Programming Language :: Python :: 3
|
|
14
|
+
License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
|
|
15
|
+
Operating System :: OS Independent
|
|
16
|
+
|
|
17
|
+
[options]
|
|
18
|
+
package_dir =
|
|
19
|
+
= src
|
|
20
|
+
packages = find:
|
|
21
|
+
python_requires = >=3.6
|
|
22
|
+
include_package_data = True
|
|
23
|
+
|
|
24
|
+
[options.packages.find]
|
|
25
|
+
where = src
|
|
26
|
+
|
|
27
|
+
[egg_info]
|
|
28
|
+
tag_build =
|
|
29
|
+
tag_date = 0
|
|
30
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from .varint_codec import VarintCodec
|
|
2
|
+
from .fixedint_codec import FixedIntCodec
|
|
3
|
+
from .fixedint_codec import Int8Codec, Int16Codec, Int32Codec, Int64Codec
|
|
4
|
+
from .fixedint_codec import UInt8Codec, UInt16Codec, UInt32Codec, UInt64Codec
|
|
5
|
+
from .float_codec import FloatCodec
|
|
6
|
+
from .linspace_float_codec import LinspaceFloatCodec
|
|
7
|
+
from .ieee_float_codec import IeeeFloat32Codec, IeeeFloat64Codec
|
|
8
|
+
from .bool_codec import BoolCodec
|
|
9
|
+
from .string_codecs import AsciiStringCodec
|
|
10
|
+
from .string_enum_codec import StringEnumCodec
|
|
11
|
+
from .bytes_codec import BytesCodec
|
|
12
|
+
from .variable_len_array_codec import VariableLenArrayCodec
|
|
13
|
+
from .fixed_len_array_codec import FixedLenArrayCodec
|
|
14
|
+
from .ros_msg_field_codec import RosMsgFieldCodec
|
|
15
|
+
from .ccl_latlon_codec import CclLatLonCodec
|
|
16
|
+
from .ccl_latlon_bcd_codec import CclLatLonBcdCodec
|
|
17
|
+
from .padding_codec import PaddingCodec
|
|
18
|
+
from .rostime_codec import RosTimeCodec
|
|
19
|
+
from .ros_message_codec import RosMessageCodec
|
|
20
|
+
from .lzma_codec import LzmaCodec
|
|
21
|
+
from .exceptions import EncodingFailed
|
|
22
|
+
|
|
23
|
+
field_codec_classes = {
|
|
24
|
+
"integer": VarintCodec,
|
|
25
|
+
"fixedint": FixedIntCodec,
|
|
26
|
+
"varint": VarintCodec,
|
|
27
|
+
"float": FloatCodec,
|
|
28
|
+
"linspace_float": LinspaceFloatCodec,
|
|
29
|
+
"linspace": LinspaceFloatCodec,
|
|
30
|
+
"uint8": UInt8Codec,
|
|
31
|
+
"uint16": UInt16Codec,
|
|
32
|
+
"uint32": UInt32Codec,
|
|
33
|
+
"uint64": UInt64Codec,
|
|
34
|
+
"int8": Int8Codec,
|
|
35
|
+
"int16": Int16Codec,
|
|
36
|
+
"int32": Int32Codec,
|
|
37
|
+
"int64": Int64Codec,
|
|
38
|
+
"float32": IeeeFloat32Codec,
|
|
39
|
+
"float64": IeeeFloat64Codec,
|
|
40
|
+
"bool": BoolCodec,
|
|
41
|
+
"string": AsciiStringCodec,
|
|
42
|
+
"ascii": AsciiStringCodec,
|
|
43
|
+
"bytes": BytesCodec,
|
|
44
|
+
"msg": RosMsgFieldCodec,
|
|
45
|
+
"ros_msg": RosMsgFieldCodec,
|
|
46
|
+
"variable_len_array": VariableLenArrayCodec,
|
|
47
|
+
"fixed_len_array": FixedLenArrayCodec,
|
|
48
|
+
"ccl_latlon": CclLatLonCodec,
|
|
49
|
+
"ccl_latlon_bcd": CclLatLonBcdCodec,
|
|
50
|
+
"pad": PaddingCodec,
|
|
51
|
+
"padding": PaddingCodec,
|
|
52
|
+
"time": RosTimeCodec,
|
|
53
|
+
"rostime": RosTimeCodec,
|
|
54
|
+
"string_enum": StringEnumCodec,
|
|
55
|
+
"lzma": LzmaCodec,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
metadata_decoders = {
|
|
59
|
+
"src": "packet.src",
|
|
60
|
+
"dest": "packet.dest",
|
|
61
|
+
"dest_decoder": "packet.dest",
|
|
62
|
+
"toa": "cst.toa",
|
|
63
|
+
"snr_in": "cst.snr_in",
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
metadata_encoders = {"dest": "packet.dest"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ltcodecs.bool_codec
|
|
3
|
+
---------------------
|
|
4
|
+
|
|
5
|
+
This module contains the BoolCodec class, which is used to encode and decode bools.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
from bitstring import BitArray, ConstBitStream, Bits
|
|
10
|
+
from .field_codec import FieldCodec
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BoolCodec(FieldCodec):
|
|
14
|
+
"""
|
|
15
|
+
codec for bools
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, **kwargs) -> None:
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
def encode(self, value: bool) -> tuple[Bits, bool]:
|
|
22
|
+
"""
|
|
23
|
+
encode a bool
|
|
24
|
+
|
|
25
|
+
:param value: the bool to encode
|
|
26
|
+
"""
|
|
27
|
+
value = bool(value)
|
|
28
|
+
value_bits = BitArray(bool=value)
|
|
29
|
+
return value_bits, value
|
|
30
|
+
|
|
31
|
+
def decode(self, bits_to_decode: ConstBitStream) -> bool:
|
|
32
|
+
"""
|
|
33
|
+
decode a bool
|
|
34
|
+
|
|
35
|
+
:param bits_to_decode: the bits to decode
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
value = bits_to_decode.read("bool")
|
|
39
|
+
return value
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def min_length_bits(self) -> int:
|
|
43
|
+
return 1
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def max_length_bits(self) -> int:
|
|
47
|
+
return 1
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ltcodecs.bytes_codec
|
|
3
|
+
---------------------
|
|
4
|
+
|
|
5
|
+
This module contains the BytesCodec class, which is used to encode and decode bytes.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
from bitstring import BitArray, ConstBitStream, Bits
|
|
10
|
+
from .field_codec import FieldCodec
|
|
11
|
+
from .varint_codec import VarintCodec
|
|
12
|
+
from .exceptions import EncodingFailed
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BytesCodec(FieldCodec):
|
|
16
|
+
"""
|
|
17
|
+
codec for bytes
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, max_length: int, fail_on_overflow=False, **kwargs) -> None:
|
|
21
|
+
self.max_length = max_length
|
|
22
|
+
self.length_codec = VarintCodec(min_value=0, max_value=self.max_length)
|
|
23
|
+
self.fail_on_overflow = fail_on_overflow
|
|
24
|
+
|
|
25
|
+
def encode(self, value: bytes) -> tuple[Bits, bytes]:
|
|
26
|
+
"""
|
|
27
|
+
encode bytes
|
|
28
|
+
|
|
29
|
+
:param value: the bytes to encode
|
|
30
|
+
"""
|
|
31
|
+
if self.fail_on_overflow and len(value) > self.max_length:
|
|
32
|
+
raise EncodingFailed(
|
|
33
|
+
f"BytesCodec: value with length {len(value)} is too long to encode (codec max_length={self.max_length}"
|
|
34
|
+
)
|
|
35
|
+
value = value[0 : self.max_length]
|
|
36
|
+
length_bits, _ = self.length_codec.encode(len(value))
|
|
37
|
+
value_bits = BitArray(bytes=value)
|
|
38
|
+
value_bits.prepend(length_bits)
|
|
39
|
+
return value_bits, value
|
|
40
|
+
|
|
41
|
+
def decode(self, bits_to_decode: ConstBitStream) -> bytes:
|
|
42
|
+
"""
|
|
43
|
+
decode bytes
|
|
44
|
+
|
|
45
|
+
:param bits_to_decode: the bits to decode
|
|
46
|
+
"""
|
|
47
|
+
num_bytes = self.length_codec.decode(bits_to_decode)
|
|
48
|
+
value = bits_to_decode.read("bytes:" + str(num_bytes))
|
|
49
|
+
return value
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def min_length_bits(self) -> int:
|
|
53
|
+
return self.length_codec.max_length_bits
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def max_length_bits(self) -> int:
|
|
57
|
+
return self.length_codec.max_length_bits + (8 * self.max_length)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ltcodecs.ccl_latlon_bcd_codec
|
|
3
|
+
-----------------------------
|
|
4
|
+
|
|
5
|
+
This module contains the the ccl latlon bcd codec
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
from bitstring import ConstBitStream, Bits
|
|
10
|
+
from .field_codec import FieldCodec
|
|
11
|
+
from math import modf, copysign
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CclLatLonBcdCodec(FieldCodec):
|
|
15
|
+
"""This codec is horrifically inefficient, but included for compatibility with messages like MDAT_RANGER"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, lat_not_lon=True, **kwargs):
|
|
18
|
+
self.lat_not_lon = lat_not_lon
|
|
19
|
+
|
|
20
|
+
def encode(self, value: float) -> tuple[Bits, float]:
|
|
21
|
+
sign = copysign(1, value)
|
|
22
|
+
abs_value = abs(value)
|
|
23
|
+
frac, degrees = modf(abs_value)
|
|
24
|
+
degrees = int(degrees)
|
|
25
|
+
minutes = frac * 60
|
|
26
|
+
dec_min = int(minutes * 10000)
|
|
27
|
+
|
|
28
|
+
if self.lat_not_lon:
|
|
29
|
+
sign_char = "a" if sign > 0 else "c"
|
|
30
|
+
else:
|
|
31
|
+
sign_char = "b" if sign > 0 else "d"
|
|
32
|
+
|
|
33
|
+
hex_string = f"{degrees:03d}{sign_char}{dec_min:06d}"
|
|
34
|
+
encoded_value = sign * (degrees + (dec_min / 10000) / 60)
|
|
35
|
+
encoded_bits = Bits(hex=hex_string)
|
|
36
|
+
|
|
37
|
+
return encoded_bits, encoded_value
|
|
38
|
+
|
|
39
|
+
def decode(self, bits_to_decode: ConstBitStream) -> float:
|
|
40
|
+
string_bytes = bits_to_decode.read("bytes:5")
|
|
41
|
+
hex_string = "".join(f"{x:02x}" for x in string_bytes)
|
|
42
|
+
|
|
43
|
+
degrees = int(hex_string[0:3])
|
|
44
|
+
direction = 1 if hex_string[3] in ("a", "b") else -1
|
|
45
|
+
minutes = float(hex_string[4:10]) / 10000.0
|
|
46
|
+
|
|
47
|
+
value = direction * (degrees + (minutes / 60))
|
|
48
|
+
return value
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def max_length_bits(self) -> int:
|
|
52
|
+
return 40
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def min_length_bits(self) -> int:
|
|
56
|
+
return 40
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ltcodecs.ccl_latlon_codec
|
|
3
|
+
-------------------------
|
|
4
|
+
|
|
5
|
+
ccl_latlon_codec encodes and decodes CCL latitude and longitude values
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
from bitstring import ConstBitStream, Bits
|
|
10
|
+
from .field_codec import FieldCodec
|
|
11
|
+
from math import ceil, log2
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CclLatLonCodec(FieldCodec):
|
|
15
|
+
"""
|
|
16
|
+
codec for CCL latitude and longitude values
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, **kwargs) -> None:
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
def encode(self, value: float) -> tuple[Bits, float]:
|
|
23
|
+
"""
|
|
24
|
+
encode value
|
|
25
|
+
|
|
26
|
+
:param value: the value to encode
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
encoded_value = int(value * ((2**23 - 1) / 180.0))
|
|
30
|
+
encoded_bits = Bits(intle=encoded_value, length=24)
|
|
31
|
+
|
|
32
|
+
return encoded_bits, encoded_value
|
|
33
|
+
|
|
34
|
+
def decode(self, bits_to_decode: ConstBitStream) -> float:
|
|
35
|
+
"""
|
|
36
|
+
decode value
|
|
37
|
+
|
|
38
|
+
:param bits_to_decode: the bitstream to decode
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
scale = bits_to_decode.read("intle:24")
|
|
42
|
+
value = scale * (180.0 / (2**23 - 1))
|
|
43
|
+
return value
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def max_length_bits(self) -> int:
|
|
47
|
+
return 24
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def min_length_bits(self) -> int:
|
|
51
|
+
return 24
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ltcodecs.exceptions
|
|
3
|
+
-------------------
|
|
4
|
+
|
|
5
|
+
This module contains custom exceptions for ltcodecs
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class EncodingFailed(Exception):
|
|
10
|
+
"""
|
|
11
|
+
Raised when encoding fails
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, message: str = "Encoding failed") -> None:
|
|
15
|
+
self.message = message
|
|
16
|
+
super().__init__(self.message)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""
|
|
2
|
+
abstract base class for field codecs
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
from abc import ABC, abstractmethod
|
|
7
|
+
from bitstring import ConstBitStream, Bits
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class FieldCodec(ABC):
|
|
12
|
+
"""
|
|
13
|
+
abstract base class for field codecs
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, **kwargs) -> None:
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def encode(self, value: Any) -> tuple[Bits, Any]:
|
|
21
|
+
"""
|
|
22
|
+
encodes value
|
|
23
|
+
|
|
24
|
+
:param value: value to encode
|
|
25
|
+
"""
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def decode(self, bits_to_decode: ConstBitStream) -> Any:
|
|
30
|
+
"""
|
|
31
|
+
decodes value
|
|
32
|
+
|
|
33
|
+
:param bits_to_decode: ConstBitStream to decode
|
|
34
|
+
"""
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
@abstractmethod
|
|
39
|
+
def max_length_bits(self) -> int:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
@abstractmethod
|
|
44
|
+
def min_length_bits(self) -> int:
|
|
45
|
+
pass
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ltcodecs.fixed_len_array_codec
|
|
3
|
+
------------------------------
|
|
4
|
+
|
|
5
|
+
This module contains the FixedLenArrayCodec class, which is used to encode and decode fixed length arrays.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
from bitstring import BitArray, ConstBitStream, Bits
|
|
10
|
+
from .field_codec import FieldCodec
|
|
11
|
+
import ltcodecs as ltcodecs
|
|
12
|
+
from typing import List
|
|
13
|
+
from .exceptions import EncodingFailed
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class FixedLenArrayCodec(FieldCodec):
|
|
17
|
+
"""
|
|
18
|
+
codec for fixed length arrays
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self, element_type: str, length: int, element_params=None, **kwargs
|
|
23
|
+
) -> None:
|
|
24
|
+
self.length = length
|
|
25
|
+
if element_params:
|
|
26
|
+
self.element_field_codec = ltcodecs.field_codec_classes[element_type](
|
|
27
|
+
**element_params
|
|
28
|
+
)
|
|
29
|
+
else:
|
|
30
|
+
self.element_field_codec = ltcodecs.field_codec_classes[element_type]()
|
|
31
|
+
|
|
32
|
+
def encode(self, value: List) -> tuple[Bits, List]:
|
|
33
|
+
"""
|
|
34
|
+
encode a fixed length array
|
|
35
|
+
|
|
36
|
+
:param value: the fixed length array to encode
|
|
37
|
+
"""
|
|
38
|
+
value = value[0 : self.length]
|
|
39
|
+
value_bits = BitArray()
|
|
40
|
+
encoded_value_list = []
|
|
41
|
+
for element in value:
|
|
42
|
+
(
|
|
43
|
+
element_bits,
|
|
44
|
+
element_value,
|
|
45
|
+
) = self.element_field_codec.encode(element)
|
|
46
|
+
|
|
47
|
+
value_bits.append(element_bits)
|
|
48
|
+
encoded_value_list.append(element_value)
|
|
49
|
+
return value_bits, encoded_value_list
|
|
50
|
+
|
|
51
|
+
def decode(self, bits_to_decode: ConstBitStream) -> List:
|
|
52
|
+
"""
|
|
53
|
+
decode a fixed length array
|
|
54
|
+
|
|
55
|
+
:param bits_to_decode: the bits to decode
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
decoded_list = []
|
|
59
|
+
for i in range(self.length):
|
|
60
|
+
element = self.element_field_codec.decode(bits_to_decode)
|
|
61
|
+
decoded_list.append(element)
|
|
62
|
+
return decoded_list
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def min_length_bits(self) -> int:
|
|
66
|
+
return self.length * self.element_field_codec.max_length_bits
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def max_length_bits(self) -> int:
|
|
70
|
+
return self.length * self.element_field_codec.max_length_bits
|
|
@@ -1,18 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"""
|
|
2
|
+
ltcodecs.fixedint_codec
|
|
3
|
+
-----------------------
|
|
4
|
+
|
|
5
|
+
This module contains classes for fixed width integer codecs
|
|
6
|
+
"""
|
|
7
|
+
|
|
3
8
|
from .varint_codec import VarintCodec
|
|
4
|
-
from math import ceil, log2
|
|
5
9
|
|
|
6
10
|
|
|
7
11
|
class FixedIntCodec(VarintCodec):
|
|
8
|
-
|
|
9
|
-
|
|
12
|
+
"""
|
|
13
|
+
FixedIntCodec base class
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
num_bits: int,
|
|
19
|
+
signed: bool = False,
|
|
20
|
+
min_value: int = None,
|
|
21
|
+
resolution: int = 1,
|
|
22
|
+
little_endian: bool = False,
|
|
23
|
+
**kwargs
|
|
24
|
+
):
|
|
10
25
|
self.num_bits = num_bits
|
|
11
26
|
if min_value:
|
|
12
27
|
self.min_value = int(min_value)
|
|
13
28
|
else:
|
|
14
29
|
if signed:
|
|
15
|
-
self.min_value = -1 * resolution * 2**(self.num_bits - 1)
|
|
30
|
+
self.min_value = -1 * resolution * 2 ** (self.num_bits - 1)
|
|
16
31
|
else:
|
|
17
32
|
self.min_value = 0
|
|
18
33
|
self.max_value = self.min_value + (2**self.num_bits * resolution)
|
|
@@ -21,43 +36,73 @@ class FixedIntCodec(VarintCodec):
|
|
|
21
36
|
self.little_endian = little_endian
|
|
22
37
|
|
|
23
38
|
|
|
24
|
-
|
|
25
|
-
|
|
26
39
|
class Int8Codec(FixedIntCodec):
|
|
40
|
+
"""
|
|
41
|
+
metaclass for int8 codec
|
|
42
|
+
"""
|
|
43
|
+
|
|
27
44
|
def __init__(self, **kwargs):
|
|
28
45
|
super(Int8Codec, self).__init__(num_bits=8, signed=True)
|
|
29
46
|
|
|
30
47
|
|
|
31
48
|
class Int16Codec(FixedIntCodec):
|
|
49
|
+
"""
|
|
50
|
+
metaclass for int16 codec
|
|
51
|
+
"""
|
|
52
|
+
|
|
32
53
|
def __init__(self, **kwargs):
|
|
33
54
|
super(Int16Codec, self).__init__(num_bits=16, signed=True)
|
|
34
55
|
|
|
35
56
|
|
|
36
57
|
class Int32Codec(FixedIntCodec):
|
|
58
|
+
"""
|
|
59
|
+
metaclass for int32 codec
|
|
60
|
+
"""
|
|
61
|
+
|
|
37
62
|
def __init__(self, **kwargs):
|
|
38
63
|
super(Int32Codec, self).__init__(num_bits=32, signed=True)
|
|
39
64
|
|
|
40
65
|
|
|
41
66
|
class Int64Codec(FixedIntCodec):
|
|
67
|
+
"""
|
|
68
|
+
metaclass for int64 codec
|
|
69
|
+
"""
|
|
70
|
+
|
|
42
71
|
def __init__(self, **kwargs):
|
|
43
72
|
super(Int64Codec, self).__init__(num_bits=64, signed=True)
|
|
44
73
|
|
|
45
74
|
|
|
46
75
|
class UInt8Codec(FixedIntCodec):
|
|
76
|
+
"""
|
|
77
|
+
metaclass for uint8 codec
|
|
78
|
+
"""
|
|
79
|
+
|
|
47
80
|
def __init__(self, **kwargs):
|
|
48
81
|
super(UInt8Codec, self).__init__(num_bits=8, signed=False)
|
|
49
82
|
|
|
50
83
|
|
|
51
84
|
class UInt16Codec(FixedIntCodec):
|
|
85
|
+
"""
|
|
86
|
+
metaclass for uint16 codec
|
|
87
|
+
"""
|
|
88
|
+
|
|
52
89
|
def __init__(self, **kwargs):
|
|
53
90
|
super(UInt16Codec, self).__init__(num_bits=16, signed=False)
|
|
54
91
|
|
|
55
92
|
|
|
56
93
|
class UInt32Codec(FixedIntCodec):
|
|
94
|
+
"""
|
|
95
|
+
metaclass for uint32 codec
|
|
96
|
+
"""
|
|
97
|
+
|
|
57
98
|
def __init__(self, **kwargs):
|
|
58
99
|
super(UInt32Codec, self).__init__(num_bits=32, signed=False)
|
|
59
100
|
|
|
60
101
|
|
|
61
102
|
class UInt64Codec(FixedIntCodec):
|
|
103
|
+
"""
|
|
104
|
+
metaclass for uint64 codec
|
|
105
|
+
"""
|
|
106
|
+
|
|
62
107
|
def __init__(self, **kwargs):
|
|
63
|
-
super(UInt32Codec, self).__init__(num_bits=64, signed=False)
|
|
108
|
+
super(UInt32Codec, self).__init__(num_bits=64, signed=False)
|