from typing import Protocol, Any, Union, Iterable, TypeVar, runtime_checkable

# T_co is covariant, meaning SemanticPointerProtocol can return subtypes of itself
T_Pointer = TypeVar("T_Pointer", bound="SemanticPointerProtocol", covariant=True)


@runtime_checkable
class SemanticPointerProtocol(Protocol[T_Pointer]):
    def __getattr__(self, name: str) -> T_Pointer: ...

    def __str__(self) -> str: ...

    def __hash__(self) -> int: ...

    def __eq__(self, other: Any) -> bool: ...

    def __add__(self, other: Any) -> T_Pointer: ...

    def __truediv__(
        self, other: Union[str, "SemanticPointerProtocol"]
    ) -> T_Pointer: ...

    def __mul__(self, other: Any) -> "PointerSetProtocol": ...

    def __getitem__(self, key: Any) -> Union[T_Pointer, "PointerSetProtocol"]: ...


@runtime_checkable
class PointerSetProtocol(Protocol):
    def __iter__(self) -> Iterable[SemanticPointerProtocol]: ...

    def __getattr__(self, name: str) -> "PointerSetProtocol": ...

    def __truediv__(
        self, other: Union[str, SemanticPointerProtocol]
    ) -> "PointerSetProtocol": ...

    def __or__(self, other: "PointerSetProtocol") -> "PointerSetProtocol": ...

    def __add__(
        self, other: Union[str, SemanticPointerProtocol]
    ) -> "PointerSetProtocol": ...

    def __mul__(self, other: Any) -> "PointerSetProtocol": ...

    def __getitem__(self, key: Any) -> "PointerSetProtocol": ...


@runtime_checkable
class OperatorProtocol(Protocol):
    def __call__(self, key: Any) -> Any: ...


@runtime_checkable
class RendererProtocol(Protocol):
    def render(self, message: str, level: str = "info", **kwargs: Any) -> None: ...
