{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}

-- |
-- Module      : Aztecs.ECS.Query.Dynamic
-- Copyright   : (c) Matt Hunzinger, 2025
-- License     : BSD-style (see the LICENSE file in the distribution)
--
-- Maintainer  : matt@hunzinger.me
-- Stability   : provisional
-- Portability : non-portable (GHC extensions)
module Aztecs.ECS.Query.Dynamic
  ( -- * Dynamic queries
    DynamicQuery,
    DynamicQueryT (..),
    DynamicQueryReaderF (..),
    DynamicQueryF (..),

    -- ** Conversion
    fromDynReader,
    toDynReader,

    -- ** Running
    mapDyn,
    filterMapDyn,
    mapSingleDyn,
    mapSingleMaybeDyn,

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

import Aztecs.ECS.Component
import Aztecs.ECS.Query.Dynamic.Class
import Aztecs.ECS.Query.Dynamic.Reader
import Aztecs.ECS.World.Archetype (Archetype)
import qualified Aztecs.ECS.World.Archetype as A
import Aztecs.ECS.World.Archetypes (ArchetypeID, Node (..))
import qualified Aztecs.ECS.World.Archetypes as AS
import Aztecs.ECS.World.Entities (Entities (..))
import Control.Monad.Identity
import Data.Foldable
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Set (Set)
import qualified Data.Set as Set
import GHC.Stack

type DynamicQuery = DynamicQueryT Identity

-- | Dynamic query for components by ID.
--
-- @since 0.10
newtype DynamicQueryT f a
  = DynamicQuery
  { -- | Run a dynamic query.
    --
    -- @since 0.10
    forall (f :: * -> *) a.
DynamicQueryT f a -> Archetype -> f ([a], Archetype)
runDynQuery :: Archetype -> f ([a], Archetype)
  }
  deriving ((forall a b. (a -> b) -> DynamicQueryT f a -> DynamicQueryT f b)
-> (forall a b. a -> DynamicQueryT f b -> DynamicQueryT f a)
-> Functor (DynamicQueryT f)
forall a b. a -> DynamicQueryT f b -> DynamicQueryT f a
forall a b. (a -> b) -> DynamicQueryT f a -> DynamicQueryT f b
forall (f :: * -> *) a b.
Functor f =>
a -> DynamicQueryT f b -> DynamicQueryT f a
forall (f :: * -> *) a b.
Functor f =>
(a -> b) -> DynamicQueryT f a -> DynamicQueryT f b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall (f :: * -> *) a b.
Functor f =>
(a -> b) -> DynamicQueryT f a -> DynamicQueryT f b
fmap :: forall a b. (a -> b) -> DynamicQueryT f a -> DynamicQueryT f b
$c<$ :: forall (f :: * -> *) a b.
Functor f =>
a -> DynamicQueryT f b -> DynamicQueryT f a
<$ :: forall a b. a -> DynamicQueryT f b -> DynamicQueryT f a
Functor)

-- | @since 0.10
instance (Applicative f) => Applicative (DynamicQueryT f) where
  {-# INLINE pure #-}
  pure :: forall a. a -> DynamicQueryT f a
pure a
a = (Archetype -> f ([a], Archetype)) -> DynamicQueryT f a
forall (f :: * -> *) a.
(Archetype -> f ([a], Archetype)) -> DynamicQueryT f a
DynamicQuery ((Archetype -> f ([a], Archetype)) -> DynamicQueryT f a)
-> (Archetype -> f ([a], Archetype)) -> DynamicQueryT f a
forall a b. (a -> b) -> a -> b
$ \Archetype
arch -> ([a], Archetype) -> f ([a], Archetype)
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int -> a -> [a]
forall a. Int -> a -> [a]
replicate (Set EntityID -> Int
forall a. Set a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Set EntityID -> Int) -> Set EntityID -> Int
forall a b. (a -> b) -> a -> b
$ Archetype -> Set EntityID
A.entities Archetype
arch) a
a, Archetype
arch)

  {-# INLINE (<*>) #-}
  DynamicQueryT f (a -> b)
f <*> :: forall a b.
DynamicQueryT f (a -> b) -> DynamicQueryT f a -> DynamicQueryT f b
<*> DynamicQueryT f a
g = (Archetype -> f ([b], Archetype)) -> DynamicQueryT f b
forall (f :: * -> *) a.
(Archetype -> f ([a], Archetype)) -> DynamicQueryT f a
DynamicQuery ((Archetype -> f ([b], Archetype)) -> DynamicQueryT f b)
-> (Archetype -> f ([b], Archetype)) -> DynamicQueryT f b
forall a b. (a -> b) -> a -> b
$ \Archetype
arch -> do
    ([a], Archetype)
x <- DynamicQueryT f a -> Archetype -> f ([a], Archetype)
forall (f :: * -> *) a.
DynamicQueryT f a -> Archetype -> f ([a], Archetype)
runDynQuery DynamicQueryT f a
g Archetype
arch
    ([a -> b], Archetype)
y <- DynamicQueryT f (a -> b) -> Archetype -> f ([a -> b], Archetype)
forall (f :: * -> *) a.
DynamicQueryT f a -> Archetype -> f ([a], Archetype)
runDynQuery DynamicQueryT f (a -> b)
f Archetype
arch
    return $
      let ([a]
as, Archetype
arch') = ([a], Archetype)
x
          ([a -> b]
bs, Archetype
arch'') = ([a -> b], Archetype)
y
       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]
bs [a]
as, Archetype
arch' Archetype -> Archetype -> Archetype
forall a. Semigroup a => a -> a -> a
<> Archetype
arch'')

