changes from voice chat
This commit is contained in:
parent
c5eaba88b7
commit
6d1a6907d2
@ -1 +1,2 @@
|
|||||||
from .gear import *
|
from .gear import Gear
|
||||||
|
from .effect import Effect
|
||||||
|
@ -3,11 +3,8 @@ from typing import Any, Hashable, TypeVar, Callable
|
|||||||
from gears.effect import effect_of
|
from gears.effect import effect_of
|
||||||
from gears.gear import Gear
|
from gears.gear import Gear
|
||||||
|
|
||||||
S = TypeVar("S", bound=Hashable)
|
|
||||||
T = TypeVar("T", bound=Hashable)
|
|
||||||
|
|
||||||
|
def connect[S: Hashable, T: Hashable](
|
||||||
def connect(
|
|
||||||
source: Gear[S],
|
source: Gear[S],
|
||||||
to_target_val: Callable[[S], T],
|
to_target_val: Callable[[S], T],
|
||||||
to_source: Callable[[S, T], S],
|
to_source: Callable[[S, T], S],
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
from __future__ import annotations
|
||||||
from typing import Any, Callable, cast
|
from typing import Any, Callable, cast
|
||||||
|
|
||||||
from gears import Gear
|
|
||||||
from .wrap_aware_tuple import WrapAwareTuple
|
from .wrap_aware_tuple import WrapAwareTuple
|
||||||
|
|
||||||
|
|
||||||
class Effect[*Ts]:
|
class Effect[*Ts]:
|
||||||
def __init__(self, fn: Callable[[*Ts], None], gears: WrapAwareTuple[Gear, *Ts]):
|
def __init__(self, fn: Callable[[*Ts], None], gears: WrapAwareTuple[Gear, *Ts]):
|
||||||
for gear in gears:
|
for gear in gears:
|
||||||
@ -15,17 +15,22 @@ class Effect[*Ts]:
|
|||||||
def on_change(self):
|
def on_change(self):
|
||||||
self._fn(*self._gears.unwrap(lambda x: x()))
|
self._fn(*self._gears.unwrap(lambda x: x()))
|
||||||
|
|
||||||
def effect_of[*Ts, *G_Ts](
|
|
||||||
*gears: Gear[Any]
|
def effect_of[*Ts](
|
||||||
|
*gears: Gear[Any],
|
||||||
) -> Callable[[Callable[[*Ts], None]], Effect]:
|
) -> Callable[[Callable[[*Ts], None]], Effect]:
|
||||||
# No deduction, no tears, only cast now
|
# No deduction, no tears, only cast now
|
||||||
ts_gears = cast(WrapAwareTuple[Gear, *Ts], WrapAwareTuple.prewrapped(gears))
|
ts_gears = cast(WrapAwareTuple[Gear, *Ts], WrapAwareTuple.prewrapped(gears))
|
||||||
return effect_of_typechecked(ts_gears)
|
return effect_of_typechecked(ts_gears)
|
||||||
|
|
||||||
|
|
||||||
def effect_of_typechecked[*Ts](
|
def effect_of_typechecked[*Ts](
|
||||||
gears: WrapAwareTuple[Gear, *Ts]
|
gears: WrapAwareTuple[Gear, *Ts],
|
||||||
) -> Callable[[Callable[[*Ts], None]], Effect]:
|
) -> Callable[[Callable[[*Ts], None]], Effect]:
|
||||||
def decorator(fn: Callable[[*Ts], None]) -> Effect:
|
def decorator(fn: Callable[[*Ts], None]) -> Effect:
|
||||||
return Effect(fn, gears)
|
return Effect(fn, gears)
|
||||||
|
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
from gears import Gear
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
|
from __future__ import annotations
|
||||||
from typing import Any, Hashable, TypeVar, TYPE_CHECKING
|
from typing import Any, Hashable, TypeVar, TYPE_CHECKING
|
||||||
|
|
||||||
T = TypeVar("T", bound=Hashable)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from gears.effect import Effect
|
from gears.effect import Effect
|
||||||
|
|
||||||
class Gear[T]():
|
|
||||||
|
class Gear[T: Hashable]:
|
||||||
def __init__(self, value: T):
|
def __init__(self, value: T):
|
||||||
self._value = value
|
self._value = value
|
||||||
self.effects: list['Effect'] = []
|
self.effects: list[Effect] = []
|
||||||
|
|
||||||
def get(self) -> T:
|
def get(self) -> T:
|
||||||
return self._value
|
return self._value
|
||||||
|
@ -1,90 +0,0 @@
|
|||||||
|
|
||||||
from typing import cast, Callable, reveal_type, TYPE_CHECKING
|
|
||||||
|
|
||||||
# no-op "Wrap" type
|
|
||||||
type Identity[X] = X
|
|
||||||
|
|
||||||
class WrapAwareTuple[Wrap, *Ts](tuple[Wrap, ...]):
|
|
||||||
'''
|
|
||||||
Wrap is a wrapper type around each of the types in Ts, in order.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
a: Wrapped[Wrap, int, str, float] = Wrapped(Wrap[int], Wrap[str], Wrap[float])
|
|
||||||
|
|
||||||
This lets us keep track of type transformations, starting from the Identity mapping.
|
|
||||||
'''
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def id[*NewTs](*args: *NewTs) -> 'WrapAwareTuple[Identity, *NewTs]':
|
|
||||||
'''
|
|
||||||
Create a new WrapAwareTuple, using the Identity psuedo-wrapper.
|
|
||||||
'''
|
|
||||||
return WrapAwareTuple[Identity, *NewTs](args)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def prewrapped[NewWrap, *NewTs](args: tuple[NewWrap, ...]) -> 'WrapAwareTuple[NewWrap, *NewTs]':
|
|
||||||
'''
|
|
||||||
Create a new WrapAwareTuple, using the given wrapper type.
|
|
||||||
'''
|
|
||||||
return WrapAwareTuple[NewWrap, *NewTs](args)
|
|
||||||
|
|
||||||
def wrap[NewWrap](self, mapper: Callable[[Wrap], NewWrap]) -> 'WrapAwareTuple[NewWrap, *Ts]':
|
|
||||||
'''
|
|
||||||
Wrap all existing elements with a new wrapping function.
|
|
||||||
|
|
||||||
This function must unwrap the current wrapping type, if non-Identity, and apply a new one.
|
|
||||||
|
|
||||||
To pop the wrapped value from a tuple wrapper:
|
|
||||||
>>> Wrapped[tuple, int](3).wrap[Identity](lambda x: x[0])
|
|
||||||
|
|
||||||
To wrap an unwrapped value into a tuple:
|
|
||||||
>>> Wrapped[Identity, int](3).wrap(tuple)
|
|
||||||
'''
|
|
||||||
# pyright supports Union[*Ts], but we still can't do applicative functor things with it
|
|
||||||
return WrapAwareTuple[NewWrap, *Ts](mapper(v) for v in self)
|
|
||||||
|
|
||||||
def unwrap(self, mapper: Callable[[Wrap], Identity]) -> tuple[*Ts]:
|
|
||||||
'''
|
|
||||||
Unwrap all elements in the tuple, returning a normal tuple.
|
|
||||||
|
|
||||||
This is the same as calling wrap with the appropriate wrapper, except we simplify the signature and
|
|
||||||
return type for this case.
|
|
||||||
'''
|
|
||||||
return cast(tuple[*Ts], self.wrap(mapper))
|
|
||||||
|
|
||||||
def list_fmap[*Ts](t: tuple[*Ts]):
|
|
||||||
match t:
|
|
||||||
case (head, *tail):
|
|
||||||
return ([head], *list_fmap(tuple(tail)))
|
|
||||||
case _:
|
|
||||||
return ()
|
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
def _fmap_scratchpad():
|
|
||||||
reveal_type(list_fmap((1,"s",3.0)))
|
|
||||||
# Type of "list_fmap((1, "s", 3))" is "tuple[list[*tuple[int, str, float]], *tuple[list[*tuple[Unknown, ...]] | Unknown, ...]] | tuple[()]"
|
|
||||||
# ...wanted to get "tuple[list[int], list[str], list[float]]"; RIP
|
|
||||||
|
|
||||||
def _wrapaware_scratchpad():
|
|
||||||
|
|
||||||
atom = WrapAwareTuple.id(3)
|
|
||||||
reveal_type(atom)
|
|
||||||
# Type of "atom" is "Wrapped[Unknown, int]"
|
|
||||||
# (variable) atom: Wrapped[Identity[Unknown], int]
|
|
||||||
|
|
||||||
compound_3 = WrapAwareTuple.id(3, "str", 9.0)
|
|
||||||
reveal_type(compound_3)
|
|
||||||
# Type of "compound_3" is "Wrapped[Unknown, int, str, float]"
|
|
||||||
# (variable) compound_3: Wrapped[Identity[Unknown], int, str, float]
|
|
||||||
|
|
||||||
tupled_compound_3 = compound_3.wrap(tuple)
|
|
||||||
reveal_type(tupled_compound_3)
|
|
||||||
# Type of "tupled_compound_3" is "Wrapped[tuple[Unknown, ...], int, str, float]"
|
|
||||||
# (variable) tupled_compound_3: Wrapped[tuple[Identity[Unknown], ...], int, str, float]
|
|
||||||
|
|
||||||
restored_compound_3 = tupled_compound_3.wrap(lambda x: x[0])
|
|
||||||
reveal_type(restored_compound_3)
|
|
||||||
# Type of "restored_compound_3" is "Wrapped[Unknown, int, str, float]"
|
|
||||||
# (variable) restored_compound_3: Wrapped[Unknown, int, str, float]
|
|
@ -3,7 +3,7 @@ from typing import NamedTuple
|
|||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
from gears import Gear
|
from gears import Gear
|
||||||
from gears.connections import connect
|
from gears.connections import connect
|
||||||
from gears.effect import effect_of
|
from gears.effect import effect_of, effect_of_2
|
||||||
|
|
||||||
|
|
||||||
def test_get_set():
|
def test_get_set():
|
||||||
@ -35,7 +35,7 @@ def test_effect_of_2():
|
|||||||
|
|
||||||
last_arg: tuple[str, int] | None = None
|
last_arg: tuple[str, int] | None = None
|
||||||
|
|
||||||
@effect_of(g1, g2)
|
@effect_of_2(g1, g2)
|
||||||
def value_changed(v1: str, v2: int):
|
def value_changed(v1: str, v2: int):
|
||||||
nonlocal last_arg
|
nonlocal last_arg
|
||||||
last_arg = (v1, v2)
|
last_arg = (v1, v2)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user