aztecs-0.13.0: src/Aztecs/ECS/Queryable/Internal.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE UndecidableInstances #-}
module Aztecs.ECS.Queryable.Internal where
import Aztecs.ECS.Entities
import Aztecs.ECS.HSet
import qualified Aztecs.ECS.HSet as HS
import Aztecs.ECS.Query
import Data.Kind
import Data.Maybe
import qualified Data.Set as Set
import Data.SparseSet.Strict.Mutable
import qualified Data.SparseSet.Strict.Mutable as MS
import Data.Word
import GHC.Generics
import Prelude hiding (Read)
type family (++) (xs :: [Type]) (ys :: [Type]) :: [Type] where
'[] ++ ys = ys
(x ': xs) ++ ys = x ': (xs ++ ys)
type family AccessToComponents (accesses :: [Type]) :: [Type] where
AccessToComponents '[] = '[]
AccessToComponents (Read a ': rest) = a ': AccessToComponents rest
AccessToComponents (Write a ': rest) = a ': AccessToComponents rest
AccessToComponents (With a ': rest) = a ': AccessToComponents rest
AccessToComponents (Without a ': rest) = AccessToComponents rest
type family ReadComponents (accesses :: [Type]) :: [Type] where
ReadComponents '[] = '[]
ReadComponents (Read a ': rest) = a ': ReadComponents rest
ReadComponents (Write a ': rest) = ReadComponents rest
ReadComponents (With a ': rest) = ReadComponents rest
ReadComponents (Without a ': rest) = ReadComponents rest
type family WriteComponents (accesses :: [Type]) :: [Type] where
WriteComponents '[] = '[]
WriteComponents (Read a ': rest) = WriteComponents rest
WriteComponents (Write a ': rest) = a ': WriteComponents rest
WriteComponents (With a ': rest) = WriteComponents rest
WriteComponents (Without a ': rest) = WriteComponents rest
type family WithComponents (accesses :: [Type]) :: [Type] where
WithComponents '[] = '[]
WithComponents (Read a ': rest) = WithComponents rest
WithComponents (Write a ': rest) = WithComponents rest
WithComponents (With a ': rest) = a ': WithComponents rest
WithComponents (Without a ': rest) = WithComponents rest
type family WithoutComponents (accesses :: [Type]) :: [Type] where
WithoutComponents '[] = '[]
WithoutComponents (Read a ': rest) = WithoutComponents rest
WithoutComponents (Write a ': rest) = WithoutComponents rest
WithoutComponents (With a ': rest) = WithoutComponents rest
WithoutComponents (Without a ': rest) = a ': WithoutComponents rest
type family Contains (a :: Type) (list :: [Type]) :: Bool where
Contains a '[] = 'False
Contains a (a ': rest) = 'True
Contains a (b ': rest) = Contains a rest
type family HasOverlap (list1 :: [Type]) (list2 :: [Type]) :: Bool where
HasOverlap '[] list2 = 'False
HasOverlap (a ': rest) list2 = Or (Contains a list2) (HasOverlap rest list2)
type family HasDuplicates (list :: [Type]) :: Bool where
HasDuplicates '[] = 'False
HasDuplicates (a ': rest) = Or (Contains a rest) (HasDuplicates rest)
type family ValidateAccess (accesses :: [Type]) :: Bool where
ValidateAccess accesses =
And
(Not (HasOverlap (WriteComponents accesses) (ReadComponents accesses)))
(Not (HasDuplicates (WriteComponents accesses)))
type family And (a :: Bool) (b :: Bool) :: Bool where
And 'True 'True = 'True
And 'True 'False = 'False
And 'False 'True = 'False
And 'False 'False = 'False
type family Or (a :: Bool) (b :: Bool) :: Bool where
Or 'True _ = 'True
Or 'False 'True = 'True
Or 'False 'False = 'False
type family Not (b :: Bool) :: Bool where
Not 'True = 'False
Not 'False = 'True
type ValidAccess accesses = (ValidateAccess accesses ~ 'True)
data Read (a :: Type)
data Write (a :: Type)
data With (a :: Type) = With
data Without (a :: Type) = Without
instance (PrimMonad m, Lookup a cs) => Queryable cs m (With a) where
type QueryableAccess (With a) = '[With a]
queryable cs entitiesArg = Query $ do
withComponent <- MS.toList $ HS.lookup @a cs
let withComponentIndices = Set.fromList $ map fst $ catMaybes withComponent
allEntities = entities entitiesArg
result =
map
( \e ->
if Set.member (entityIndex e) withComponentIndices
then Just (With)
else Nothing
)
allEntities
return result
instance (PrimMonad m, Lookup a cs) => Queryable cs m (Without a) where
type QueryableAccess (Without a) = '[Without a]
queryable cs entitiesArg = Query $ do
withComponent <- MS.toList $ HS.lookup @a cs
let withComponentIndices = Set.fromList $ map fst $ catMaybes withComponent
allEntities = entities entitiesArg
result =
map
( \e ->
if Set.member (entityIndex e) withComponentIndices
then Nothing
else Just (Without)
)
allEntities
return result
type family AccessComponent (access :: Type) :: Type where
AccessComponent (Read a) = a
AccessComponent (Write a) = a
AccessComponent (With a) = a
AccessComponent (Without a) = a
type Components s = HSet (ComponentStorage s)
type ComponentStorage s = MSparseSet s Word32
type family GenericQueryableAccess (f :: Type -> Type) :: [Type] where
GenericQueryableAccess (M1 _ _ f) = GenericQueryableAccess f
GenericQueryableAccess (f :*: g) = GenericQueryableAccess f ++ GenericQueryableAccess g
GenericQueryableAccess (K1 _ a) = QueryableAccess a
GenericQueryableAccess U1 = '[]
class GenericQueryable cs m (f :: Type -> Type) where
genericQueryableRep :: Components (PrimState m) cs -> Entities -> m [Maybe (f p)]
instance (Monad m) => GenericQueryable s m U1 where
genericQueryableRep _ _ = pure [Just U1]
{-# INLINE genericQueryableRep #-}
instance
( Monad m,
GenericQueryable cs m f,
GenericQueryable cs m g
) =>
GenericQueryable cs m (f :*: g)
where
genericQueryableRep components entitiesArg = do
fs <- genericQueryableRep components entitiesArg
gs <- genericQueryableRep components entitiesArg
return $ zipWith (\f g -> (:*:) <$> f <*> g) fs gs
{-# INLINE genericQueryableRep #-}
instance (Functor m, GenericQueryable s m f) => GenericQueryable s m (M1 i c f) where
genericQueryableRep components entitiesArg = map (fmap M1) <$> genericQueryableRep components entitiesArg
{-# INLINE genericQueryableRep #-}
instance (Functor m, PrimMonad m, PrimState m ~ s, Queryable cs m a) => GenericQueryable cs m (K1 i a) where
genericQueryableRep components entitiesArg = map (fmap K1) <$> unQuery (queryable components entitiesArg)
{-# INLINE genericQueryableRep #-}
genericQueryable ::
forall a cs m.
( Generic a,
GenericQueryable cs m (Rep a),
Functor m
) =>
Components (PrimState m) cs ->
Entities ->
m [Maybe a]
genericQueryable components entitiesArg = map (fmap to) <$> genericQueryableRep components entitiesArg
{-# INLINE genericQueryable #-}
class (PrimMonad m) => Queryable cs m a where
type QueryableAccess a :: [Type]
type QueryableAccess a = GenericQueryableAccess (Rep a)
queryable :: Components (PrimState m) cs -> Entities -> Query m a
default queryable ::
( Generic a,
GenericQueryable cs m (Rep a),
QueryableAccess a ~ GenericQueryableAccess (Rep a),
ValidAccess (QueryableAccess a)
) =>
Components (PrimState m) cs ->
Entities ->
Query m a
queryable components entitiesArg = Query $ map (fmap to) <$> genericQueryableRep components entitiesArg
{-# INLINE queryable #-}
instance (Functor m, Monad m, PrimMonad m) => Queryable cs m Entity where
type QueryableAccess Entity = '[]
queryable _ ec = Query $ pure . map pure $ entities ec
instance
( Queryable cs m a,
Queryable cs m b,
ValidAccess (QueryableAccess a ++ QueryableAccess b)
) =>
Queryable cs m (a, b)
where
type QueryableAccess (a, b) = QueryableAccess a ++ QueryableAccess b
instance
( Queryable cs m a,
Queryable cs m b,
Queryable cs m c,
ValidAccess (QueryableAccess a ++ (QueryableAccess b ++ QueryableAccess c))
) =>
Queryable cs m (a, b, c)
where
type QueryableAccess (a, b, c) = QueryableAccess a ++ (QueryableAccess b ++ QueryableAccess c)
instance
( Queryable cs m a,
Queryable cs m b,
Queryable cs m c,
Queryable cs m d,
ValidAccess
( (QueryableAccess a ++ QueryableAccess b)
++ (QueryableAccess c ++ QueryableAccess d)
)
) =>
Queryable cs m (a, b, c, d)
where
type QueryableAccess (a, b, c, d) = (QueryableAccess a ++ QueryableAccess b) ++ (QueryableAccess c ++ QueryableAccess d)
instance
( Queryable cs m a,
Queryable cs m b,
Queryable cs m c,
Queryable cs m d,
Queryable cs m e,
ValidAccess
( (QueryableAccess a ++ QueryableAccess b)
++ (QueryableAccess c ++ (QueryableAccess d ++ QueryableAccess e))
)
) =>
Queryable cs m (a, b, c, d, e)
where
type
QueryableAccess (a, b, c, d, e) =
(QueryableAccess a ++ QueryableAccess b)
++ (QueryableAccess c ++ (QueryableAccess d ++ QueryableAccess e))
instance
( Queryable cs m a,
Queryable cs m b,
Queryable cs m c,
Queryable cs m d,
Queryable cs m e,
Queryable cs m f,
ValidAccess
( (QueryableAccess a ++ (QueryableAccess b ++ QueryableAccess c))
++ ( QueryableAccess d
++ (QueryableAccess e ++ QueryableAccess f)
)
)
) =>
Queryable cs m (a, b, c, d, e, f)
where
type
QueryableAccess (a, b, c, d, e, f) =
( (QueryableAccess a ++ (QueryableAccess b ++ QueryableAccess c))
++ ( QueryableAccess d
++ (QueryableAccess e ++ QueryableAccess f)
)
)
instance
( Queryable cs m a,
Queryable cs m b,
Queryable cs m c,
Queryable cs m d,
Queryable cs m e,
Queryable cs m f,
Queryable cs m g,
ValidAccess
( (QueryableAccess a ++ (QueryableAccess b ++ QueryableAccess c))
++ ( (QueryableAccess d ++ QueryableAccess e)
++ (QueryableAccess f ++ QueryableAccess g)
)
)
) =>
Queryable cs m (a, b, c, d, e, f, g)
where
type
QueryableAccess (a, b, c, d, e, f, g) =
(QueryableAccess a ++ (QueryableAccess b ++ QueryableAccess c))
++ ( (QueryableAccess d ++ QueryableAccess e)
++ (QueryableAccess f ++ QueryableAccess g)
)
instance
( Queryable cs m a,
Queryable cs m b,
Queryable cs m c,
Queryable cs m d,
Queryable cs m e,
Queryable cs m f,
Queryable cs m g,
Queryable cs m h,
ValidAccess
( ( (QueryableAccess a ++ QueryableAccess b)
++ (QueryableAccess c ++ QueryableAccess d)
)
++ ( (QueryableAccess e ++ QueryableAccess f)
++ (QueryableAccess g ++ QueryableAccess h)
)
)
) =>
Queryable cs m (a, b, c, d, e, f, g, h)
where
type
QueryableAccess (a, b, c, d, e, f, g, h) =
( (QueryableAccess a ++ QueryableAccess b)
++ (QueryableAccess c ++ QueryableAccess d)
)
++ ( (QueryableAccess e ++ QueryableAccess f)
++ (QueryableAccess g ++ QueryableAccess h)
)