Changeset View
Changeset View
Standalone View
Standalone View
swh/core/bencode.py
- This file was added.
# Copyright (C) 2019 The Software Heritage developers | |||||
# See the AUTHORS file at the top-level directory of this distribution | |||||
# License: GNU General Public License version 3, or any later version | |||||
# See top-level LICENSE file for more information | |||||
douardda: It really misses a docstring at module level to explain what it is and how to use it, and how… | |||||
Done Inline ActionsI'm not sure what to write here; there's a single public function, and it's already documented. vlorentz: I'm not sure what to write here; there's a single public function, and it's already documented. | |||||
"""Provides a bencode encoder. | |||||
This allows encoding a nested bytes/int/list/dict structure | |||||
into its bencode representation.""" | |||||
from typing import Dict, Callable, Any, Generator | |||||
def _encode_bytes(obj: bytes) -> Generator[bytes, None, None]: | |||||
yield b'%d:' % len(obj) | |||||
yield obj | |||||
def _encode_int(obj: int) -> Generator[bytes, None, None]: | |||||
yield b'i%de' % obj | |||||
def _encode_list(obj: list) -> Generator[bytes, None, None]: | |||||
yield b'l' | |||||
for item in obj: | |||||
yield from _encode(item) | |||||
yield b'e' | |||||
def _encode_dict(obj: dict) -> Generator[bytes, None, None]: | |||||
yield b'd' | |||||
for (key, value) in sorted(obj.items()): | |||||
if type(key) != bytes: | |||||
raise TypeError('bencode dictionary keys must be bytes, not {}.' | |||||
.format(type(key))) | |||||
yield from _encode_bytes(key) | |||||
yield from _encode(value) | |||||
yield b'e' | |||||
_ENCODERS = { | |||||
bytes: _encode_bytes, | |||||
int: _encode_int, | |||||
list: _encode_list, | |||||
dict: _encode_dict, | |||||
} # type: Dict[type, Callable[[Any], Generator[bytes, None, None]]] | |||||
def _encode(obj: Any) -> Generator[bytes, None, None]: | |||||
encoder = _ENCODERS.get(type(obj), None) | |||||
if not encoder: | |||||
raise TypeError('Unsupported type for bencoding: {}'.format(type(obj))) | |||||
yield from encoder(obj) | |||||
Not Done Inline ActionsI don't get the list used to gather results here. Why isn't this just a generator? douardda: I don't get the list used to gather results here. Why isn't this just a generator? | |||||
Done Inline ActionsBecause I didn't think of using a generator. I just rewrote it to use a generator, the code is almost the same (although generators are slightly slower), so I don't really care either way * shrug * vlorentz: Because I didn't think of using a generator.
I just rewrote it to use a generator, the code is… | |||||
def encode(obj) -> bytes: | |||||
"""Encodes a nested bytes/int/list/dict structure into its bencode | |||||
representation. | |||||
""" | |||||
return b''.join(_encode(obj)) |
It really misses a docstring at module level to explain what it is and how to use it, and how are basic types serialized by this encoder.