{-# LANGUAGE AllowAmbiguousTypes #-}

module Mischief.ECS.World.Query.QueryFilter where

import Data.Data
import Data.Maybe
import Data.Set qualified as Set
import GHC.Base (eqWord#, isTrue#, (/=#))
import Mischief.ECS.Collectable
import Mischief.ECS.Components
import Mischief.ECS.Components.BundleTypes
import Mischief.ECS.Entities
import Mischief.ECS.EntityDef
import Mischief.ECS.World
import Mischief.ECS.World.Query.Queryable

-- newtype QueryFilters = QueryFilters [QueryFilter] deriving newtype (Semigroup)

qfChangedF :: ComponentTicks -> Tick -> Tick -> Bool
qfChangedF :: ComponentTicks -> Tick -> Tick -> Bool
qfChangedF ComponentTicks
ticks Tick
lastSystemTick Tick
currentSystemTick = ComponentTicks
ticks.changed Tick -> Tick -> Bool
forall a. Ord a => a -> a -> Bool
>= Tick
lastSystemTick Bool -> Bool -> Bool
&& ComponentTicks
ticks.changed Tick -> Tick -> Bool
forall a. Ord a => a -> a -> Bool
< Tick
currentSystemTick

qfAddedF :: ComponentTicks -> Tick -> Tick -> Bool
qfAddedF :: ComponentTicks -> Tick -> Tick -> Bool
qfAddedF ComponentTicks
ticks Tick
lastSystemTick Tick
currentSystemTick = ComponentTicks
ticks.added Tick -> Tick -> Bool
forall a. Ord a => a -> a -> Bool
>= Tick
lastSystemTick Bool -> Bool -> Bool
&& ComponentTicks
ticks.added Tick -> Tick -> Bool
forall a. Ord a => a -> a -> Bool
< Tick
currentSystemTick

data QueryFilter
  = NoFilter
  | QFWith (TypeRep, Maybe Entity)
  | QFWithRelAny TypeRep
  | QFChanged (TypeRep, Maybe Entity) (ComponentTicks -> Tick -> Tick -> Bool)
  | QFChangedRelAny TypeRep (ComponentTicks -> Tick -> Tick -> Bool)
  | QFCheckRaw (TypeRep, Maybe Entity, ErasedCheck)
  | QFCheckRawRelAny (TypeRep, ErasedCheck)
  | QFNot QueryFilter
  | QFAnd QueryFilter QueryFilter
  | QFOr QueryFilter QueryFilter

instance Semigroup QueryFilter where
  (<>) :: QueryFilter -> QueryFilter -> QueryFilter
  <> :: QueryFilter -> QueryFilter -> QueryFilter
(<>) = QueryFilter -> QueryFilter -> QueryFilter
QFAnd

instance {-# OVERLAPPING #-} EraseIntoStorage QueryFilter QueryFilter where
  erase :: QueryFilter -> QueryFilter
erase = QueryFilter -> QueryFilter
forall a. a -> a
id

instance (IntoQueryFilter q) => EraseIntoStorage q QueryFilter where
  erase :: q -> QueryFilter
erase = q -> QueryFilter
forall q. IntoQueryFilter q => q -> QueryFilter
intoQueryFilter

data ErasedCheck where
  ErasedCheck :: (Component c) => (c -> Bool) -> ErasedCheck

instance Show ErasedCheck where
  show :: ErasedCheck -> String
show ErasedCheck
_ = String
"erased check"

and' :: [QueryFilter] -> QueryFilter
and' :: [QueryFilter] -> QueryFilter
and' [QueryFilter
x] = QueryFilter
x
and' [QueryFilter]
x = (QueryFilter -> QueryFilter -> QueryFilter)
-> QueryFilter -> [QueryFilter] -> QueryFilter
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr QueryFilter -> QueryFilter -> QueryFilter
QFAnd QueryFilter
NoFilter [QueryFilter]
x

filterArchetype :: QueryFilter -> [ComponentId] -> World -> IO Bool
filterArchetype :: QueryFilter -> [ComponentId] -> World -> IO Bool
filterArchetype QueryFilter
NoFilter [ComponentId]
_ World
_ = Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
filterArchetype (QFWith (TypeRep
x, Maybe Entity
entity)) [ComponentId]
components World
world = do
  component <- (ComponentId -> ComponentId)
-> Maybe ComponentId -> Maybe ComponentId
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Maybe Entity -> ComponentId -> ComponentId
setCompIdTarget Maybe Entity
entity) (Maybe ComponentId -> Maybe ComponentId)
-> IO (Maybe ComponentId) -> IO (Maybe ComponentId)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TypeRep -> Components -> IO (Maybe ComponentId)
getComponentId TypeRep
x World
world.components
  return $ case component of
    Maybe ComponentId
Nothing -> Bool
False
    Just ComponentId
component -> ComponentId
component ComponentId -> [ComponentId] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [ComponentId]
components
filterArchetype (QFWithRelAny TypeRep
x) [ComponentId]
components World
world = do
  component <- TypeRep -> Components -> IO (Maybe ComponentId)
getComponentId TypeRep
x World
world.components
  case component of
    Maybe ComponentId
Nothing -> Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
    Just (ComponentId (# Word#
id, Maybe Entity
_ #)) -> do
      Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> IO Bool) -> Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ (ComponentId -> Bool) -> [ComponentId] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\(ComponentId (# Word#
id', Maybe Entity
a #)) -> Maybe Entity -> Bool
forall a. Maybe a -> Bool
isJust Maybe Entity
a Bool -> Bool -> Bool
&& Int# -> Bool
isTrue# (Word# -> Word# -> Int#
eqWord# Word#
id' Word#
id)) [ComponentId]
components
filterArchetype (QueryFilter
a `QFAnd` QueryFilter
b) [ComponentId]
c World
w = do
  x <- QueryFilter -> [ComponentId] -> World -> IO Bool
filterArchetype QueryFilter
a [ComponentId]
c World
w
  y <- filterArchetype b c w
  return $ x && y
filterArchetype (QueryFilter
a `QFOr` QueryFilter
b) [ComponentId]
c World
w = do
  x <- QueryFilter -> [ComponentId] -> World -> IO Bool
filterArchetype QueryFilter
a [ComponentId]
c World
w
  y <- filterArchetype b c w
  return $ x || y
filterArchetype (QFNot QueryFilter
a) [ComponentId]
c World
w = Bool -> Bool
not (Bool -> Bool) -> IO Bool -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> QueryFilter -> [ComponentId] -> World -> IO Bool
filterArchetype QueryFilter
a [ComponentId]
c World
w
filterArchetype QueryFilter
_ [ComponentId]
_ World
_ = Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True

-- | Extracts archetype-level filters from the bigger filter where possible, to be applied at the start of querying for better performance.
extractArchetypeFilters :: QueryFilter -> (QueryFilter, QueryFilter)
extractArchetypeFilters :: QueryFilter -> (QueryFilter, QueryFilter)
extractArchetypeFilters QueryFilter
NoFilter = (QueryFilter
NoFilter, QueryFilter
NoFilter)
extractArchetypeFilters (QFWith (TypeRep, Maybe Entity)
x) = (QueryFilter
NoFilter, (TypeRep, Maybe Entity) -> QueryFilter
QFWith (TypeRep, Maybe Entity)
x)
extractArchetypeFilters (QFWithRelAny TypeRep
x) = (QueryFilter
NoFilter, TypeRep -> QueryFilter
QFWithRelAny TypeRep
x)
extractArchetypeFilters (QFChanged (TypeRep, Maybe Entity)
x ComponentTicks -> Tick -> Tick -> Bool
f) = ((TypeRep, Maybe Entity)
-> (ComponentTicks -> Tick -> Tick -> Bool) -> QueryFilter
QFChanged (TypeRep, Maybe Entity)
x ComponentTicks -> Tick -> Tick -> Bool
f, QueryFilter
NoFilter)
extractArchetypeFilters (QFChangedRelAny TypeRep
x ComponentTicks -> Tick -> Tick -> Bool
f) = (TypeRep -> (ComponentTicks -> Tick -> Tick -> Bool) -> QueryFilter
QFChangedRelAny TypeRep
x ComponentTicks -> Tick -> Tick -> Bool
f, QueryFilter
NoFilter)
extractArchetypeFilters (QFCheckRaw (TypeRep, Maybe Entity, ErasedCheck)
x) = ((TypeRep, Maybe Entity, ErasedCheck) -> QueryFilter
QFCheckRaw (TypeRep, Maybe Entity, ErasedCheck)
x, QueryFilter
NoFilter)
extractArchetypeFilters (QFCheckRawRelAny (TypeRep, ErasedCheck)
x) = ((TypeRep, ErasedCheck) -> QueryFilter
QFCheckRawRelAny (TypeRep, ErasedCheck)
x, QueryFilter
NoFilter)
extractArchetypeFilters (QueryFilter
a `QFAnd` QueryFilter
b) = (QueryFilter
filter1 QueryFilter -> QueryFilter -> QueryFilter
`QFAnd` QueryFilter
filter2, QueryFilter
res1 QueryFilter -> QueryFilter -> QueryFilter
`QFAnd` QueryFilter
res2)
  where
    (QueryFilter
filter1, QueryFilter
res1) = QueryFilter -> (QueryFilter, QueryFilter)
extractArchetypeFilters QueryFilter
a
    (QueryFilter
filter2, QueryFilter
res2) = QueryFilter -> (QueryFilter, QueryFilter)
extractArchetypeFilters QueryFilter
b
extractArchetypeFilters (QueryFilter
a `QFOr` QueryFilter
b) =
  if QueryFilter -> Bool
isArchetypeFilter QueryFilter
a Bool -> Bool -> Bool
&& QueryFilter -> Bool
isArchetypeFilter QueryFilter
b
    then
      (QueryFilter
filter1 QueryFilter -> QueryFilter -> QueryFilter
`QFOr` QueryFilter
filter2, QueryFilter
res1 QueryFilter -> QueryFilter -> QueryFilter
`QFOr` QueryFilter
res2)
    else
      (QueryFilter
a QueryFilter -> QueryFilter -> QueryFilter
`QFOr` QueryFilter
b, QueryFilter
NoFilter)
  where
    (QueryFilter
filter1, QueryFilter
res1) = QueryFilter -> (QueryFilter, QueryFilter)
extractArchetypeFilters QueryFilter
a
    (QueryFilter
filter2, QueryFilter
res2) = QueryFilter -> (QueryFilter, QueryFilter)
extractArchetypeFilters QueryFilter
b
extractArchetypeFilters (QFNot QueryFilter
a) = (QueryFilter -> QueryFilter
QFNot QueryFilter
x, QueryFilter -> QueryFilter
QFNot QueryFilter
y)
  where
    (QueryFilter
x, QueryFilter
y) = QueryFilter -> (QueryFilter, QueryFilter)
extractArchetypeFilters QueryFilter
a

isArchetypeFilter :: QueryFilter -> Bool
isArchetypeFilter :: QueryFilter -> Bool
isArchetypeFilter QueryFilter
NoFilter = Bool
True
isArchetypeFilter (QFChanged (TypeRep, Maybe Entity)
_ ComponentTicks -> Tick -> Tick -> Bool
_) = Bool
False
isArchetypeFilter (QFChangedRelAny TypeRep
_ ComponentTicks -> Tick -> Tick -> Bool
_) = Bool
False
isArchetypeFilter (QFWith (TypeRep, Maybe Entity)
_) = Bool
True
isArchetypeFilter (QFWithRelAny TypeRep
_) = Bool
True
isArchetypeFilter (QueryFilter
a `QFAnd` QueryFilter
b) = QueryFilter -> Bool
isArchetypeFilter QueryFilter
a Bool -> Bool -> Bool
|| QueryFilter -> Bool
isArchetypeFilter QueryFilter
b
isArchetypeFilter (QueryFilter
a `QFOr` QueryFilter
b) = QueryFilter -> Bool
isArchetypeFilter QueryFilter
a Bool -> Bool -> Bool
&& QueryFilter -> Bool
isArchetypeFilter QueryFilter
b
isArchetypeFilter (QFCheckRaw (TypeRep, Maybe Entity, ErasedCheck)
_) = Bool
False
isArchetypeFilter (QFCheckRawRelAny (TypeRep, ErasedCheck)
_) = Bool
False
isArchetypeFilter (QFNot QueryFilter
a) = QueryFilter -> Bool
isArchetypeFilter QueryFilter
a

preprocessFilter :: QueryFilter -> QueryFilter
preprocessFilter :: QueryFilter -> QueryFilter
preprocessFilter = QueryFilter -> QueryFilter
propagateQFNot

propagateQFNot :: QueryFilter -> QueryFilter
propagateQFNot :: QueryFilter -> QueryFilter
propagateQFNot (QFNot QueryFilter
NoFilter) = QueryFilter
NoFilter
propagateQFNot (QFNot (QFNot QueryFilter
a)) = QueryFilter -> QueryFilter
propagateQFNot QueryFilter
a
propagateQFNot (QFNot (QueryFilter
a `QFAnd` QueryFilter
b)) = QueryFilter -> QueryFilter
propagateQFNot (QueryFilter -> QueryFilter
QFNot QueryFilter
a) QueryFilter -> QueryFilter -> QueryFilter
`QFOr` QueryFilter -> QueryFilter
propagateQFNot (QueryFilter -> QueryFilter
QFNot QueryFilter
b)
propagateQFNot (QFNot (QueryFilter
a `QFOr` QueryFilter
b)) = QueryFilter -> QueryFilter
propagateQFNot (QueryFilter -> QueryFilter
QFNot QueryFilter
a) QueryFilter -> QueryFilter -> QueryFilter
`QFAnd` QueryFilter -> QueryFilter
propagateQFNot (QueryFilter -> QueryFilter
QFNot QueryFilter
b)
propagateQFNot (QueryFilter
a `QFAnd` QueryFilter
b) = QueryFilter -> QueryFilter
propagateQFNot QueryFilter
a QueryFilter -> QueryFilter -> QueryFilter
`QFAnd` QueryFilter -> QueryFilter
propagateQFNot QueryFilter
b
propagateQFNot (QueryFilter
a `QFOr` QueryFilter
b) = QueryFilter -> QueryFilter
propagateQFNot QueryFilter
a QueryFilter -> QueryFilter -> QueryFilter
`QFOr` QueryFilter -> QueryFilter
propagateQFNot QueryFilter
b
propagateQFNot QueryFilter
x = QueryFilter
x

class IntoQueryFilter qf where
  intoQueryFilter :: qf -> QueryFilter

newtype With c = With c

instance (Collectable c FilterType) => IntoQueryFilter (With c) where
  intoQueryFilter :: With c -> QueryFilter
intoQueryFilter (With c
c) =
    let FilterType
l :: FilterType = c -> FilterType
forall v storage. Collectable v storage => v -> storage
collect c
c
     in [QueryFilter] -> QueryFilter
and' ([QueryFilter] -> QueryFilter) -> [QueryFilter] -> QueryFilter
forall a b. (a -> b) -> a -> b
$ ((TypeRep, Maybe Entity, Maybe Any) -> QueryFilter)
-> [(TypeRep, Maybe Entity, Maybe Any)] -> [QueryFilter]
forall a b. (a -> b) -> [a] -> [b]
map (TypeRep, Maybe Entity, Maybe Any) -> QueryFilter
withF FilterType
l.inner

newtype Without c = Without c

instance (Collectable c FilterType) => IntoQueryFilter (Without c) where
  intoQueryFilter :: Without c -> QueryFilter
intoQueryFilter (Without c
c) =
    let FilterType
l :: FilterType = c -> FilterType
forall v storage. Collectable v storage => v -> storage
collect c
c
     in [QueryFilter] -> QueryFilter
and' ([QueryFilter] -> QueryFilter) -> [QueryFilter] -> QueryFilter
forall a b. (a -> b) -> a -> b
$ ((TypeRep, Maybe Entity, Maybe Any) -> QueryFilter)
-> [(TypeRep, Maybe Entity, Maybe Any)] -> [QueryFilter]
forall a b. (a -> b) -> [a] -> [b]
map (QueryFilter -> QueryFilter
QFNot (QueryFilter -> QueryFilter)
-> ((TypeRep, Maybe Entity, Maybe Any) -> QueryFilter)
-> (TypeRep, Maybe Entity, Maybe Any)
-> QueryFilter
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TypeRep, Maybe Entity, Maybe Any) -> QueryFilter
withF) FilterType
l.inner

newtype Not c = Not c

instance (IntoQueryFilter q) => IntoQueryFilter (Not q) where
  intoQueryFilter :: Not q -> QueryFilter
intoQueryFilter (Not q
a) = QueryFilter -> QueryFilter
QFNot (QueryFilter -> QueryFilter) -> QueryFilter -> QueryFilter
forall a b. (a -> b) -> a -> b
$ q -> QueryFilter
forall q. IntoQueryFilter q => q -> QueryFilter
intoQueryFilter q
a

data Or a b = Or a b

(|.) :: a -> b -> Or a b
|. :: forall a b. a -> b -> Or a b
(|.) = a -> b -> Or a b
forall a b. a -> b -> Or a b
Or

data And a b = And a b

(&.) :: a -> b -> And a b
&. :: forall a b. a -> b -> And a b
(&.) = a -> b -> And a b
forall a b. a -> b -> And a b
And

infix 8 &.

infix 9 |.

instance (IntoQueryFilter a, IntoQueryFilter b) => IntoQueryFilter (a `Or` b) where
  intoQueryFilter :: Or a b -> QueryFilter
intoQueryFilter (Or a
a b
b) = QueryFilter -> QueryFilter -> QueryFilter
QFOr (a -> QueryFilter
forall q. IntoQueryFilter q => q -> QueryFilter
intoQueryFilter a
a) (b -> QueryFilter
forall q. IntoQueryFilter q => q -> QueryFilter
intoQueryFilter b
b)

instance (IntoQueryFilter a, IntoQueryFilter b) => IntoQueryFilter (a `And` b) where
  intoQueryFilter :: And a b -> QueryFilter
intoQueryFilter (And a
a b
b) = QueryFilter -> QueryFilter -> QueryFilter
QFAnd (a -> QueryFilter
forall q. IntoQueryFilter q => q -> QueryFilter
intoQueryFilter a
a) (b -> QueryFilter
forall q. IntoQueryFilter q => q -> QueryFilter
intoQueryFilter b
b)

newtype Changed c = Changed c

instance (Collectable c FilterType) => IntoQueryFilter (Changed c) where
  intoQueryFilter :: Changed c -> QueryFilter
intoQueryFilter (Changed c
c) =
    let FilterType
l :: FilterType = c -> FilterType
forall v storage. Collectable v storage => v -> storage
collect c
c
     in [QueryFilter] -> QueryFilter
and' ([QueryFilter] -> QueryFilter) -> [QueryFilter] -> QueryFilter
forall a b. (a -> b) -> a -> b
$ ((TypeRep, Maybe Entity, Maybe Any) -> QueryFilter)
-> [(TypeRep, Maybe Entity, Maybe Any)] -> [QueryFilter]
forall a b. (a -> b) -> [a] -> [b]
map (TypeRep, Maybe Entity, Maybe Any) -> QueryFilter
changedF FilterType
l.inner

newtype Added c = Added c

instance (Collectable c FilterType) => IntoQueryFilter (Added c) where
  intoQueryFilter :: Added c -> QueryFilter
intoQueryFilter (Added c
c) =
    let FilterType
l :: FilterType = c -> FilterType
forall v storage. Collectable v storage => v -> storage
collect c
c
     in [QueryFilter] -> QueryFilter
and' ([QueryFilter] -> QueryFilter) -> [QueryFilter] -> QueryFilter
forall a b. (a -> b) -> a -> b
$ ((TypeRep, Maybe Entity, Maybe Any) -> QueryFilter)
-> [(TypeRep, Maybe Entity, Maybe Any)] -> [QueryFilter]
forall a b. (a -> b) -> [a] -> [b]
map (TypeRep, Maybe Entity, Maybe Any) -> QueryFilter
addedF FilterType
l.inner

newtype Check c = Check (c -> Bool)

instance (Component c) => IntoQueryFilter (Check c) where
  intoQueryFilter :: Check c -> QueryFilter
intoQueryFilter (Check c -> Bool
f) = (TypeRep, Maybe Entity, Maybe Any, ErasedCheck) -> QueryFilter
checkF (Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c, Maybe Entity
forall a. Maybe a
Nothing, Maybe Any
forall a. Maybe a
Nothing, (c -> Bool) -> ErasedCheck
forall c. Component c => (c -> Bool) -> ErasedCheck
ErasedCheck c -> Bool
f)

data CheckR e c = CheckR e (c -> Bool)

instance (Component c) => IntoQueryFilter (CheckR Entity c) where
  intoQueryFilter :: CheckR Entity c -> QueryFilter
intoQueryFilter (CheckR Entity
e c -> Bool
f) = (TypeRep, Maybe Entity, Maybe Any, ErasedCheck) -> QueryFilter
checkF (Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c, Entity -> Maybe Entity
forall a. a -> Maybe a
Just Entity
e, Maybe Any
forall a. Maybe a
Nothing, (c -> Bool) -> ErasedCheck
forall c. Component c => (c -> Bool) -> ErasedCheck
ErasedCheck c -> Bool
f)

instance (Component c) => IntoQueryFilter (CheckR Any c) where
  intoQueryFilter :: CheckR Any c -> QueryFilter
intoQueryFilter (CheckR Any
_ c -> Bool
f) = (TypeRep, Maybe Entity, Maybe Any, ErasedCheck) -> QueryFilter
checkF (Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c, Maybe Entity
forall a. Maybe a
Nothing, Any -> Maybe Any
forall a. a -> Maybe a
Just Any
Any, (c -> Bool) -> ErasedCheck
forall c. Component c => (c -> Bool) -> ErasedCheck
ErasedCheck c -> Bool
f)

withF :: (TypeRep, Maybe Entity, Maybe Any) -> QueryFilter
withF :: (TypeRep, Maybe Entity, Maybe Any) -> QueryFilter
withF (TypeRep
c, Maybe Entity
e, Maybe Any
Nothing) = (TypeRep, Maybe Entity) -> QueryFilter
QFWith (TypeRep
c, Maybe Entity
e)
withF (TypeRep
c, Maybe Entity
_, Maybe Any
_) = TypeRep -> QueryFilter
QFWithRelAny TypeRep
c

addedF :: (TypeRep, Maybe Entity, Maybe Any) -> QueryFilter
addedF :: (TypeRep, Maybe Entity, Maybe Any) -> QueryFilter
addedF (TypeRep
c, Maybe Entity
e, Maybe Any
Nothing) = (TypeRep, Maybe Entity) -> QueryFilter
QFWith (TypeRep
c, Maybe Entity
e) QueryFilter -> QueryFilter -> QueryFilter
`QFAnd` (TypeRep, Maybe Entity)
-> (ComponentTicks -> Tick -> Tick -> Bool) -> QueryFilter
QFChanged (TypeRep
c, Maybe Entity
e) ComponentTicks -> Tick -> Tick -> Bool
qfAddedF
addedF (TypeRep
c, Maybe Entity
_, Maybe Any
_) = TypeRep -> QueryFilter
QFWithRelAny TypeRep
c QueryFilter -> QueryFilter -> QueryFilter
`QFAnd` TypeRep -> (ComponentTicks -> Tick -> Tick -> Bool) -> QueryFilter
QFChangedRelAny TypeRep
c ComponentTicks -> Tick -> Tick -> Bool
qfAddedF

changedF :: (TypeRep, Maybe Entity, Maybe Any) -> QueryFilter
changedF :: (TypeRep, Maybe Entity, Maybe Any) -> QueryFilter
changedF (TypeRep
c, Maybe Entity
e, Maybe Any
Nothing) = (TypeRep, Maybe Entity) -> QueryFilter
QFWith (TypeRep
c, Maybe Entity
e) QueryFilter -> QueryFilter -> QueryFilter
`QFAnd` (TypeRep, Maybe Entity)
-> (ComponentTicks -> Tick -> Tick -> Bool) -> QueryFilter
QFChanged (TypeRep
c, Maybe Entity
e) ComponentTicks -> Tick -> Tick -> Bool
qfChangedF
changedF (TypeRep
c, Maybe Entity
_, Maybe Any
_) = TypeRep -> QueryFilter
QFWithRelAny TypeRep
c QueryFilter -> QueryFilter -> QueryFilter
`QFAnd` TypeRep -> (ComponentTicks -> Tick -> Tick -> Bool) -> QueryFilter
QFChangedRelAny TypeRep
c ComponentTicks -> Tick -> Tick -> Bool
qfChangedF

checkF :: (TypeRep, Maybe Entity, Maybe Any, ErasedCheck) -> QueryFilter
checkF :: (TypeRep, Maybe Entity, Maybe Any, ErasedCheck) -> QueryFilter
checkF (TypeRep
c, Maybe Entity
e, Maybe Any
Nothing, ErasedCheck
f) = (TypeRep, Maybe Entity) -> QueryFilter
QFWith (TypeRep
c, Maybe Entity
e) QueryFilter -> QueryFilter -> QueryFilter
`QFAnd` (TypeRep, Maybe Entity, ErasedCheck) -> QueryFilter
QFCheckRaw (TypeRep
c, Maybe Entity
e, ErasedCheck
f)
checkF (TypeRep
c, Maybe Entity
_, Maybe Any
_, ErasedCheck
f) = TypeRep -> QueryFilter
QFWithRelAny TypeRep
c QueryFilter -> QueryFilter -> QueryFilter
`QFAnd` (TypeRep, ErasedCheck) -> QueryFilter
QFCheckRawRelAny (TypeRep
c, ErasedCheck
f)

newtype FilterType = FilterType {FilterType -> [(TypeRep, Maybe Entity, Maybe Any)]
inner :: [(TypeRep, Maybe Entity, Maybe Any)]} deriving newtype (NonEmpty FilterType -> FilterType
FilterType -> FilterType -> FilterType
(FilterType -> FilterType -> FilterType)
-> (NonEmpty FilterType -> FilterType)
-> (forall b. Integral b => b -> FilterType -> FilterType)
-> Semigroup FilterType
forall b. Integral b => b -> FilterType -> FilterType
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
$c<> :: FilterType -> FilterType -> FilterType
<> :: FilterType -> FilterType -> FilterType
$csconcat :: NonEmpty FilterType -> FilterType
sconcat :: NonEmpty FilterType -> FilterType
$cstimes :: forall b. Integral b => b -> FilterType -> FilterType
stimes :: forall b. Integral b => b -> FilterType -> FilterType
Semigroup)

instance (Component c) => EraseIntoStorage (C c) FilterType where
  erase :: C c -> FilterType
erase C c
_ = [(TypeRep, Maybe Entity, Maybe Any)] -> FilterType
FilterType [(Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c, Maybe Entity
forall a. Maybe a
Nothing, Maybe Any
forall a. Maybe a
Nothing)]

instance (Component c) => EraseIntoStorage (R c Entity) FilterType where
  erase :: R c Entity -> FilterType
erase (R Entity
e) = [(TypeRep, Maybe Entity, Maybe Any)] -> FilterType
FilterType [(Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c, Entity -> Maybe Entity
forall a. a -> Maybe a
Just Entity
e, Maybe Any
forall a. Maybe a
Nothing)]

instance (Component c) => EraseIntoStorage (R c Any) FilterType where
  erase :: R c Any -> FilterType
erase R c Any
_ = [(TypeRep, Maybe Entity, Maybe Any)] -> FilterType
FilterType [(Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c, Maybe Entity
forall a. Maybe a
Nothing, Any -> Maybe Any
forall a. a -> Maybe a
Just Any
Any)]

newtype CheckFilterType = CheckFilterType {CheckFilterType
-> [(TypeRep, Maybe Entity, Maybe Any, ErasedCheck)]
inner :: [(TypeRep, Maybe Entity, Maybe Any, ErasedCheck)]} deriving newtype (NonEmpty CheckFilterType -> CheckFilterType
CheckFilterType -> CheckFilterType -> CheckFilterType
(CheckFilterType -> CheckFilterType -> CheckFilterType)
-> (NonEmpty CheckFilterType -> CheckFilterType)
-> (forall b.
    Integral b =>
    b -> CheckFilterType -> CheckFilterType)
-> Semigroup CheckFilterType
forall b. Integral b => b -> CheckFilterType -> CheckFilterType
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
$c<> :: CheckFilterType -> CheckFilterType -> CheckFilterType
<> :: CheckFilterType -> CheckFilterType -> CheckFilterType
$csconcat :: NonEmpty CheckFilterType -> CheckFilterType
sconcat :: NonEmpty CheckFilterType -> CheckFilterType
$cstimes :: forall b. Integral b => b -> CheckFilterType -> CheckFilterType
stimes :: forall b. Integral b => b -> CheckFilterType -> CheckFilterType
Semigroup)

instance (Component c) => EraseIntoStorage (C c, c -> Bool) CheckFilterType where
  erase :: (C c, c -> Bool) -> CheckFilterType
erase (C c
_, c -> Bool
f) = [(TypeRep, Maybe Entity, Maybe Any, ErasedCheck)]
-> CheckFilterType
CheckFilterType [(Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c, Maybe Entity
forall a. Maybe a
Nothing, Maybe Any
forall a. Maybe a
Nothing, (c -> Bool) -> ErasedCheck
forall c. Component c => (c -> Bool) -> ErasedCheck
ErasedCheck c -> Bool
f)]

instance (Component c) => EraseIntoStorage (R c Entity, c -> Bool) CheckFilterType where
  erase :: (Component c) => (R c Entity, c -> Bool) -> CheckFilterType
  erase :: Component c => (R c Entity, c -> Bool) -> CheckFilterType
erase (R Entity
e, c -> Bool
f) = [(TypeRep, Maybe Entity, Maybe Any, ErasedCheck)]
-> CheckFilterType
CheckFilterType [(Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c, Entity -> Maybe Entity
forall a. a -> Maybe a
Just Entity
e, Maybe Any
forall a. Maybe a
Nothing, (c -> Bool) -> ErasedCheck
forall c. Component c => (c -> Bool) -> ErasedCheck
ErasedCheck c -> Bool
f)]

instance (Component c) => EraseIntoStorage (R c Any, c -> Bool) CheckFilterType where
  erase :: (Component c) => (R c Any, c -> Bool) -> CheckFilterType
  erase :: Component c => (R c Any, c -> Bool) -> CheckFilterType
erase (R c Any
_, c -> Bool
f) = [(TypeRep, Maybe Entity, Maybe Any, ErasedCheck)]
-> CheckFilterType
CheckFilterType [(Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c, Maybe Entity
forall a. Maybe a
Nothing, Any -> Maybe Any
forall a. a -> Maybe a
Just Any
Any, (c -> Bool) -> ErasedCheck
forall c. Component c => (c -> Bool) -> ErasedCheck
ErasedCheck c -> Bool
f)]

type family InnerC a where
  InnerC (C (Rel a)) = a
  InnerC (C a) = a