From: Axy Date: Tue, 22 Sep 2026 22:43:13 +0000 (+0200) Subject: Small update to fix union support in queries X-Git-Url: https://git.uwuaxy.net/sitemap.xml?a=commitdiff_plain;h=9120a7931081eec2d8292c852092a2613bd0f2fb;p=axy%2Fft%2Fpacman.git Small update to fix union support in queries --- diff --git a/src/pacman/ecs/__init__.py b/src/pacman/ecs/__init__.py index d963f97..c231363 100644 --- a/src/pacman/ecs/__init__.py +++ b/src/pacman/ecs/__init__.py @@ -126,7 +126,8 @@ def close_on_close(world: World, events: WindowEvents) -> None: def render_sprite2d( - window: Window, sprites_q: Query[tuple[CoordAbs2D, Sprite2D, ShouldRender]] + window: Window, + sprites_q: Query[tuple[CoordAbs2D, Sprite2D], ShouldRender], ) -> None: sprites_raw = sorted( sprites_q, @@ -134,7 +135,9 @@ def render_sprite2d( reverse=True, ) sprites = [ - (sprite.surface, coord._vec.xy) for coord, sprite, _ in sprites_raw + (sprite.surface, coord._vec.xy) + for coord, sprite in sprites_raw + if sprite is not None ] window.surface.fill((0, 0, 0)) window.surface.blits(sprites) diff --git a/src/pacman/ecs/world.py b/src/pacman/ecs/world.py index f6a6a9c..7f0a862 100644 --- a/src/pacman/ecs/world.py +++ b/src/pacman/ecs/world.py @@ -225,6 +225,13 @@ class QueryFilter: type QueryFilters = RecursiveTuple[QueryFilter] +class _NoFetchCls: + pass + + +_NoFetch = _NoFetchCls() + + class QueryItem(QueryFilter): @override @classmethod @@ -242,10 +249,10 @@ class QueryItem(QueryFilter): @abstractmethod def filter_fetch( cls, ty: type - ) -> Callable[[Archetype], None | Callable[[int], Self]]: ... + ) -> Callable[[Archetype], None | Callable[[int], Self | _NoFetchCls]]: ... -type QueryItems = RecursiveTuple[QueryItem] +type QueryItems = RecursiveTuple[QueryItem | None] class Component(QueryItem): @@ -258,7 +265,7 @@ class Component(QueryItem): @classmethod def filter_fetch( cls, ty: type - ) -> Callable[[Archetype], None | Callable[[int], Self]]: + ) -> Callable[[Archetype], None | Callable[[int], Self | _NoFetchCls]]: return lambda archetype: ( None if (idx := archetype._components.get(ty)) is None @@ -340,25 +347,27 @@ class Query[Items, Filters = tuple[()]]( ) -> None: if filters is None: filters = cast(type[Filters], tuple[()]) + resolved_fetchers = resolve_type_aliases(fetchers) + resolved_filters = resolve_type_aliases(filters) self._world: World = world self._fetchers_raw = cast( - Callable[[Archetype], Callable[[int], Items] | None], - Query.preprocess_fetchers(resolve_type_aliases(fetchers)), - ) - self._filters_raw = Query.preprocess_filters( - resolve_type_aliases(filters) + Callable[[Archetype], Callable[[int], Items | _NoFetchCls] | None], + Query.preprocess_fetchers(resolved_fetchers), ) + self._filters_raw = Query.preprocess_filters(resolved_filters) self._seen_archetypes: int = 0 self._archetypes_idx: dict[Archetype, int] = {} self._archetypes: list[Archetype] = [] self._filters: list[Callable[[int], bool]] = [] - self._fetchers: list[Callable[[int], Items]] = [] + self._fetchers: list[Callable[[int], Items | _NoFetchCls]] = [] self.updated_from_world() @staticmethod def preprocess_fetchers( fetcher: type[QueryItems], - ) -> Callable[[Archetype], Callable[[int], QueryItems] | None]: + ) -> Callable[ + [Archetype], Callable[[int], QueryItems | _NoFetchCls] | None + ]: args = list(map(Query.preprocess_fetchers, get_args(fetcher))) def tuple_constructor( @@ -370,12 +379,20 @@ class Query[Items, Filters = tuple[()]]( if curr is None: return None lst.append(curr) - return fast_tuple_constructor(tuple(lst)) + constr = fast_tuple_constructor(tuple(lst)) + return lambda i: cast( + QueryItems, + ( + res + if all(map(lambda e: e is not _NoFetch, res := constr(i))) + else _NoFetch + ), + ) def union_constructor( archetype: Archetype, - ) -> Callable[[int], QueryItems] | None: - lst: list[Callable[[int], QueryItems]] = [] + ) -> Callable[[int], QueryItems | _NoFetchCls] | None: + lst: list[Callable[[int], QueryItems | _NoFetchCls]] = [] for arg in args: curr = arg(archetype) if curr is None: @@ -383,12 +400,17 @@ class Query[Items, Filters = tuple[()]]( lst.append(curr) if len(lst) == 0: return None - return lst.pop() + return lambda i: next( + (res for e in lst if (res := e(i)) is not _NoFetch), _NoFetch + ) - if origin_or_cls(fetcher) is tuple: + orig = origin_or_cls(fetcher) + if orig is tuple: return tuple_constructor - if origin_or_cls(fetcher) is Union: + if orig is Union: return union_constructor + if orig is None or orig is type(None): + return lambda _: None return cast(QueryItem, fetcher).filter_fetch(fetcher) @@ -419,7 +441,7 @@ class Query[Items, Filters = tuple[()]]( return False cond = composed_by(cond, curr, bool.__and__) if cond is None: - return lambda _: True + return True return cond def union_constructor( @@ -434,13 +456,16 @@ class Query[Items, Filters = tuple[()]]( continue cond = composed_by(cond, curr, bool.__or__) if cond is None: - return lambda _: False + return False return cond - if origin_or_cls(filter) is tuple: + orig = origin_or_cls(filter) + if orig is tuple: return tuple_constructor - if origin_or_cls(filter) is Union: + if orig is Union: return union_constructor + if orig is None or orig is type(None): + return lambda _: True return cast(QueryFilter, filter).filter(filter) @@ -479,12 +504,12 @@ class Query[Items, Filters = tuple[()]]( @override def __iter__(self) -> Iterator[Items]: return ( - fetch(i) + cast(Items, res) for filt, fetch, arch in zip( self._filters, self._fetchers, self._archetypes, strict=True ) for i in range(len(arch._entities)) - if filt(i) + if filt(i) and (res := fetch(i)) is not _NoFetch ) @override diff --git a/src/pacman/utils/type_resolve.py b/src/pacman/utils/type_resolve.py index 1367910..7b9d8b3 100644 --- a/src/pacman/utils/type_resolve.py +++ b/src/pacman/utils/type_resolve.py @@ -5,16 +5,10 @@ import typing from collections.abc import Iterable from typing import ( Any, - cast, get_args, get_origin, ) -from pacman.utils.variadics_please import ( - RecursiveTuple, - recursive_tuple_create, -) - def map_type_generics(ty: Any, mapping: dict[Any, type]) -> Any: """Map generics for this type, maybe creating a new type.""" @@ -46,20 +40,6 @@ def resolve_type_aliases(ty: Any) -> Any: ) -def resolve_ty_to_tup[T]( - tup: type[RecursiveTuple[T]], -) -> RecursiveTuple[type[T]]: - def inner( - ty: type[RecursiveTuple[T]], - ) -> type[T] | tuple[type[RecursiveTuple[T]], ...]: - base = get_origin(ty) - if base is tuple: - return cast(tuple[type[RecursiveTuple[T]], ...], get_args(ty)) - return cast(type[T], ty) - - return recursive_tuple_create(tup, inner) - - def origin_or_cls(ty: Any) -> Any: res = get_origin(ty) if res is None: @@ -74,4 +54,4 @@ type A[T] = list[tuple[T, B[int]]] if __name__ == "__main__": ty = tuple[int, tuple[float, str], tuple[int, int] | float] print(ty) - print(resolve_ty_to_tup(resolve_type_aliases(ty))) + print(resolve_type_aliases(ty))