mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-08-08 04:52:30 +00:00
Generate deserializers for requests
This commit is contained in:
@@ -1,5 +1,24 @@
|
||||
from .reader import Reader
|
||||
from .reader import (
|
||||
Reader,
|
||||
deserialize_bool,
|
||||
deserialize_i32_list,
|
||||
deserialize_i64_list,
|
||||
deserialize_identity,
|
||||
list_deserializer,
|
||||
single_deserializer,
|
||||
)
|
||||
from .request import Request
|
||||
from .serializable import Serializable, serialize_bytes_to
|
||||
|
||||
__all__ = ["Reader", "Request", "Serializable", "serialize_bytes_to"]
|
||||
__all__ = [
|
||||
"Reader",
|
||||
"deserialize_bool",
|
||||
"deserialize_i32_list",
|
||||
"deserialize_i64_list",
|
||||
"deserialize_identity",
|
||||
"list_deserializer",
|
||||
"single_deserializer",
|
||||
"Request",
|
||||
"Serializable",
|
||||
"serialize_bytes_to",
|
||||
]
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import functools
|
||||
import struct
|
||||
from typing import TYPE_CHECKING, Any, Optional, Type, TypeVar
|
||||
from typing import TYPE_CHECKING, Any, Callable, List, Optional, Type, TypeVar
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .serializable import Serializable
|
||||
@@ -85,3 +86,47 @@ class Reader:
|
||||
raise ValueError(f"No type found for constructor ID: {cid:x}")
|
||||
assert issubclass(ty, cls)
|
||||
return ty._read_from(self)
|
||||
|
||||
|
||||
@functools.cache
|
||||
def single_deserializer(cls: Type[T]) -> Callable[[bytes], T]:
|
||||
def deserializer(body: bytes) -> T:
|
||||
return Reader(body).read_serializable(cls)
|
||||
|
||||
return deserializer
|
||||
|
||||
|
||||
@functools.cache
|
||||
def list_deserializer(cls: Type[T]) -> Callable[[bytes], List[T]]:
|
||||
def deserializer(body: bytes) -> List[T]:
|
||||
reader = Reader(body)
|
||||
vec_id, length = reader.read_fmt("<ii", 8)
|
||||
assert vec_id == 0x1CB5C415 and length >= 0
|
||||
return [reader.read_serializable(cls) for _ in range(length)]
|
||||
|
||||
return deserializer
|
||||
|
||||
|
||||
def deserialize_i64_list(body: bytes) -> List[int]:
|
||||
reader = Reader(body)
|
||||
vec_id, length = reader.read_fmt("<ii", 8)
|
||||
assert vec_id == 0x1CB5C415 and length >= 0
|
||||
return [*reader.read_fmt(f"<{length}q", length * 8)]
|
||||
|
||||
|
||||
def deserialize_i32_list(body: bytes) -> List[int]:
|
||||
reader = Reader(body)
|
||||
vec_id, length = reader.read_fmt("<ii", 8)
|
||||
assert vec_id == 0x1CB5C415 and length >= 0
|
||||
return [*reader.read_fmt(f"<{length}i", length * 4)]
|
||||
|
||||
|
||||
def deserialize_identity(body: bytes) -> bytes:
|
||||
return body
|
||||
|
||||
|
||||
def deserialize_bool(body: bytes) -> bool:
|
||||
reader = Reader(body)
|
||||
bool_id = reader.read_fmt("<I", 4)[0]
|
||||
assert isinstance(bool_id, int) and bool_id in (0x997275B5, 0xBC799737)
|
||||
return bool_id == 0x997275B5
|
||||
|
@@ -1,9 +1,28 @@
|
||||
import struct
|
||||
from typing import Generic, TypeVar
|
||||
from typing import Any, Callable, Generic, Optional, TypeVar
|
||||
|
||||
Return = TypeVar("Return")
|
||||
|
||||
|
||||
def _bootstrap_get_deserializer(
|
||||
constructor_id: int,
|
||||
) -> Optional[Callable[[bytes], Any]]:
|
||||
# Similar to Reader's bootstrapping.
|
||||
if Request._get_deserializer is _bootstrap_get_deserializer:
|
||||
from ..layer import RESPONSE_MAPPING as API_DESER
|
||||
from ..mtproto.layer import RESPONSE_MAPPING as MTPROTO_DESER
|
||||
|
||||
if API_DESER.keys() & MTPROTO_DESER.keys():
|
||||
raise RuntimeError(
|
||||
"generated api and mtproto schemas cannot have colliding constructor identifiers"
|
||||
)
|
||||
ALL_DESER = API_DESER | MTPROTO_DESER
|
||||
|
||||
Request._get_deserializer = ALL_DESER.get # type: ignore [assignment]
|
||||
|
||||
return Request._get_deserializer(constructor_id)
|
||||
|
||||
|
||||
class Request(bytes, Generic[Return]):
|
||||
__slots__ = ()
|
||||
|
||||
@@ -16,5 +35,12 @@ class Request(bytes, Generic[Return]):
|
||||
except struct.error:
|
||||
return 0
|
||||
|
||||
_get_deserializer = staticmethod(_bootstrap_get_deserializer)
|
||||
|
||||
def deserialize_response(self, response: bytes) -> Return:
|
||||
deserializer = self._get_deserializer(self.constructor_id)
|
||||
assert deserializer is not None
|
||||
return deserializer(response) # type: ignore [no-any-return]
|
||||
|
||||
def debug_name(self) -> str:
|
||||
return f"request#{self.constructor_id:x}"
|
||||
|
Reference in New Issue
Block a user