aboutsummaryrefslogtreecommitdiff
path: root/tools/cru-py/cru/_event.py
blob: 51a794c49aa3c9081d4ea1682d5ed872bb1cea34 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
from __future__ import annotations

from collections.abc import Callable
from typing import Generic, ParamSpec, TypeVar

from .list import CruList

_P = ParamSpec("_P")
_R = TypeVar("_R")


class CruEventHandlerToken(Generic[_P, _R]):
    def __init__(
        self, event: CruEvent, handler: Callable[_P, _R], once: bool = False
    ) -> None:
        self._event = event
        self._handler = handler
        self._once = once

    @property
    def event(self) -> CruEvent:
        return self._event

    @property
    def handler(self) -> Callable[_P, _R]:
        return self._handler

    @property
    def once(self) -> bool:
        return self._once


class CruEvent(Generic[_P, _R]):
    def __init__(self, name: str) -> None:
        self._name = name
        self._tokens: CruList[CruEventHandlerToken] = CruList()

    def register(
        self, handler: Callable[_P, _R], once: bool = False
    ) -> CruEventHandlerToken:
        token = CruEventHandlerToken(self, handler, once)
        self._tokens.append(token)
        return token

    def unregister(self, *handlers: CruEventHandlerToken | Callable[_P, _R]) -> int:
        old_length = len(self._tokens)
        self._tokens.reset(
            self._tokens.as_cru_iterator().filter(
                (lambda t: t in handlers or t.handler in handlers)
            )
        )
        return old_length - len(self._tokens)

    def trigger(self, *args: _P.args, **kwargs: _P.kwargs) -> CruList[_R]:
        results = CruList(
            self._tokens.as_cru_iterator()
            .transform(lambda t: t.handler(*args, **kwargs))
            .to_list()
        )
        self._tokens.reset(self._tokens.as_cru_iterator().filter(lambda t: not t.once))
        return results