{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}

module Aztecs.ECS.Query.Dynamic.Reader
  ( -- * Dynamic queries
    DynamicQueryReader (..),
    ArrowDynamicQueryReader (..),

    -- ** Running
    allDyn,
    runDynQueryReader,

    -- * Dynamic query filters
    DynamicQueryFilter (..),
  )
where

import Aztecs.ECS.Component
import Aztecs.ECS.Entity (EntityID)
import Aztecs.ECS.Query.Dynamic.Reader.Class (ArrowDynamicQueryReader (..))
import Aztecs.ECS.World.Archetype (Archetype)
import qualified Aztecs.ECS.World.Archetype as A
import qualified Aztecs.ECS.World.Archetypes as AS
import Aztecs.ECS.World.Entities (Entities (..))
import qualified Aztecs.ECS.World.Storage as S
import Control.Arrow
import Control.Category
import Data.Either (partitionEithers)
import qualified Data.Map as Map
import Data.Set (Set)
import qualified Data.Set as Set

-- | Dynamic query for components by ID.
newtype DynamicQueryReader i o
  = DynamicQueryReader {forall i o.
DynamicQueryReader i o -> [i] -> [EntityID] -> Archetype -> [o]
runDynQueryReader' :: [i] -> [EntityID] -> Archetype -> [o]}
  deriving ((forall a b.
 (a -> b) -> DynamicQueryReader i a -> DynamicQueryReader i b)
-> (forall a b.
    a -> DynamicQueryReader i b -> DynamicQueryReader i a)
-> Functor (DynamicQueryReader i)
forall a b. a -> DynamicQueryReader i b -> DynamicQueryReader i a
forall a b.
(a -> b) -> DynamicQueryReader i a -> DynamicQueryReader i b
forall i a b. a -> DynamicQueryReader i b -> DynamicQueryReader i a
forall i a b.
(a -> b) -> DynamicQueryReader i a -> DynamicQueryReader i b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall i a b.
(a -> b) -> DynamicQueryReader i a -> DynamicQueryReader i b
fmap :: forall a b.
(a -> b) -> DynamicQueryReader i a -> DynamicQueryReader i b
$c<$ :: forall i a b. a -> DynamicQueryReader i b -> DynamicQueryReader i a
<$ :: forall a b. a -> DynamicQueryReader i b -> DynamicQueryReader i a
Functor)

instance Applicative (DynamicQueryReader i) where
  pure :: forall a. a -> DynamicQueryReader i a
pure a
a = ([i] -> [EntityID] -> Archetype -> [a]) -> DynamicQueryReader i a
forall i o.
([i] -> [EntityID] -> Archetype -> [o]) -> DynamicQueryReader i o
DynamicQueryReader (([i] -> [EntityID] -> Archetype -> [a]) -> DynamicQueryReader i a)
-> ([i] -> [EntityID] -> Archetype -> [a])
-> DynamicQueryReader i a
forall a b. (a -> b) -> a -> b
$ \[i]
_ [EntityID]
es Archetype
_ -> Int -> a -> [a]
forall a. Int -> a -> [a]
replicate ([EntityID] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [EntityID]
es) a
a

  DynamicQueryReader i (a -> b)
f <*> :: forall a b.
DynamicQueryReader i (a -> b)
-> DynamicQueryReader i a -> DynamicQueryReader i b
<*> DynamicQueryReader i a
g =
    ([i] -> [EntityID] -> Archetype -> [b]) -> DynamicQueryReader i b
forall i o.
([i] -> [EntityID] -> Archetype -> [o]) -> DynamicQueryReader i o
DynamicQueryReader (([i] -> [EntityID] -> Archetype -> [b]) -> DynamicQueryReader i b)
-> ([i] -> [EntityID] -> Archetype -> [b])
-> DynamicQueryReader i b
forall a b. (a -> b) -> a -> b
$ \[i]
i [EntityID]
es Archetype
arch ->
      let as :: [a]
as = DynamicQueryReader i a -> [i] -> [EntityID] -> Archetype -> [a]
forall i o.
DynamicQueryReader i o -> [i] -> [EntityID] -> Archetype -> [o]
runDynQueryReader' DynamicQueryReader i a
g [i]
i [EntityID]
es Archetype
arch
          fs :: [a -> b]
fs = DynamicQueryReader i (a -> b)
-> [i] -> [EntityID] -> Archetype -> [a -> b]
forall i o.
DynamicQueryReader i o -> [i] -> [EntityID] -> Archetype -> [o]
runDynQueryReader' DynamicQueryReader i (a -> b)
f [i]
i [EntityID]
es Archetype
arch
       in ((a -> b) -> a -> b) -> [a -> b] -> [a] -> [b]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (a -> b) -> a -> b
forall a b. (a -> b) -> a -> b
($) [a -> b]
fs [a]
as

instance Category DynamicQueryReader where
  id :: forall a. DynamicQueryReader a a
id = ([a] -> [EntityID] -> Archetype -> [a]) -> DynamicQueryReader a a
forall i o.
([i] -> [EntityID] -> Archetype -> [o]) -> DynamicQueryReader i o
DynamicQueryReader (([a] -> [EntityID] -> Archetype -> [a]) -> DynamicQueryReader a a)
-> ([a] -> [EntityID] -> Archetype -> [a])
-> DynamicQueryReader a a
forall a b. (a -> b) -> a -> b
$ \[a]
as [EntityID]
_ Archetype
_ -> [a]
as
  DynamicQueryReader b c
f . :: forall b c a.
DynamicQueryReader b c
-> DynamicQueryReader a b -> DynamicQueryReader a c
. DynamicQueryReader a b
g = ([a] -> [EntityID] -> Archetype -> [c]) -> DynamicQueryReader a c
forall i o.
([i] -> [EntityID] -> Archetype -> [o]) -> DynamicQueryReader i o
DynamicQueryReader (([a] -> [EntityID] -> Archetype -> [c]) -> DynamicQueryReader a c)
-> ([a] -> [EntityID] -> Archetype -> [c])
-> DynamicQueryReader a c
forall a b. (a -> b) -> a -> b
$ \[a]
i [EntityID]
es Archetype
arch ->
    let as :: [b]
as = DynamicQueryReader a b -> [a] -> [EntityID] -> Archetype -> [b]
forall i o.
DynamicQueryReader i o -> [i] -> [EntityID] -> Archetype -> [o]
runDynQueryReader' DynamicQueryReader a b
g [a]
i [EntityID]
es Archetype
arch in DynamicQueryReader b c -> [b] -> [EntityID] -> Archetype -> [c]
forall i o.
DynamicQueryReader i o -> [i] -> [EntityID] -> Archetype -> [o]
runDynQueryReader' DynamicQueryReader b c
f [b]
as [EntityID]
es Archetype
arch

instance Arrow DynamicQueryReader where
  arr :: forall b c. (b -> c) -> DynamicQueryReader b c
arr b -> c
f = ([b] -> [EntityID] -> Archetype -> [c]) -> DynamicQueryReader b c
forall i o.
([i] -> [EntityID] -> Archetype -> [o]) -> DynamicQueryReader i o
DynamicQueryReader (([b] -> [EntityID] -> Archetype -> [c]) -> DynamicQueryReader b c)
-> ([b] -> [EntityID] -> Archetype -> [c])
-> DynamicQueryReader b c
forall a b. (a -> b) -> a -> b
$ \[b]
bs [EntityID]
_ Archetype
_ -> (b -> c) -> [b] -> [c]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap b -> c
f [b]
bs
  first :: forall b c d.
DynamicQueryReader b c -> DynamicQueryReader (b, d) (c, d)
first DynamicQueryReader b c
f = ([(b, d)] -> [EntityID] -> Archetype -> [(c, d)])
-> DynamicQueryReader (b, d) (c, d)
forall i o.
([i] -> [EntityID] -> Archetype -> [o]) -> DynamicQueryReader i o
DynamicQueryReader (([(b, d)] -> [EntityID] -> Archetype -> [(c, d)])
 -> DynamicQueryReader (b, d) (c, d))
-> ([(b, d)] -> [EntityID] -> Archetype -> [(c, d)])
-> DynamicQueryReader (b, d) (c, d)
forall a b. (a -> b) -> a -> b
$ \[(b, d)]
bds [EntityID]
es Archetype
arch ->
    let ([b]
bs, [d]
ds) = [(b, d)] -> ([b], [d])
forall a b. [(a, b)] -> ([a], [b])
unzip [(b, d)]
bds
        cs :: [c]
cs = DynamicQueryReader b c -> [b] -> [EntityID] -> Archetype -> [c]
forall i o.
DynamicQueryReader i o -> [i] -> [EntityID] -> Archetype -> [o]
runDynQueryReader' DynamicQueryReader b c
f [b]
bs [EntityID]
es Archetype
arch
     in [c] -> [d] -> [(c, d)]
forall a b. [a] -> [b] -> [(a, b)]
zip [c]
cs [d]
ds

instance ArrowChoice DynamicQueryReader where
  left :: forall b c d.
DynamicQueryReader b c
-> DynamicQueryReader (Either b d) (Either c d)
left DynamicQueryReader b c
f = ([Either b d] -> [EntityID] -> Archetype -> [Either c d])
-> DynamicQueryReader (Either b d) (Either c d)
forall i o.
([i] -> [EntityID] -> Archetype -> [o]) -> DynamicQueryReader i o
DynamicQueryReader (([Either b d] -> [EntityID] -> Archetype -> [Either c d])
 -> DynamicQueryReader (Either b d) (Either c d))
-> ([Either b d] -> [EntityID] -> Archetype -> [Either c d])
-> DynamicQueryReader (Either b d) (Either c d)
forall a b. (a -> b) -> a -> b
$ \[Either b d]
eds [EntityID]
es Archetype
arch ->
    let ([b]
es', [d]
ds) = [Either b d] -> ([b], [d])
forall a b. [Either a b] -> ([a], [b])
partitionEithers [Either b d]
eds
        cs :: [c]
cs = DynamicQueryReader b c -> [b] -> [EntityID] -> Archetype -> [c]
forall i o.
DynamicQueryReader i o -> [i] -> [EntityID] -> Archetype -> [o]
runDynQueryReader' DynamicQueryReader b c
f [b]
es' [EntityID]
es Archetype
arch
     in (c -> Either c d) -> [c] -> [Either c d]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap c -> Either c d
forall a b. a -> Either a b
Left [c]
cs [Either c d] -> [Either c d] -> [Either c d]
forall a. [a] -> [a] -> [a]
++ (d -> Either c d) -> [d] -> [Either c d]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap d -> Either c d
forall a b. b -> Either a b
Right [d]
ds

instance ArrowDynamicQueryReader DynamicQueryReader where
  entity :: DynamicQueryReader () EntityID
entity = ([()] -> [EntityID] -> Archetype -> [EntityID])
-> DynamicQueryReader () EntityID
forall i o.
([i] -> [EntityID] -> Archetype -> [o]) -> DynamicQueryReader i o
DynamicQueryReader (([()] -> [EntityID] -> Archetype -> [EntityID])
 -> DynamicQueryReader () EntityID)
-> ([()] -> [EntityID] -> Archetype -> [EntityID])
-> DynamicQueryReader () EntityID
forall a b. (a -> b) -> a -> b
$ \[()]
_ [EntityID]
es Archetype
_ -> [EntityID]
es
  fetchDyn :: forall a. (Component a) => ComponentID -> DynamicQueryReader () a
  fetchDyn :: forall a. Component a => ComponentID -> DynamicQueryReader () a
fetchDyn ComponentID
cId = ([()] -> [EntityID] -> Archetype -> [a]) -> DynamicQueryReader () a
forall i o.
([i] -> [EntityID] -> Archetype -> [o]) -> DynamicQueryReader i o
DynamicQueryReader (([()] -> [EntityID] -> Archetype -> [a])
 -> DynamicQueryReader () a)
-> ([()] -> [EntityID] -> Archetype -> [a])
-> DynamicQueryReader () a
forall a b. (a -> b) -> a -> b
$ \[()]
_ [EntityID]
_ Archetype
arch ->
    [a] -> (StorageT a -> [a]) -> Maybe (StorageT a) -> [a]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] (forall a s. Storage a s => s -> [a]
S.toAscList @a @(StorageT a)) (forall a.
Component a =>
ComponentID -> Archetype -> Maybe (StorageT a)
A.lookupStorage @a ComponentID
cId Archetype
arch)
  fetchMaybeDyn :: forall a. (Component a) => ComponentID -> DynamicQueryReader () (Maybe a)
  fetchMaybeDyn :: forall a.