-- | @since 0.10
instance DynamicQueryReaderF DynamicQuery where
  {-# INLINE entity #-}
  entity :: DynamicQuery EntityID
entity = DynamicQueryReader EntityID -> DynamicQuery EntityID
forall (m :: * -> *) a.
Applicative m =>
DynamicQueryReader a -> DynamicQueryT m a
fromDynReader DynamicQueryReader EntityID
forall (f :: * -> *). DynamicQueryReaderF f => f EntityID
entity

  {-# INLINE fetchDyn #-}
  fetchDyn :: forall a. Component a => ComponentID -> DynamicQuery a
fetchDyn = DynamicQueryReader a -> DynamicQueryT Identity a
forall (m :: * -> *) a.
Applicative m =>
DynamicQueryReader a -> DynamicQueryT m a
fromDynReader (DynamicQueryReader a -> DynamicQueryT Identity a)
-> (ComponentID -> DynamicQueryReader a)
-> ComponentID
-> DynamicQueryT Identity a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ComponentID -> DynamicQueryReader a
forall a. Component a => ComponentID -> DynamicQueryReader a
forall (f :: * -> *) a.
(DynamicQueryReaderF f, Component a) =>
ComponentID -> f a
fetchDyn

  {-# INLINE fetchMaybeDyn #-}
  fetchMaybeDyn :: forall a. Component a => ComponentID -> DynamicQuery (Maybe a)
fetchMaybeDyn = DynamicQueryReader (Maybe a) -> DynamicQueryT Identity (Maybe a)
forall (m :: * -> *) a.
Applicative m =>
DynamicQueryReader a -> DynamicQueryT m a
fromDynReader (DynamicQueryReader (Maybe a) -> DynamicQueryT Identity (Maybe a))
-> (ComponentID -> DynamicQueryReader (Maybe a))
-> ComponentID
-> DynamicQueryT Identity (Maybe a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ComponentID -> DynamicQueryReader (Maybe a)
forall a.
Component a =>
ComponentID -> DynamicQueryReader (Maybe a)
forall (f :: * -> *) a.
(DynamicQueryReaderF f, Component a) =>
ComponentID -> f (Maybe a)
fetchMaybeDyn

-- | @since 0.10
instance (Applicative f) => DynamicQueryF f (DynamicQueryT f) where
  {-# INLINE adjustDyn #-}
  adjustDyn :: forall a b.
Component a =>
(b -> a -> a)
-> ComponentID -> DynamicQueryT f b -> DynamicQueryT f a
adjustDyn b -> a -> a
f ComponentID
cId DynamicQueryT f b
q =
    (Archetype -> f ([a], Archetype)) -> DynamicQueryT f a
forall (f :: * -> *) a.
(Archetype -> f ([a], Archetype)) -> DynamicQueryT f a
DynamicQuery ((([b], Archetype) -> ([a], Archetype))
-> f ([b], Archetype) -> f ([a], Archetype)
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\([b]
bs, Archetype
arch') -> [b]
-> (b -> a -> a) -> ComponentID -> Archetype -> ([a], Archetype)
forall a c.
Component c =>
[a]
-> (a -> c -> c) -> ComponentID -> Archetype -> ([c], Archetype)
A.zipWith [b]
bs b -> a -> a
f ComponentID
cId Archetype
arch') (f ([b], Archetype) -> f ([a], Archetype))
-> (Archetype -> f ([b], Archetype))
-> Archetype
-> f ([a], Archetype)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DynamicQueryT f b -> Archetype -> f ([b], Archetype)
forall (f :: * -> *) a.
DynamicQueryT f a -> Archetype -> f ([a], Archetype)
runDynQuery DynamicQueryT f b
q)

  {-# INLINE adjustDyn_ #-}
  adjustDyn_ :: forall a b.
Component a =>
(b -> a -> a)
-> ComponentID -> DynamicQueryT f b -> DynamicQueryT f ()
adjustDyn_ b -> a -> a
f ComponentID
cId DynamicQueryT f b
q = (Archetype -> f ([()], Archetype)) -> DynamicQueryT f ()
forall (f :: * -> *) a.
(Archetype -> f ([a], Archetype)) -> DynamicQueryT f a
DynamicQuery ((Archetype -> f ([()], Archetype)) -> DynamicQueryT f ())
-> (Archetype -> f ([()], Archetype)) -> DynamicQueryT f ()
forall a b. (a -> b) -> a -> b
$ \Archetype
arch ->
    (([b], Archetype) -> ([()], Archetype))
-> f ([b], Archetype) -> f ([()], Archetype)
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\([b]
bs, Archetype
arch') -> ((b -> ()) -> [b] -> [()]
forall a b. (a -> b) -> [a] -> [b]
map (() -> b -> ()
forall a b. a -> b -> a
const ()) [b]
bs, [b] -> (b -> a -> a) -> ComponentID -> Archetype -> Archetype
forall a c.
Component c =>
[a] -> (a -> c -> c) -> ComponentID -> Archetype -> Archetype
A.zipWith_ [b]
bs b -> a -> a
f ComponentID
cId Archetype
arch')) (DynamicQueryT f b -> Archetype -> f ([b], Archetype)
forall (f :: * -> *) a.
DynamicQueryT f a -> Archetype -> f ([a], Archetype)
runDynQuery DynamicQueryT f b
q Archetype
arch)

  {-# INLINE adjustDynM #-}
  adjustDynM :: forall a b.
(Monad f, Component a) =>
(b -> a -> f a)
-> ComponentID -> DynamicQueryT f b -> DynamicQueryT f a
adjustDynM b -> a -> f a
f ComponentID
cId DynamicQueryT f b
q = (Archetype -> f ([a], Archetype)) -> DynamicQueryT f a
forall (f :: * -> *) a.
(Archetype -> f ([a], Archetype)) -> DynamicQueryT f a
DynamicQuery ((Archetype -> f ([a], Archetype)) -> DynamicQueryT f a)
-> (Archetype -> f ([a], Archetype)) -> DynamicQueryT f a
forall a b. (a -> b) -> a -> b
$ \Archetype
arch -> do
    ([b]
bs, Archetype
arch') <- DynamicQueryT f b -> Archetype -> f ([b], Archetype)
forall (f :: * -> *) a.
DynamicQueryT f a -> Archetype -> f ([a], Archetype)
runDynQuery DynamicQueryT f b
q Archetype
arch
    [b]
-> (b -> a -> f a)
-> ComponentID
-> Archetype
-> f ([a], Archetype)
forall (m :: * -> *) a c.
(Applicative m, Component c) =>
[a]
-> (a -> c -> m c)
-> ComponentID
-> Archetype
-> m ([c], Archetype)
A.zipWithM [b]
bs b -> a -> f a
f ComponentID
cId Archetype
arch'

  {-# INLINE setDyn #-}
  setDyn :: forall a.
Component a =>
ComponentID -> DynamicQueryT f a -> DynamicQueryT f a
setDyn ComponentID
cId DynamicQueryT f a
q =
    (Archetype -> f ([a], Archetype)) -> DynamicQueryT f a
forall (f :: * -> *) a.
(Archetype -> f ([a], Archetype)) -> DynamicQueryT f a
DynamicQuery ((([a], Archetype) -> ([a], Archetype))
-> f ([a], Archetype) -> f ([a], Archetype)
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\([a]
bs, Archetype
arch') -> ([a]
bs, ComponentID -> [a] -> Archetype -> Archetype
forall a.
Component a =>
ComponentID -> [a] -> Archetype -> Archetype
A.insertAscList ComponentID
cId [a]
bs Archetype
arch')) (f ([a], Archetype) -> f ([a], Archetype))
-> (Archetype -> f ([a], Archetype))
-> Archetype
-> f ([a], Archetype)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DynamicQueryT f a -> Archetype -> f ([a], Archetype)
forall (f :: * -> *) a.
DynamicQueryT f a -> Archetype -> f ([a], Archetype)
runDynQuery DynamicQueryT f a
q)

-- | Convert a `DynamicQueryReaderT` to a `DynamicQueryT`.
--
-- @since 0.10
{-# INLINE fromDynReader #-}
fromDynReader :: (Applicative m) => DynamicQueryReader a -> DynamicQueryT m a
fromDynReader :: forall (m :: * -> *) a.
Applicative m =>
DynamicQueryReader a -> DynamicQueryT m a
fromDynReader DynamicQueryReader a
q = (Archetype -> m ([a], Archetype)) -> DynamicQueryT m a
forall (f :: * -> *) a.
(Archetype -> f ([a], Archetype)) -> DynamicQueryT f a
DynamicQuery ((Archetype -> m ([a], Archetype)) -> DynamicQueryT m a)
-> (Archetype -> m ([a], Archetype)) -> DynamicQueryT m a
forall a b. (a -> b) -> a -> b
$ \Archetype
arch -> let !os :: [a]
os = DynamicQueryReader a -> Archetype -> [a]
forall a. DynamicQueryReader a -> Archetype -> [a]
runDynQueryReader DynamicQueryReader a
q Archetype
arch in ([a], Archetype) -> m ([a], Archetype)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([a]
os, Archetype
arch)

-- | Convert a `DynamicQueryT` to a `DynamicQueryReaderT`.
--
-- @since 0.10
{-# INLINE toDynReader #-}
toDynReader :: DynamicQuery a -> DynamicQueryReader a
toDynReader :: forall a. DynamicQuery a -> DynamicQueryReader a
toDynReader DynamicQuery a
q = (Archetype -> [a]) -> DynamicQueryReader a
forall a. (Archetype -> [a]) -> DynamicQueryReader a
DynamicQueryReader ((Archetype -> [a]) -> DynamicQueryReader a)
-> (Archetype -> [a]) -> DynamicQueryReader a
forall a b. (a -> b) -> a -> b
$ \Archetype
arch -> ([a], Archetype) -> [a]
forall a b. (a, b) -> a
fst (([a], Archetype) -> [a]) -> ([a], Archetype) -> [a]
forall a b. (a -> b) -> a -> b
$ Identity ([a], Archetype) -> ([a], Archetype)
forall a. Identity a -> a
runIdentity (Identity ([a], Archetype) -> ([a], Archetype))
-> Identity ([a], Archetype) -> ([a], Archetype)
forall a b. (a -> b) -> a -> b
$ DynamicQuery a -> Archetype -> Identity ([a], Archetype)
forall (f :: * -> *) a.
DynamicQueryT f a -> Archetype -> f ([a], Archetype)
runDynQuery DynamicQuery a
q Archetype
arch

-- | Map all matched entities.
--
-- @since 0.10
{-# INLINE mapDyn #-}
mapDyn :: (Monad m) => Set ComponentID -> DynamicQueryT m a -> Entities -> m ([a], Entities)
mapDyn :: forall (m :: * -> *) a.
Monad m =>
Set ComponentID
-> DynamicQueryT m a -> Entities -> m ([a], Entities)
mapDyn Set ComponentID
cIds = Set ComponentID
-> (Map ArchetypeID Node -> Map ArchetypeID Node)
-> DynamicQueryT m a
-> Entities
-> m ([a], Entities)
forall (m :: * -> *) a.
Monad m =>
Set ComponentID
-> (Map ArchetypeID Node -> Map ArchetypeID Node)
-> DynamicQueryT m a
-> Entities
-> m ([a], Entities)
mapDyn' Set ComponentID
cIds Map ArchetypeID Node -> Map ArchetypeID Node
forall a. a -> a
id

-- | Map all matched entities with a filter.
--
-- @since 0.10
{-# INLINE filterMapDyn #-}
filterMapDyn ::
  (Monad m) =>
  Set ComponentID ->
  (Node -> Bool) ->
  DynamicQueryT m a ->
  Entities ->
  m ([a], Entities)
filterMapDyn :: forall (m :: * -> *) a.
Monad m =>
Set ComponentID
-> (Node -> Bool)
-> DynamicQueryT m a
-> Entities
-> m ([a], Entities)
filterMapDyn Set ComponentID
cIds Node -> Bool
f = Set ComponentID
-> (Map ArchetypeID Node -> Map ArchetypeID Node)
-> DynamicQueryT m a
-> Entities
-> m ([a], Entities)
forall (m :: * -> *) a.
Monad m =>
Set ComponentID
-> (Map ArchetypeID Node -> Map ArchetypeID Node)
-> DynamicQueryT m a
-> Entities
-> m ([a], Entities)
mapDyn' Set ComponentID
cIds ((Node -> Bool) -> Map ArchetypeID Node -> Map ArchetypeID Node
forall a k. (a -> Bool) -> Map k a -> Map k a
Map.filter Node -> Bool
f)

{-# INLINE mapDyn' #-}
mapDyn' ::
  (Monad m) =>
  Set ComponentID ->
  (Map ArchetypeID Node -> Map ArchetypeID Node) ->
  DynamicQueryT m a ->
  Entities ->
  m ([a], Entities)
mapDyn' :: forall (m :: * -> *) a.
Monad m =>
Set ComponentID
-> (Map ArchetypeID Node -> Map ArchetypeID Node)
-> DynamicQueryT m a
-> Entities
-> m ([a], Entities)
mapDyn' Set ComponentID
cIds Map ArchetypeID Node -> Map ArchetypeID Node
f DynamicQueryT m a
q Entities
es =
  let go :: Archetype -> m ([a], Archetype)
go = DynamicQueryT m a -> Archetype -> m ([a], Archetype)
forall (f :: * -> *) a.
DynamicQueryT f a -> Archetype -> f ([a], Archetype)
runDynQuery DynamicQueryT m a
q
   in if Set ComponentID -> Bool
forall a. Set a -> Bool
Set.null Set ComponentID
cIds
        then do
          ([a]
as, Archetype
_) <- Archetype -> m ([a], Archetype)
go Archetype
A.empty {A.entities = Map.keysSet $ entities es}
          ([a], Entities) -> m ([a], Entities)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ([a]
as, Entities
es)
        else
          let go' :: ([a], Entities) -> (ArchetypeID, Node) -> m ([a], Entities)
go' ([a]
acc, Entities
esAcc) (ArchetypeID
aId, Node
n) = do
                ([a]
as', Archetype
arch') <- Archetype -> m ([a], Archetype)
go (Archetype -> m ([a], Archetype))
-> Archetype -> m ([a], Archetype)
forall a b. (a -> b) -> a -> b
$ Node -> Archetype
nodeArchetype Node
n
                let n' :: Node
n' = Node
n {nodeArchetype = arch' <> nodeArchetype n}
                    !nodes :: Map ArchetypeID Node
nodes = ArchetypeID -> Node -> Map ArchetypeID Node -> Map ArchetypeID Node
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert ArchetypeID
aId Node
n' (Map ArchetypeID Node -> Map ArchetypeID Node)
-> (Archetypes -> Map ArchetypeID Node)
-> Archetypes
-> Map ArchetypeID Node
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Archetypes -> Map ArchetypeID Node
AS.nodes (Archetypes -> Map ArchetypeID Node)
-> Archetypes -> Map ArchetypeID Node
forall a b. (a -> b) -> a -> b
$ Entities -> Archetypes
archetypes Entities
esAcc
                ([a], Entities) -> m ([a], Entities)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
return ([a]
as' [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a]
acc, Entities
esAcc {archetypes = (archetypes esAcc) {AS.nodes = nodes}})
           in (([a], Entities) -> (ArchetypeID, Node) -> m ([a], Entities))
-> ([a], Entities) -> [(ArchetypeID, Node)] -> m ([a], Entities)
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldlM ([a], Entities) -> (ArchetypeID, Node) -> m ([a], Entities)
go' ([], Entities
es) ([(ArchetypeID, Node)] -> m ([a], Entities))
-> [(ArchetypeID, Node)] -> m ([a], Entities)
forall a b. (a -> b) -> a -> b
$ Map ArchetypeID Node -> [(ArchetypeID, Node)]
forall k a. Map k a -> [(k, a)]
Map.toList (Map ArchetypeID Node -> [(ArchetypeID, Node)])
-> (Archetypes -> Map ArchetypeID Node)
-> Archetypes
-> [(ArchetypeID, Node)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map ArchetypeID Node -> Map ArchetypeID Node
f (Map ArchetypeID Node -> Map ArchetypeID Node)
-> (Archetypes -> Map ArchetypeID Node)
-> Archetypes
-> Map ArchetypeID Node
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Set ComponentID -> Archetypes -> Map ArchetypeID Node
AS.find Set ComponentID
cIds (Archetypes -> [(ArchetypeID, Node)])
-> Archetypes -> [(ArchetypeID, Node)]
forall a b. (a -> b) -> a -> b
$ Entities -> Archetypes
archetypes Entities
es

-- | Map a single matched entity.
--
-- @since 0.10
mapSingleDyn :: (HasCallStack, Monad m) => Set ComponentID -> DynamicQueryT m a -> Entities -> m (a, Entities)
mapSingleDyn :: forall (m :: * -> *) a.
(HasCallStack, Monad m) =>
Set ComponentID -> DynamicQueryT m a -> Entities -> m (a, Entities)
mapSingleDyn Set ComponentID
cIds DynamicQueryT m a
q Entities
es = do
  (Maybe a, Entities)
res <- Set ComponentID
-> DynamicQueryT m a -> Entities -> m (Maybe a, Entities)
forall (m :: * -> *) a.
Monad m =>
Set ComponentID
-> DynamicQueryT m a -> Entities -> m (Maybe a, Entities)
mapSingleMaybeDyn Set ComponentID
cIds DynamicQueryT m a
q Entities
es
  return $ case (Maybe a, Entities)
res of
    (Just a
a, Entities
es') -> (a
a, Entities
es')
    (Maybe a, Entities)
_ -> [Char] -> (a, Entities)
forall a. HasCallStack => [Char] -> a
error [Char]
"mapSingleDyn: expected single matching entity"

-- | Map a single matched entity, or @Nothing@.
--
-- @since 0.10
{-# INLINE mapSingleMaybeDyn #-}
mapSingleMaybeDyn :: (Monad m) => Set ComponentID -> DynamicQueryT m a -> Entities -> m (Maybe a, Entities)
mapSingleMaybeDyn :: forall (m :: * -> *) a.
Monad m =>
Set ComponentID
-> DynamicQueryT m a -> Entities -> m (Maybe a, Entities)
mapSingleMaybeDyn Set ComponentID
cIds DynamicQueryT m a
q Entities
es =
  if Set ComponentID -> Bool
forall a. Set a -> Bool
Set.null Set ComponentID
cIds
    then case 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 of
      [EntityID
eId] -> do
        ([a], Archetype)
res <- DynamicQueryT m a -> Archetype -> m ([a], Archetype)
forall (f :: * -> *) a.
DynamicQueryT f a -> Archetype -> f ([a], Archetype)
runDynQuery DynamicQueryT m a
q (Archetype -> m ([a], Archetype))
-> Archetype -> m ([a], Archetype)
forall a b. (a -> b) -> a -> b
$ EntityID -> Archetype
A.singleton EntityID
eId
        return $ case ([a], Archetype)
res of
          ([a
a], Archetype
_) -> (a -> Maybe a
forall a. a -> Maybe a
Just a
a, Entities
es)
          ([a], Archetype)
_ -> (Maybe a
forall a. Maybe a
Nothing, Entities
es)
      [EntityID]
_ -> (Maybe a, Entities) -> m (Maybe a, Entities)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe a
forall a. Maybe a
Nothing, Entities
es)
    else case Map ArchetypeID Node -> [(ArchetypeID, Node)]
forall k a. Map k a -> [(k, a)]
Map.toList (Map ArchetypeID Node -> [(ArchetypeID, Node)])
-> Map ArchetypeID Node -> [(ArchetypeID, Node)]
forall a b. (a -> b) -> a -> b
$ 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 of
      [(ArchetypeID
aId, Node
n)] -> do
        ([a], Archetype)
res <- DynamicQueryT m a -> Archetype -> m ([a], Archetype)
forall (f :: * -> *) a.
DynamicQueryT f a -> Archetype -> f ([a], Archetype)
runDynQuery DynamicQueryT m a
q (Archetype -> m ([a], Archetype))
-> Archetype -> m ([a], Archetype)
forall a b. (a -> b) -> a -> b
$ Node -> Archetype
AS.nodeArchetype Node
n
        return $ case ([a], Archetype)
res of
          ([a
a], Archetype
arch') ->
            let nodes :: Map ArchetypeID Node
nodes = ArchetypeID -> Node -> Map ArchetypeID Node -> Map ArchetypeID Node
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert ArchetypeID
aId Node
n {nodeArchetype = arch' <> nodeArchetype n} (Map ArchetypeID Node -> Map ArchetypeID Node)
-> (Archetypes -> Map ArchetypeID Node)
-> Archetypes
-> Map ArchetypeID Node
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Archetypes -> Map ArchetypeID Node
AS.nodes (Archetypes -> Map ArchetypeID Node)
-> Archetypes -> Map ArchetypeID Node
forall a b. (a -> b) -> a -> b
$ Entities -> Archetypes
archetypes Entities
es
             in (a -> Maybe a
forall a. a -> Maybe a
Just a
a, Entities
es {archetypes = (archetypes es) {AS.nodes = nodes}})
          ([a], Archetype)
_ -> (Maybe a
forall a. Maybe a
Nothing, Entities
es)
      [(ArchetypeID, Node)]
_ -> (Maybe a, Entities) -> m (Maybe a, Entities)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe a
forall a. Maybe a
Nothing, Entities
es)