type QueryFilters = RecursiveTuple[QueryFilter]
+class _NoFetchCls:
+ pass
+
+
+_NoFetch = _NoFetchCls()
+
+
class QueryItem(QueryFilter):
@override
@classmethod
@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):
@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
) -> 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(
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:
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)
return False
cond = composed_by(cond, curr, bool.__and__)
if cond is None:
- return lambda _: True
+ return True
return cond
def union_constructor(
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)
@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
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."""
)
-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:
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))