Component a =>
ComponentID -> DynamicQueryReader () (Maybe a)
fetchMaybeDyn ComponentID
cId = ([()] -> [EntityID] -> Archetype -> [Maybe a])
-> DynamicQueryReader () (Maybe a)
forall i o.
([i] -> [EntityID] -> Archetype -> [o]) -> DynamicQueryReader i o
DynamicQueryReader (([()] -> [EntityID] -> Archetype -> [Maybe a])
 -> DynamicQueryReader () (Maybe a))
-> ([()] -> [EntityID] -> Archetype -> [Maybe a])
-> DynamicQueryReader () (Maybe a)
forall a b. (a -> b) -> a -> b
$ \[()]
_ [EntityID]
es Archetype
arch -> case forall a.
Component a =>
ComponentID -> Archetype -> Maybe (StorageT a)
A.lookupStorage @a ComponentID
cId Archetype
arch of
    Just StorageT a
s -> let !as :: [a]
as = forall a s. Storage a s => s -> [a]
S.toAscList @a @(StorageT a) StorageT a
s in (a -> Maybe a) -> [a] -> [Maybe a]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Maybe a
forall a. a -> Maybe a
Just [a]
as
    Maybe (StorageT a)
Nothing -> (EntityID -> Maybe a) -> [EntityID] -> [Maybe a]
forall a b. (a -> b) -> [a] -> [b]
map (Maybe a -> EntityID -> Maybe a
forall a b. a -> b -> a
const Maybe a
forall a. Maybe a
Nothing) [EntityID]
es

