{-# LANGUAGE AllowAmbiguousTypes #-}
{-# OPTIONS_GHC -Wno-partial-fields #-}
{-# OPTIONS_GHC -Wno-redundant-constraints #-}

module Mischief.ECS.World.Query.Pipe
  ( -- * Impure
    qtraverse,
    qtap,

    -- * Mapping
    qmap,
    qmapM,
    qmapMaybe,
    qmapMaybeM,

    -- * Filtering
    qfilter,
    qfilterM,

    -- * Insertion
    qinsert,
    qinsertNew,
    qinsertIfNeq,
    qmodify,
    qmodifyNew,
    qmodifyIfNeq,

    -- * Expansion
    qextend,
    qentity,

    -- * Traversal
    qrelateOne,
    qrelateMany,
    qjoin,

    -- * Monad
    qpure,
    qrefocus,
    qres,
    qget,
    qgetAll,
    qcollect,
    qmaybe,
    qstopIf,
    qstop,
    qiter,
    qiterE,
    qlift,
    qlift_,

    -- * Logging
    qinfo,
    qwarn,
    qerr,

    -- * Other
    qdespawn,

    -- * Parallelism
    qpar,
  )
where

import Control.Monad (void)
import Control.Monad qualified
import Data.Function
import Data.Maybe
import Data.Text (Text)
import GHC.Stack
import Mischief.ECS.Components
import Mischief.ECS.Components.Bundle
import Mischief.ECS.Entities
import Mischief.ECS.Log
import Mischief.ECS.World
import Mischief.ECS.World.Defer
import Mischief.ECS.World.Insert
import Mischief.ECS.World.Query
import Mischief.ECS.World.Query.Markers
import Mischief.ECS.World.Query.QueryFilter
import Mischief.ECS.World.Query.Queryable
import Mischief.ECS.World.Spawn

{-# RULES
"qmap/qmap" forall f g xs. qmap f (qmap g xs) = qmap (f . g) xs
  #-}

qcollect :: (MonadSystem w m) => Query m a -> Query m [From a]
qcollect :: forall w (m :: * -> *) a.
MonadSystem w m =>
Query m a -> Query m [From a]
qcollect = Query m a -> Query m [From a]
forall (m :: * -> *) a1. Query m a1 -> Query m [From a1]
CollectQuery

-- | Maps @Query m a@ to @Query m b@. Same as 'fmap'.
--
-- __Example__
--
-- @
-- [q|Name, Position|]
--   & qmap (\\(name, _) -> name)
--   & query
-- @
qmap :: (MonadSystem w m) => (a -> b) -> Query m a -> Query m b
qmap :: forall w (m :: * -> *) a b.
MonadSystem w m =>
(a -> b) -> Query m a -> Query m b
qmap = (a -> b) -> Query m a -> Query m b
forall a b. (a -> b) -> Query m a -> Query m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
{-# INLINE [1] qmap #-}

-- | 'qmap' with side effects. Same as 'qtraverse'.
qmapM :: (MonadSystem w m) => (Entity -> a -> m b) -> Query m a -> Query m b
qmapM :: forall w (m :: * -> *) a b.
MonadSystem w m =>
(Entity -> a -> m b) -> Query m a -> Query m b
qmapM = (Entity -> a -> m b) -> Query m a -> Query m b
forall a (m :: * -> *) b.
(Entity -> a -> m b) -> Query m a -> Query m b
qtraverse

-- | 'qmapMaybe' with side effects.
qmapMaybeM :: (MonadSystem w m) => (Entity -> a -> m (Maybe b)) -> Query m a -> Query m b
qmapMaybeM :: forall w (m :: * -> *) a b.
MonadSystem w m =>
(Entity -> a -> m (Maybe b)) -> Query m a -> Query m b
qmapMaybeM !Entity -> a -> m (Maybe b)
f !Query m a
b = Query m (Maybe b) -> (Entity -> Maybe b -> m b) -> Query m b
forall (m :: * -> *) b a.
Query m b -> (Entity -> b -> m a) -> Query m a
MapQuery (Query m (Maybe b)
-> (Entity -> Maybe b -> m Bool) -> Query m (Maybe b)
forall (m :: * -> *) a.
Query m a -> (Entity -> a -> m Bool) -> Query m a
FilterQuery (Query m a -> (Entity -> a -> m (Maybe b)) -> Query m (Maybe b)
forall (m :: * -> *) b a.
Query m b -> (Entity -> b -> m a) -> Query m a
MapQuery Query m a
b Entity -> a -> m (Maybe b)
f) (\Entity
_ !Maybe b
x -> Bool -> m Bool
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe b -> Bool
forall a. Maybe a -> Bool
isJust Maybe b
x))) (\Entity
_ !Maybe b
x -> b -> m b
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (b -> Maybe b -> b
forall a. a -> Maybe a -> a
fromMaybe b
forall a. HasCallStack => a
undefined Maybe b
x))

-- | Possibly maps each element from @Query m a@ to an element from @Query m b@. If Nothing, will filter this Entity out of the Query.
--
-- __Example__
--
-- @
-- f :: Name -> Maybe Name
-- @
--
-- @
-- [q|Name|]
--   & qmapMaybe f
--   & query
-- @
qmapMaybe :: (MonadSystem w m) => (a -> Maybe b) -> Query m a -> Query m b
qmapMaybe :: forall w (m :: * -> *) a b.
MonadSystem w m =>
(a -> Maybe b) -> Query m a -> Query m b
qmapMaybe !a -> Maybe b
f !Query m a
x = (Maybe b -> b) -> Query m (Maybe b) -> Query m b
forall w (m :: * -> *) a b.
MonadSystem w m =>
(a -> b) -> Query m a -> Query m b
qmap (b -> Maybe b -> b
forall a. a -> Maybe a -> a
fromMaybe b
forall a. HasCallStack => a
undefined) (Query m (Maybe b) -> Query m b) -> Query m (Maybe b) -> Query m b
forall a b. (a -> b) -> a -> b
$ (Maybe b -> Bool) -> Query m (Maybe b) -> Query m (Maybe b)
forall w (m :: * -> *) a.
MonadSystem w m =>
(a -> Bool) -> Query m a -> Query m a
qfilter Maybe b -> Bool
forall a. Maybe a -> Bool
isJust ((a -> Maybe b) -> Query m a -> Query m (Maybe b)
forall w (m :: * -> *) a b.
MonadSystem w m =>
(a -> b) -> Query m a -> Query m b
qmap a -> Maybe b
f Query m a
x)

-- | Map @Query m a@ to @Query m b@ with side effects.
--
-- __Example__
--
-- @
-- [q|Name, Position|]
--   & qtraverse (\\e (name, pos) -> do
--     [i|The name of entity #{e} is #{name}|]
--     pure pos
--   )
--   & query
-- @
qtraverse :: (Entity -> a -> m b) -> Query m a -> Query m b
qtraverse :: forall a (m :: * -> *) b.
(Entity -> a -> m b) -> Query m a -> Query m b
qtraverse !Entity -> a -> m b
f !Query m a
x = Query m a -> (Entity -> a -> m b) -> Query m b
forall (m :: * -> *) b a.
Query m b -> (Entity -> b -> m a) -> Query m a
MapQuery Query m a
x Entity -> a -> m b
f

qlift :: (MonadSystem w m) => m a -> Query m a
qlift :: forall w (m :: * -> *) a. MonadSystem w m => m a -> Query m a
qlift !m a
s = () -> Query m ()
forall a. a -> Query m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure () Query m () -> (Query m () -> Query m a) -> Query m a
forall a b. a -> (a -> b) -> b
& (Entity -> () -> m a) -> Query m () -> Query m a
forall a (m :: * -> *) b.
(Entity -> a -> m b) -> Query m a -> Query m b
qtraverse (\Entity
_ ()
_ -> m a
s)

qlift_ :: (MonadSystem w m) => m a -> Query m ()
qlift_ :: forall w (m :: * -> *) a. MonadSystem w m => m a -> Query m ()
qlift_ = Query m a -> Query m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Query m a -> Query m ())
-> (m a -> Query m a) -> m a -> Query m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> Query m a
forall w (m :: * -> *) a. MonadSystem w m => m a -> Query m a
qlift

-- | Apply a side effect over a query.
--
-- __Example__
--
-- @
-- [q|Name, Position|]
--   & qtraverse (\\e (name, pos) -> do
--     [i|The name of entity #{e} is #{name}|]
--   )
--   & query
-- @
qtap :: (Entity -> a -> m b) -> Query m a -> Query m a
qtap :: forall a (m :: * -> *) b.
(Entity -> a -> m b) -> Query m a -> Query m a
qtap = (Query m a -> (Entity -> a -> m b) -> Query m a)
-> (Entity -> a -> m b) -> Query m a -> Query m a
forall a b c. (a -> b -> c) -> b -> a -> c
flip Query m a -> (Entity -> a -> m b) -> Query m a
forall (m :: * -> *) a b.
Query m a -> (Entity -> a -> m b) -> Query m a
DoQuery

-- | Insert the values obtained from a mapping function.
--
-- __Example__
--
-- @
-- q[|Position, Velocity|]
--   & qinsert (\\(Position p, Velocity v) -> Position (p + v))
--   & query
-- @
qinsert :: (Bundle b) => (a -> b) -> Query System a -> Query System a
qinsert :: forall b a.
Bundle b =>
(a -> b) -> Query System a -> Query System a
qinsert !a -> b
f = (Entity -> a -> System ()) -> Query System a -> Query System a
forall a (m :: * -> *) b.
(Entity -> a -> m b) -> Query m a -> Query m a
qtap (\(!Entity
e) !a
a -> b -> Entity -> System ()
forall b. (HasCallStack, Bundle b) => b -> Entity -> System ()
forall b. Bundle b => b -> Entity -> System ()
insert (a -> b
f a
a) Entity
e)

-- | Same as 'qinsert' but only inserts components that aren't already on the entity.
qinsertNew :: (Bundle b) => (a -> b) -> Query System a -> Query System a
qinsertNew :: forall b a.
Bundle b =>
(a -> b) -> Query System a -> Query System a
qinsertNew !a -> b
f = (Entity -> a -> System ()) -> Query System a -> Query System a
forall a (m :: * -> *) b.
(Entity -> a -> m b) -> Query m a -> Query m a
qtap (\(!Entity
e) !a
a -> b -> Entity -> System ()
forall b. Bundle b => b -> Entity -> System ()
insertNew (a -> b
f a
a) Entity
e)

-- | Same as 'qinsert' but only inserts components that are new or different than the ones already on the entity. Avoids triggering false change detection.
qinsertIfNeq :: (BundleEq b) => (a -> b) -> Query System a -> Query System a
qinsertIfNeq :: forall b a.
BundleEq b =>
(a -> b) -> Query System a -> Query System a
qinsertIfNeq !a -> b
f = (Entity -> a -> System ()) -> Query System a -> Query System a
forall a (m :: * -> *) b.
(Entity -> a -> m b) -> Query m a -> Query m a
qtap (\(!Entity
e) !a
a -> b -> Entity -> System ()
forall b. BundleEq b => b -> Entity -> System ()
insertIfNeq (a -> b
f a
a) Entity
e)

-- | Same as 'qinsert' but will also propagate the mapped elements. Equivalent to @qinsert id . qmap f@.
qmodify :: (Bundle b) => (a -> b) -> Query System a -> Query System b
qmodify :: forall b a.
Bundle b =>
(a -> b) -> Query System a -> Query System b
qmodify !a -> b
f = (b -> b) -> Query System b -> Query System b
forall b a.
Bundle b =>
(a -> b) -> Query System a -> Query System a
qinsert b -> b
forall a. a -> a
id (Query System b -> Query System b)
-> (Query System a -> Query System b)
-> Query System a
-> Query System b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> Query System a -> Query System b
forall w (m :: * -> *) a b.
MonadSystem w m =>
(a -> b) -> Query m a -> Query m b
qmap a -> b
f

-- | Same as 'qinsertNew' but will also propagate the mapped elements. Equivalent to @qinsertNew id . qmap f@.
qmodifyNew :: (Bundle b) => (a -> b) -> Query System a -> Query System b
qmodifyNew :: forall b a.
Bundle b =>
(a -> b) -> Query System a -> Query System b
qmodifyNew !a -> b
f = (b -> b) -> Query System b -> Query System b
forall b a.
Bundle b =>
(a -> b) -> Query System a -> Query System a
qinsertNew b -> b
forall a. a -> a
id (Query System b -> Query System b)
-> (Query System a -> Query System b)
-> Query System a
-> Query System b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> Query System a -> Query System b
forall w (m :: * -> *) a b.
MonadSystem w m =>
(a -> b) -> Query m a -> Query m b
qmap a -> b
f

-- | Same as 'qinsertIfNeq' but will also propagate the mapped elements. Equivalent to @qinsertIfNeq id . qmap f@.
qmodifyIfNeq :: (BundleEq b) => (a -> b) -> Query System a -> Query System b
qmodifyIfNeq :: forall b a.
BundleEq b =>
(a -> b) -> Query System a -> Query System b
qmodifyIfNeq !a -> b
f = (b -> b) -> Query System b -> Query System b
forall b a.
BundleEq b =>
(a -> b) -> Query System a -> Query System a
qinsertIfNeq b -> b
forall a. a -> a
id (Query System b -> Query System b)
-> (Query System a -> Query System b)
-> Query System a
-> Query System b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> Query System a -> Query System b
forall w (m :: * -> *) a b.
MonadSystem w m =>
(a -> b) -> Query m a -> Query m b
qmap a -> b
f

{-# RULES
"qfilter/qfilter" forall f g xs. qfilter f (qfilter g xs) = qfilter (\x -> f x && g x) xs
  #-}

-- | Filter the entities of a query.
--
-- __Example__
--
-- @
-- [q|Name|]
--   & qfilter (== Name "Florian")
--   & query
-- @
qfilter :: (MonadSystem w m) => (a -> Bool) -> Query m a -> Query m a
qfilter :: forall w (m :: * -> *) a.
MonadSystem w m =>
(a -> Bool) -> Query m a -> Query m a
qfilter !a -> Bool
f !Query m a
x = Query m a -> (Entity -> a -> m Bool) -> Query m a
forall (m :: * -> *) a.
Query m a -> (Entity -> a -> m Bool) -> Query m a
FilterQuery Query m a
x (\Entity
_ !a
x -> Bool -> m Bool
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> Bool
f a
x))
{-# INLINE [1] qfilter #-}

-- | Filter the entities of a query with possible side effects.
--
-- __Example__
--
-- @
-- [q|Position|]
--   & qfilterM (\\e _ -> 'changed' \@Position e)
--   & query
-- @
qfilterM :: (Entity -> a -> m Bool) -> Query m a -> Query m a
qfilterM :: forall a (m :: * -> *).
(Entity -> a -> m Bool) -> Query m a -> Query m a
qfilterM !Entity -> a -> m Bool
f !Query m a
x = Query m a -> (Entity -> a -> m Bool) -> Query m a
forall (m :: * -> *) a.
Query m a -> (Entity -> a -> m Bool) -> Query m a
FilterQuery Query m a
x Entity -> a -> m Bool
f

-- check :: (MonadSystem w m) => QueryFilter EntityFilter -> Entity -> m Bool
-- check NoFilter _ = pure True
-- check (With !x) !e = do
--   !world <- unsafeGetWorld
--   liftIO $ filterEntity (With x) world e
-- check (Without !x) !e = do
--   !world <- unsafeGetWorld
--   liftIO $ filterEntity (Without x) world e
-- check (Added !x) !e = added x e
-- check (Changed !x) !e = changed x e
-- check (And !a !b) !e = (&&) <$> check a e <*> check b e
-- check (Or !a !b) !e = (||) <$> check a e <*> check b e
-- check (Not !a) !e = not <$> check a e

-- {-# RULES
-- "qcheck/qcheck" forall f g xs. qcheck f (qcheck g xs) = qcheck (f `And` g) xs
--   #-}

-- | Filter the entities of a query with a dedicated query filter.
--
-- __Example__
--
-- @
-- [q|Position|]
--   & qcheck [qf|Changed Position, !Added Position|]
--   & query
-- @
-- qcheck :: (MonadSystem w m) => QueryFilter EntityFilter -> Query m a -> Query m a
-- qcheck !f = qfilterM (\(!e) _ -> check f e)
-- {-# INLINE [1] qcheck #-}

-- | Extends the query with new elements.
--
-- __Example__
--
-- @
-- [q|Name|]
--   & qextend [qd|Position|] (,)
--   & query
-- @
qextend :: (MonadSystem w m, Queryable qd out) => qd -> (a -> out -> c) -> Query m a -> Query m c
qextend :: forall w (m :: * -> *) qd out a c.
(MonadSystem w m, Queryable qd out) =>
qd -> (a -> out -> c) -> Query m a -> Query m c
qextend !qd
qd !a -> out -> c
f !Query m a
a = do
  (!e, !a) <- Query m a -> Query m (Entity, a)
forall w (m :: * -> *) a.
MonadSystem w m =>
Query m a -> Query m (Entity, a)
qentity Query m a
a
  a' <- qget e qd
  qpure e & qmap (const $ f a a')

-- | Grab a Query Data from an entity resulting from a traversal and map it into the current data wrapped in a @From@:
--
-- __Example__
--
-- @
-- [q|Name|]
--   & qrelateOne (Tree.'Mischief.ECS.Relationships.Tree.root' \@Like) \[qd|Name|] (,)
--   & query_
-- @
qrelateOne :: (MonadSystem w m, Queryable qd out) => (Entity -> m (Maybe Entity)) -> qd -> (a -> From out -> c) -> Query m a -> Query m c
qrelateOne :: forall w (m :: * -> *) qd out a c.
(MonadSystem w m, Queryable qd out) =>
(Entity -> m (Maybe Entity))
-> qd -> (a -> From out -> c) -> Query m a -> Query m c
qrelateOne !Entity -> m (Maybe Entity)
f !qd
qd !a -> From out -> c
f' !Query m a
a = do
  (!a, !e) <- Query m a
a Query m a
-> (Query m a -> Query m (a, Maybe Entity))
-> Query m (a, Maybe Entity)
forall a b. a -> (a -> b) -> b
& (Entity -> a -> m (a, Maybe Entity))
-> Query m a -> Query m (a, Maybe Entity)
forall a (m :: * -> *) b.
(Entity -> a -> m b) -> Query m a -> Query m b
qtraverse (\Entity
e a
a -> (a
a,) (Maybe Entity -> (a, Maybe Entity))
-> m (Maybe Entity) -> m (a, Maybe Entity)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Entity -> m (Maybe Entity)
f Entity
e)
  case e of
    Maybe Entity
Nothing -> Query m c
forall (m :: * -> *) a. Query m a
EmptyQuery
    Just !Entity
e -> do
      !out <- Entity -> qd -> Query m out
forall w (m :: * -> *) qd out.
(MonadSystem w m, Queryable qd out) =>
Entity -> qd -> Query m out
qget Entity
e qd
qd
      pure $ f' a (From e out)

-- | Same as 'qrelateOne' but takes a traversal that returns a list of entities.
qrelateMany :: (MonadSystem w m, Queryable (E, qd) (Entity, out)) => (Entity -> m [Entity]) -> qd -> (a -> [From out] -> c) -> Query m a -> Query m c
qrelateMany :: forall w (m :: * -> *) qd out a c.
(MonadSystem w m, Queryable (E, qd) (Entity, out)) =>
(Entity -> m [Entity])
-> qd -> (a -> [From out] -> c) -> Query m a -> Query m c
qrelateMany !Entity -> m [Entity]
f !qd
qd !a -> [From out] -> c
f' !Query m a
a = do
  ((_, !a), !e) <- Query m a -> Query m (Entity, a)
forall w (m :: * -> *) a.
MonadSystem w m =>
Query m a -> Query m (Entity, a)
qentity Query m a
a Query m (Entity, a)
-> (Query m (Entity, a) -> Query m ((Entity, a), [Entity]))
-> Query m ((Entity, a), [Entity])
forall a b. a -> (a -> b) -> b
& (Entity -> (Entity, a) -> m ((Entity, a), [Entity]))
-> Query m (Entity, a) -> Query m ((Entity, a), [Entity])
forall a (m :: * -> *) b.
(Entity -> a -> m b) -> Query m a -> Query m b
qtraverse (\(!Entity
e) !(Entity, a)
a -> ((Entity, a)
a,) ([Entity] -> ((Entity, a), [Entity]))
-> m [Entity] -> m ((Entity, a), [Entity])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Entity -> m [Entity]
f Entity
e)
  case e of
    [] -> Query m c
forall (m :: * -> *) a. Query m a
EmptyQuery
    [Entity]
e -> do
      !as <-
        [Entity] -> (E, qd) -> Query m (Entity, out)
forall w (m :: * -> *) qd out.
(MonadSystem w m, Queryable qd out) =>
[Entity] -> qd -> Query m out
qgetAll [Entity]
e (E
E, qd
qd)
          Query m (Entity, out)
-> (Query m (Entity, out) -> Query m (From out))
-> Query m (From out)
forall a b. a -> (a -> b) -> b
& ((Entity, out) -> From out)
-> Query m (Entity, out) -> Query m (From out)
forall w (m :: * -> *) a b.
MonadSystem w m =>
(a -> b) -> Query m a -> Query m b
qmap ((Entity -> out -> From out) -> (Entity, out) -> From out
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Entity -> out -> From out
forall c. Entity -> c -> From c
From)
          Query m (From out)
-> (Query m (From out) -> Query m [From (From out)])
-> Query m [From (From out)]
forall a b. a -> (a -> b) -> b
& Query m (From out) -> Query m [From (From out)]
forall w (m :: * -> *) a.
MonadSystem w m =>
Query m a -> Query m [From a]
qcollect
          Query m [From (From out)]
-> (Query m [From (From out)] -> Query m [From out])
-> Query m [From out]
forall a b. a -> (a -> b) -> b
& ([From (From out)] -> [From out])
-> Query m [From (From out)] -> Query m [From out]
forall w (m :: * -> *) a b.
MonadSystem w m =>
(a -> b) -> Query m a -> Query m b
qmap ((From (From out) -> From out) -> [From (From out)] -> [From out]
forall a b. (a -> b) -> [a] -> [b]
map (.comp))
      pure $ f' a as

qres :: forall c m w. (MonadSystem w m, Component c) => Query m c
qres :: forall c (m :: * -> *) w.
(MonadSystem w m, Component c) =>
Query m c
qres = (\(Res c
c) -> c
c) (Res c -> c) -> Query m (Res c) -> Query m c
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Entity -> (c -> Res c) -> Query m (Res c)
forall w (m :: * -> *) qd out.
(MonadSystem w m, Queryable qd out) =>
Entity -> qd -> Query m out
qget ((# Word#, Word# #) -> Entity
Entity (# Word#
0##, Word#
0## #)) (forall c. c -> Res c
Res @c)

qget :: (MonadSystem w m, Queryable qd out) => Entity -> qd -> Query m out
qget :: forall w (m :: * -> *) qd out.
(MonadSystem w m, Queryable qd out) =>
Entity -> qd -> Query m out
qget !Entity
entity !qd
qd = qd -> QueryFilter -> Maybe [Entity] -> Query m out
forall qd a (m :: * -> *).
Queryable qd a =>
qd -> QueryFilter -> Maybe [Entity] -> Query m a
BuildQuery qd
qd QueryFilter
NoFilter ([Entity] -> Maybe [Entity]
forall a. a -> Maybe a
Just [Entity
entity])

qgetAll :: (MonadSystem w m, Queryable qd out) => [Entity] -> qd -> Query m out
qgetAll :: forall w (m :: * -> *) qd out.
(MonadSystem w m, Queryable qd out) =>
[Entity] -> qd -> Query m out
qgetAll ![Entity]
entity !qd
qd = qd -> QueryFilter -> Maybe [Entity] -> Query m out
forall qd a (m :: * -> *).
Queryable qd a =>
qd -> QueryFilter -> Maybe [Entity] -> Query m a
BuildQuery qd
qd QueryFilter
NoFilter ([Entity] -> Maybe [Entity]
forall a. a -> Maybe a
Just [Entity]
entity)

qmaybe :: (MonadSystem w m) => Maybe a -> Query m a
qmaybe :: forall w (m :: * -> *) a. MonadSystem w m => Maybe a -> Query m a
qmaybe = (Maybe a -> Maybe a) -> Query m (Maybe a) -> Query m a
forall w (m :: * -> *) a b.
MonadSystem w m =>
(a -> Maybe b) -> Query m a -> Query m b
qmapMaybe Maybe a -> Maybe a
forall a. a -> a
id (Query m (Maybe a) -> Query m a)
-> (Maybe a -> Query m (Maybe a)) -> Maybe a -> Query m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe a -> Query m (Maybe a)
forall a. a -> Query m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure

qrefocus :: Entity -> Query m a -> Query m a
qrefocus :: forall (m :: * -> *) a. Entity -> Query m a -> Query m a
qrefocus = (Query m a -> Entity -> Query m a)
-> Entity -> Query m a -> Query m a
forall a b c. (a -> b -> c) -> b -> a -> c
flip Query m a -> Entity -> Query m a
forall (m :: * -> *) a. Query m a -> Entity -> Query m a
RefocusQuery

qpure :: (MonadSystem w m) => Entity -> Query m ()
qpure :: forall w (m :: * -> *). MonadSystem w m => Entity -> Query m ()
qpure !Entity
e = Entity -> Query m () -> Query m ()
forall (m :: * -> *) a. Entity -> Query m a -> Query m a
qrefocus Entity
e (Query m () -> Query m ()) -> Query m () -> Query m ()
forall a b. (a -> b) -> a -> b
$ () -> Query m ()
forall a. a -> Query m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()

qstopIf :: (MonadSystem w m) => Bool -> Query m ()
qstopIf :: forall w (m :: * -> *). MonadSystem w m => Bool -> Query m ()
qstopIf Bool
b = Bool -> Query m () -> Query m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
Control.Monad.when Bool
b Query m ()
forall w (m :: * -> *) a. MonadSystem w m => Query m a
qstop

qstop :: (MonadSystem w m) => Query m a
qstop :: forall w (m :: * -> *) a. MonadSystem w m => Query m a
qstop = Query m a
forall (m :: * -> *) a. Query m a
StopQuery

qiter :: (MonadSystem w m) => [From a] -> Query m a
qiter :: forall w (m :: * -> *) a. MonadSystem w m => [From a] -> Query m a
qiter = [From a] -> Query m a
forall a (m :: * -> *). [From a] -> Query m a
IterQuery

qiterE :: (MonadSystem w m) => [Entity] -> Query m Entity
qiterE :: forall w (m :: * -> *).
MonadSystem w m =>
[Entity] -> Query m Entity
qiterE [Entity]
l = [From Entity] -> Query m Entity
forall w (m :: * -> *) a. MonadSystem w m => [From a] -> Query m a
qiter ((Entity -> From Entity) -> [Entity] -> [From Entity]
forall a b. (a -> b) -> [a] -> [b]
map (\Entity
x -> Entity -> Entity -> From Entity
forall c. Entity -> c -> From c
From Entity
x Entity
x) [Entity]
l)

--  | Pairs the query's elements with their entity.
qentity :: (MonadSystem w m) => Query m a -> Query m (Entity, a)
qentity :: forall w (m :: * -> *) a.
MonadSystem w m =>
Query m a -> Query m (Entity, a)
qentity = Query m a -> Query m (Entity, a)
forall (m :: * -> *) a1. Query m a1 -> Query m (Entity, a1)
PairEntityQuery

qjoin :: (MonadSystem w m) => (a -> Query m b) -> (a -> [From b] -> c) -> Query m a -> Query m c
qjoin :: forall w (m :: * -> *) a b c.
MonadSystem w m =>
(a -> Query m b) -> (a -> [From b] -> c) -> Query m a -> Query m c
qjoin !a -> Query m b
f !a -> [From b] -> c
f' !Query m a
a = do
  (_, !a) <- Query m a -> Query m (Entity, a)
forall w (m :: * -> *) a.
MonadSystem w m =>
Query m a -> Query m (Entity, a)
qentity Query m a
a
  f a & qcollect & qfilter (not . null) & qmap (f' a)

-- | Logs an INFO message.
qinfo :: (HasCallStack, MonadSystem w m) => (a -> Text) -> Query m a -> Query m a
qinfo :: forall w (m :: * -> *) a.
(HasCallStack, MonadSystem w m) =>
(a -> Text) -> Query m a -> Query m a
qinfo !a -> Text
f !Query m a
a = (HasCallStack => Query m a) -> Query m a
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack ((HasCallStack => Query m a) -> Query m a)
-> (HasCallStack => Query m a) -> Query m a
forall a b. (a -> b) -> a -> b
$ (Entity -> a -> m ()) -> Query m a -> Query m a
forall a (m :: * -> *) b.
(Entity -> a -> m b) -> Query m a -> Query m a
qtap (\Entity
_ !a
x -> Text -> m ()
forall w (m :: * -> *).
(HasCallStack, MonadSystem w m) =>
Text -> m ()
info (a -> Text
f a
x)) Query m a
a

-- | Logs a WARNING message.
qwarn :: (HasCallStack, MonadSystem w m) => (a -> Text) -> Query m a -> Query m a
qwarn :: forall w (m :: * -> *) a.
(HasCallStack, MonadSystem w m) =>
(a -> Text) -> Query m a -> Query m a
qwarn !a -> Text
f !Query m a
a = (HasCallStack => Query m a) -> Query m a
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack ((HasCallStack => Query m a) -> Query m a)
-> (HasCallStack => Query m a) -> Query m a
forall a b. (a -> b) -> a -> b
$ (Entity -> a -> m ()) -> Query m a -> Query m a
forall a (m :: * -> *) b.
(Entity -> a -> m b) -> Query m a -> Query m a
qtap (\Entity
_ !a
x -> Text -> m ()
forall w (m :: * -> *).
(HasCallStack, MonadSystem w m) =>
Text -> m ()
warn (a -> Text
f a
x)) Query m a
a

-- | Logs an ERROR message.
qerr :: (HasCallStack, MonadSystem w m) => (a -> Text) -> Query m a -> Query m a
qerr :: forall w (m :: * -> *) a.
(HasCallStack, MonadSystem w m) =>
(a -> Text) -> Query m a -> Query m a
qerr !a -> Text
f !Query m a
a = (HasCallStack => Query m a) -> Query m a
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack ((HasCallStack => Query m a) -> Query m a)
-> (HasCallStack => Query m a) -> Query m a
forall a b. (a -> b) -> a -> b
$ (Entity -> a -> m ()) -> Query m a -> Query m a
forall a (m :: * -> *) b.
(Entity -> a -> m b) -> Query m a -> Query m a
qtap (\Entity
_ !a
x -> Text -> m ()
forall w (m :: * -> *).
(HasCallStack, MonadSystem w m) =>
Text -> m ()
err (a -> Text
f a
x)) Query m a
a

qdespawn :: Query System a -> Query System a
qdespawn :: forall a. Query System a -> Query System a
qdespawn Query System a
a = do
  Query System a -> Query System ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Query System a -> Query System ())
-> Query System a -> Query System ()
forall a b. (a -> b) -> a -> b
$ (Entity -> a -> System ()) -> Query System a -> Query System a
forall a (m :: * -> *) b.
(Entity -> a -> m b) -> Query m a -> Query m a
qtap (\(!Entity
e) a
_ -> Entity -> System ()
despawn Entity
e) Query System a
a
  Query System a
forall w (m :: * -> *) a. MonadSystem w m => Query m a
qstop

qpar :: (MonadSystem w m) => Query ParSystem a -> Query m a
qpar :: forall w (m :: * -> *) a.
MonadSystem w m =>
Query ParSystem a -> Query m a
qpar = Query ParSystem a -> Query m a
forall a (m :: * -> *). Query ParSystem a -> Query m a
ParQuery