Skip to content

Commit b00eb3f

Browse files
committed
[New] codec: Idem and Pipeline codecs
1 parent 7f548f4 commit b00eb3f

File tree

1 file changed

+52
-6
lines changed

1 file changed

+52
-6
lines changed

src/py/extra/utils/codec.py

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,47 @@ def flush(self) -> bytes | None | Literal[False]:
1515
"""Ensures that the bytes transform is flushed, for chunked encodings this will produce a new chunk."""
1616

1717

18-
class GZipDecoder(BytesTransform):
19-
__slots__ = ["decompressor"]
18+
class IdemCodec(BytesTransform):
19+
"""A codec that doesn't change anything, can be used when you need to swap in another codec."""
2020

21-
def __init__(self) -> None:
21+
def feed(self, chunk: bytes, more: bool = False) -> bytes | None | Literal[False]:
22+
return chunk
23+
24+
def flush(
25+
self,
26+
) -> bytes | None | Literal[False]:
27+
return None
28+
29+
30+
class PipelineCodec(BytesTransform):
31+
"""A way to compose transforms together."""
32+
33+
def __init__(self, transforms: list[BytesTransform]):
2234
super().__init__()
23-
self.decompressor = zlib.decompressobj(wbits=zlib.MAX_WBITS | 32)
35+
self.transforms: list[BytesTransform] = transforms
36+
37+
def decoder(self) -> "PipelineCodec":
38+
"""Returns the decoder/coder pipeline for this codec"""
39+
return PipelineCodec(reversed(self.transforms))
2440

2541
def feed(self, chunk: bytes, more: bool = False) -> bytes | None | Literal[False]:
26-
return self.decompressor.decompress(chunk)
42+
res: bytes | Literal[False] | None = chunk
43+
for t in self.transforms:
44+
if not res:
45+
return res
46+
else:
47+
res = t.feed(res)
48+
return res
2749

2850
def flush(
2951
self,
3052
) -> bytes | None | Literal[False]:
31-
return self.decompressor.flush()
53+
return None
3254

3355

3456
class GZipEncoder(BytesTransform):
57+
"""Encode bytes as Gzip"""
58+
3559
__slots__ = ["compressor"]
3660

3761
def __init__(self, compression_level: int = 6) -> None:
@@ -47,8 +71,28 @@ def flush(self) -> bytes | None | Literal[False]:
4771
return self.compressor.flush()
4872

4973

74+
class GZipDecoder(BytesTransform):
75+
"""Decodes bytes as Gzip"""
76+
77+
__slots__ = ["decompressor"]
78+
79+
def __init__(self) -> None:
80+
super().__init__()
81+
self.decompressor = zlib.decompressobj(wbits=zlib.MAX_WBITS | 32)
82+
83+
def feed(self, chunk: bytes, more: bool = False) -> bytes | None | Literal[False]:
84+
return self.decompressor.decompress(chunk)
85+
86+
def flush(
87+
self,
88+
) -> bytes | None | Literal[False]:
89+
return self.decompressor.flush()
90+
91+
5092
# SEE: https://httpwg.org/specs/rfc9112.html#chunked.encoding
5193
class ChunkedEncoder(BytesTransform):
94+
"""Encodes as chunks"""
95+
5296
__slots__ = ["buffer"]
5397

5498
def __init__(self) -> None:
@@ -70,6 +114,8 @@ def flush(self) -> bytes | None | Literal[False]:
70114

71115

72116
class ChunkedDecoder(BytesTransform):
117+
"""Decodes as chunks"""
118+
73119
__slots__ = ["buffer", "chunkSize", "readingSize"]
74120

75121
def __init__(self) -> None:

0 commit comments

Comments
 (0)