data DynamicQueryFilter = DynamicQueryFilter
  { DynamicQueryFilter -> Set ComponentID
filterWith :: !(Set ComponentID),
    DynamicQueryFilter -> Set ComponentID
filterWithout :: !(Set ComponentID)
  }

instance Semigroup DynamicQueryFilter where
  DynamicQueryFilter Set ComponentID
withA Set ComponentID
withoutA <> :: DynamicQueryFilter -> DynamicQueryFilter -> DynamicQueryFilter
<> DynamicQueryFilter Set ComponentID
withB Set ComponentID
withoutB =
    Set ComponentID -> Set ComponentID -> DynamicQueryFilter
DynamicQueryFilter (Set ComponentID
withA Set ComponentID -> Set ComponentID -> Set ComponentID
forall a. Semigroup a => a -> a -> a
<> Set ComponentID
withB) (Set ComponentID
withoutA Set ComponentID -> Set ComponentID -> Set ComponentID
forall a. Semigroup a => a -> a -> a
<> Set ComponentID
withoutB)

instance Monoid DynamicQueryFilter where
  mempty :: DynamicQueryFilter
mempty = Set ComponentID -> Set ComponentID -> DynamicQueryFilter
DynamicQueryFilter Set ComponentID
forall a. Monoid a => a
mempty Set ComponentID
forall a. Monoid a => a
mempty

