packages feed

aztecs-0.7.0: src/Aztecs/ECS/World/Storage/Dynamic.hs

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}

module Aztecs.ECS.World.Storage.Dynamic
  ( DynamicStorage (..),
    dynStorage,
    insertDyn,
    removeDyn,
    removeAny,
    entitiesDyn,
  )
where

import qualified Aztecs.ECS.World.Storage as S
import Control.DeepSeq
import Data.Dynamic
import Data.Maybe

data DynamicStorage = DynamicStorage
  { storageDyn :: !Dynamic,
    insertDyn' :: !(Int -> Dynamic -> Dynamic -> Dynamic),
    removeDyn' :: !(Int -> Dynamic -> (Maybe Dynamic, Dynamic)),
    removeAny' :: !(Int -> Dynamic -> (Maybe DynamicStorage, Dynamic)),
    entitiesDyn' :: !(Dynamic -> [Int]),
    storageRnf :: !(Dynamic -> ())
  }

instance Show DynamicStorage where
  show s = "DynamicStorage " ++ show (storageDyn s)

instance NFData DynamicStorage where
  rnf s = storageRnf s (storageDyn s)

dynStorage :: forall s a. (S.Storage s a) => s a -> DynamicStorage
dynStorage s =
  DynamicStorage
    { storageDyn = toDyn s,
      insertDyn' = \i cDyn sDyn ->
        fromMaybe sDyn $ do
          !s' <- fromDynamic @(s a) sDyn
          !c <- fromDynamic cDyn
          return . toDyn $ S.insert i c s',
      removeDyn' = \i dyn -> case fromDynamic @(s a) dyn of
        Just s' -> let !(a, b) = S.remove i s' in (fmap toDyn a, toDyn b)
        Nothing -> (Nothing, dyn),
      removeAny' = \i dyn -> case fromDynamic @(s a) dyn of
        Just s' -> let !(a, b) = S.remove i s' in (fmap (dynStorage . S.singleton @s i) a, toDyn b)
        Nothing -> (Nothing, dyn),
      entitiesDyn' = \dyn -> case fromDynamic @(s a) dyn of
        Just s' -> map fst $ S.toList s'
        Nothing -> [],
      storageRnf = \dyn -> maybe () rnf (fromDynamic @(s a) dyn)
    }

insertDyn :: Int -> Dynamic -> DynamicStorage -> DynamicStorage
insertDyn i c s = s {storageDyn = insertDyn' s i c (storageDyn s)}

removeDyn :: Int -> DynamicStorage -> (Maybe Dynamic, DynamicStorage)
removeDyn i s = let (a, s') = removeDyn' s i (storageDyn s) in (a, s {storageDyn = s'})

removeAny :: Int -> DynamicStorage -> (Maybe DynamicStorage, DynamicStorage)
removeAny i s = let (a, s') = removeAny' s i (storageDyn s) in (a, s {storageDyn = s'})

entitiesDyn :: DynamicStorage -> [Int]
entitiesDyn s = entitiesDyn' s (storageDyn s)