packages feed

aztecs-0.8.0: src/Aztecs/ECS/System/Dynamic/Reader.hs

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

module Aztecs.ECS.System.Dynamic.Reader
  ( DynamicReaderSystem,
    DynamicReaderSystemT (..),
    ArrowDynamicReaderSystem (..),
    ArrowQueueSystem (..),
    raceDyn,
  )
where

import Aztecs.ECS.Access
import Aztecs.ECS.Query.Dynamic.Reader (DynamicQueryReader (..), runDynQueryReader)
import Aztecs.ECS.System.Dynamic.Reader.Class
import Aztecs.ECS.System.Queue (ArrowQueueSystem (..))
import qualified Aztecs.ECS.View as V
import qualified Aztecs.ECS.World.Archetype as A
import Aztecs.ECS.World.Bundle
import Aztecs.ECS.World.Entities (Entities (..))
import Control.Arrow
import Control.Category
import Control.Monad.Identity
import Control.Parallel (par)
import qualified Data.Map as Map
import Prelude hiding (id, (.))

type DynamicReaderSystem = DynamicReaderSystemT Identity

newtype DynamicReaderSystemT m i o = DynamicReaderSystem
  { -- | Run a dynamic system producing some output
    runReaderSystemDyn :: Entities -> i -> (o, AccessT m (), DynamicReaderSystemT m i o)
  }
  deriving (Functor)

instance (Monad m) => Category (DynamicReaderSystemT m) where
  id = DynamicReaderSystem $ \_ i -> (i, pure (), id)
  DynamicReaderSystem f . DynamicReaderSystem g = DynamicReaderSystem $ \w i ->
    let (b, gAccess, g') = g w i
        (c, fAccess, f') = f w b
     in (c, gAccess >> fAccess, f' . g')

instance (Monad m) => Arrow (DynamicReaderSystemT m) where
  arr f = DynamicReaderSystem $ \_ i -> (f i, pure (), arr f)
  first (DynamicReaderSystem f) = DynamicReaderSystem $ \w (i, x) ->
    let (a, access, f') = f w i in ((a, x), access, first f')

instance (Monad m) => ArrowChoice (DynamicReaderSystemT m) where
  left (DynamicReaderSystem f) = DynamicReaderSystem $ \w i -> case i of
    Left b -> let (c, access, f') = f w b in (Left c, access, left f')
    Right d -> (Right d, pure (), left (DynamicReaderSystem f))

instance (Monad m) => ArrowLoop (DynamicReaderSystemT m) where
  loop (DynamicReaderSystem f) = DynamicReaderSystem $ \w b ->
    let ((c, d), access, f') = f w (b, d) in (c, access, loop f')

instance (Monad m) => ArrowDynamicReaderSystem DynamicQueryReader (DynamicReaderSystemT m) where
  allDyn cIds q = DynamicReaderSystem $ \w i ->
    let !v = V.view cIds $ archetypes w
     in if V.null v
          then (runDynQueryReader i q (Map.keys $ entities w) A.empty, pure (), allDyn cIds q)
          else (V.readAllDyn i q v, pure (), allDyn cIds q)
  filterDyn cIds q f = DynamicReaderSystem $ \w i ->
    let !v = V.filterView cIds f $ archetypes w
     in (V.readAllDyn i q v, pure (), filterDyn cIds q f)

instance (Monad m) => ArrowQueueSystem Bundle (AccessT m) (DynamicReaderSystemT m) where
  queue f = DynamicReaderSystem $ \_ i -> let !a = f i in ((), a, queue f)

raceDyn :: (Monad m) => DynamicReaderSystemT m i a -> DynamicReaderSystemT m i b -> DynamicReaderSystemT m i (a, b)
raceDyn (DynamicReaderSystem f) (DynamicReaderSystem g) = DynamicReaderSystem $ \w i ->
  let fa = f w i
      gb = g w i
      gbPar = fa `par` gb
      (a, fAccess, f') = fa
      (b, gAccess, g') = gbPar
   in ((a, b), fAccess >> gAccess, raceDyn f' g')