runDynQueryReader :: i -> DynamicQueryReader i o -> [EntityID] -> Archetype -> [o]
runDynQueryReader :: forall i o.
i -> DynamicQueryReader i o -> [EntityID] -> Archetype -> [o]
runDynQueryReader i
i DynamicQueryReader i o
q = DynamicQueryReader i o -> [i] -> [EntityID] -> Archetype -> [o]
forall i o.
DynamicQueryReader i o -> [i] -> [EntityID] -> Archetype -> [o]
runDynQueryReader' DynamicQueryReader i o
q (i -> [i]
forall a. a -> [a]
repeat i
i)

-- | Match all entities.
allDyn :: Set ComponentID -> i -> DynamicQueryReader i a -> Entities -> [a]
allDyn :: forall i a.
Set ComponentID -> i -> DynamicQueryReader i a -> Entities -> [a]
allDyn Set ComponentID
cIds i
i DynamicQueryReader i a
q Entities
es =
  if Set ComponentID -> Bool
forall a. Set a -> Bool
Set.null Set ComponentID
cIds
    then i -> DynamicQueryReader i a -> [EntityID] -> Archetype -> [a]
forall i o.
i -> DynamicQueryReader i o -> [EntityID] -> Archetype -> [o]
runDynQueryReader i
i DynamicQueryReader i a
q (Map EntityID ArchetypeID -> [EntityID]
forall k a. Map k a -> [k]
Map.keys (Map EntityID ArchetypeID -> [EntityID])
-> Map EntityID ArchetypeID -> [EntityID]
forall a b. (a -> b) -> a -> b
$ Entities -> Map EntityID ArchetypeID
entities Entities
es) Archetype
A.empty
    else
      let go :: Node -> [a]
go Node
n =
            let eIds :: [EntityID]
eIds = Set EntityID -> [EntityID]
forall a. Set a -> [a]
Set.toList (Set EntityID -> [EntityID]) -> Set EntityID -> [EntityID]
forall a b. (a -> b) -> a -> b
$ Archetype -> Set EntityID
A.entities (Archetype -> Set EntityID) -> Archetype -> Set EntityID
forall a b. (a -> b) -> a -> b
$ Node -> Archetype
AS.nodeArchetype Node
n
             in i -> DynamicQueryReader i a -> [EntityID] -> Archetype -> [a]
forall i o.
i -> DynamicQueryReader i o -> [EntityID] -> Archetype -> [o]
runDynQueryReader i
i DynamicQueryReader i a
q [EntityID]
eIds (Node -> Archetype
AS.nodeArchetype Node
n)
       in (Node -> [a]) -> Map ArchetypeID Node -> [a]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Node -> [a]
go (Set ComponentID -> Archetypes -> Map ArchetypeID Node
AS.find Set ComponentID
cIds (Archetypes -> Map ArchetypeID Node)
-> Archetypes -> Map ArchetypeID Node
forall a b. (a -> b) -> a -> b
$ Entities -> Archetypes
archetypes Entities
es)