Skip to content

Instantly share code, notes, and snippets.

@nerodono
Created February 8, 2024 22:00
Show Gist options
  • Save nerodono/15ed162280174f8f790481dbc26bae5e to your computer and use it in GitHub Desktop.
Save nerodono/15ed162280174f8f790481dbc26bae5e to your computer and use it in GitHub Desktop.
Stupidly simple mapper
from typing import (
Generic,
TypeVar,
Protocol,
Any,
Type,
NewType,
)
T = TypeVar("T")
R = TypeVar("R")
Src = TypeVar("Src", contravariant=True)
Dst = TypeVar("Dst", covariant=True)
class ConvertRule(Protocol[Src, Dst]):
def __call__(self, src: Src, /) -> Dst:
...
class RulesStore(Generic[T]):
__slots__ = ('rules', )
def __init__(self, rules: dict[Any, ConvertRule[T, Any]]) -> None:
self.rules = rules
def add_rule(
self,
# Это можно и убрать вообще, но для lambda полезно
to_tp: Type[Dst],
rule: ConvertRule[T, Dst]
) -> None:
self.rules[to_tp] = rule
def convert(self, value: T, tp: Type[Dst]) -> Dst:
return self.rules[tp](value)
class ObjectMapper:
__slots__ = ('_types', )
def __init__(self) -> None:
self._types: dict[Any, RulesStore[Any]] = {}
def convert(
self,
src_tp: Type[Src],
dst_tp: Type[Dst],
src: Src,
) -> Dst:
return self._types[src_tp].convert(src, dst_tp)
def add_rule(
self,
src_tp: Type[Src],
dst_tp: Type[Dst],
rule: ConvertRule[Src, Dst],
) -> None:
store = self._types.get(src_tp)
if store is None:
store = RulesStore[Src]({})
self._types[src_tp] = store
store.add_rule(dst_tp, rule)
Age = NewType("Age", int)
mapper = ObjectMapper()
mapper.add_rule(int, str, str)
mapper.add_rule(int, Age, Age)
mapper.add_rule(int, int, lambda x: x + 10)
print(repr(mapper.convert(int, str, 10)))
print(repr(mapper.convert(int, Age, 13))) # Уже нормальная такая женщина
print(mapper.convert(int, int, 1478))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment