packages feed

apecs 0.2.1.1 → 0.2.2.0

raw patch · 11 files changed

+225/−249 lines, 11 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Apecs.Logs: instance (Apecs.Logs.Log l (Apecs.Types.Stores s), Apecs.Stores.Cachable s) => Apecs.Types.HasMembers (Apecs.Logs.Logger l s)
- Apecs.Logs: instance (Apecs.Logs.Log l (Apecs.Types.Stores s), Apecs.Stores.Cachable s) => Apecs.Types.Initializable (Apecs.Logs.Logger l s)
- Apecs.Slice: sliceConcat :: Slice a -> Slice b -> Slice c
- Apecs.Slice: sliceFilterM :: (Entity c -> System w Bool) -> Slice c -> System w (Slice c)
- Apecs.Slice: sliceFoldM_ :: (a -> Entity c -> System w a) -> a -> Slice b -> System w ()
- Apecs.Slice: sliceForM :: Monad m => Slice c -> (Entity c -> m a) -> m [a]
- Apecs.Slice: sliceForMC :: forall w c a. (Store (Storage c), Has w c) => Slice c -> ((Entity c, Safe c) -> System w a) -> System w [a]
- Apecs.Slice: sliceForMC_ :: forall w c a. (Store (Storage c), Has w c) => Slice c -> ((Entity c, Safe c) -> System w a) -> System w ()
- Apecs.Slice: sliceForM_ :: Monad m => Slice c -> (Entity c -> m b) -> m ()
- Apecs.Slice: sliceFromList :: [Int] -> Slice a
- Apecs.Slice: sliceMapM :: Monad m => (Entity c -> m a) -> Slice c -> m [a]
- Apecs.Slice: sliceMapMC :: forall w c a. (Store (Storage c), Has w c) => ((Entity c, Safe c) -> System w a) -> Slice c -> System w [a]
- Apecs.Slice: sliceMapMC_ :: forall w c a. (Store (Storage c), Has w c) => ((Entity c, Safe c) -> System w a) -> Slice c -> System w ()
- Apecs.Slice: sliceMapM_ :: Monad m => (Entity c -> m a) -> Slice c -> m ()
- Apecs.Slice: sliceNull :: Slice a -> Bool
- Apecs.Slice: sliceSize :: Slice a -> Int
- Apecs.Stores: instance (GHC.TypeLits.KnownNat n, Apecs.Stores.Cachable s) => Apecs.Types.Initializable (Apecs.Stores.Cache n s)
- Apecs.Stores: instance Apecs.Stores.Cachable s => Apecs.Types.HasMembers (Apecs.Stores.Cache n s)
- Apecs.Stores: instance Apecs.Stores.Cachable s => Apecs.Types.Store (Apecs.Stores.Cache n s)
- Apecs.Stores: instance Apecs.Types.GlobalRW (Apecs.Stores.Const c) c
- Apecs.Stores: instance Apecs.Types.GlobalRW (Apecs.Stores.Global c) c
- Apecs.Stores: instance Apecs.Types.HasMembers (Apecs.Stores.Const c)
- Apecs.Stores: instance Apecs.Types.HasMembers (Apecs.Stores.Map c)
- Apecs.Stores: instance Apecs.Types.HasMembers (Apecs.Stores.Set c)
- Apecs.Stores: instance Apecs.Types.HasMembers (Apecs.Stores.Unique c)
- Apecs.Stores: instance Apecs.Types.Initializable (Apecs.Stores.Const c)
- Apecs.Stores: instance Apecs.Types.Initializable (Apecs.Stores.Global c)
- Apecs.Stores: instance Apecs.Types.Initializable (Apecs.Stores.Map c)
- Apecs.Stores: instance Apecs.Types.Initializable (Apecs.Stores.Set c)
- Apecs.Stores: instance Apecs.Types.Initializable (Apecs.Stores.Unique c)
- Apecs.Types: class GlobalRW s c where explGlobalModify s f = do { r <- explGlobalRead s; explGlobalWrite s (f r) }
- Apecs.Types: class HasMembers s where explReset s = do { sl <- explMembers s; mapM_ (explDestroy s) sl } explImapM_ s ma = liftIO (explMembers s) >>= mapM_ ma . toList explImapM s ma = liftIO (explMembers s) >>= mapM ma . toList
- Apecs.Types: class Initializable s where type InitArgs s where {
- Apecs.Types: explGlobalModify :: GlobalRW s c => s -> (c -> c) -> IO ()
- Apecs.Types: explGlobalRead :: GlobalRW s c => s -> IO c
- Apecs.Types: explGlobalWrite :: GlobalRW s c => s -> c -> IO ()
- Apecs.Types: instance (Apecs.Types.GlobalRW a ca, Apecs.Types.GlobalRW b cb) => Apecs.Types.GlobalRW (a, b) (ca, cb)
- Apecs.Types: instance (Apecs.Types.GlobalRW a ca, Apecs.Types.GlobalRW b cb, Apecs.Types.GlobalRW c cc) => Apecs.Types.GlobalRW (a, b, c) (ca, cb, cc)
- Apecs.Types: instance (Apecs.Types.HasMembers a, Apecs.Types.HasMembers b) => Apecs.Types.HasMembers (a, b)
- Apecs.Types: instance (Apecs.Types.HasMembers a, Apecs.Types.HasMembers b, Apecs.Types.HasMembers c) => Apecs.Types.HasMembers (a, b, c)
- Apecs.Types: instance (Apecs.Types.Initializable a, Apecs.Types.Initializable b) => Apecs.Types.Initializable (a, b)
- Apecs.Types: instance (Apecs.Types.Initializable a, Apecs.Types.Initializable b, Apecs.Types.Initializable c) => Apecs.Types.Initializable (a, b, c)
- Apecs.Types: type IsRuntime c = (Store (Storage c), Stores (Storage c) ~ c)
+ Apecs.Slice: concat :: Slice a -> Slice b -> Slice c
+ Apecs.Slice: filterM :: (Entity c -> System w Bool) -> Slice c -> System w (Slice c)
+ Apecs.Slice: foldM_ :: (a -> Entity c -> System w a) -> a -> Slice b -> System w ()
+ Apecs.Slice: forM :: Monad m => Slice c -> (Entity c -> m a) -> m [a]
+ Apecs.Slice: forMC :: forall w c a. Has w c => Slice c -> ((Entity c, Safe c) -> System w a) -> System w [a]
+ Apecs.Slice: forMC_ :: forall w c a. Has w c => Slice c -> ((Entity c, Safe c) -> System w a) -> System w ()
+ Apecs.Slice: forM_ :: Monad m => Slice c -> (Entity c -> m b) -> m ()
+ Apecs.Slice: fromList :: [Int] -> Slice a
+ Apecs.Slice: mapM :: Monad m => (Entity c -> m a) -> Slice c -> m [a]
+ Apecs.Slice: mapMC :: forall w c a. Has w c => ((Entity c, Safe c) -> System w a) -> Slice c -> System w [a]
+ Apecs.Slice: mapMC_ :: forall w c a. Has w c => ((Entity c, Safe c) -> System w a) -> Slice c -> System w ()
+ Apecs.Slice: mapM_ :: Monad m => (Entity c -> m a) -> Slice c -> m ()
+ Apecs.Slice: null :: Slice a -> Bool
+ Apecs.Slice: size :: Slice a -> Int
+ Apecs.Stores: instance (GHC.TypeLits.KnownNat n, Apecs.Stores.Cachable s) => Apecs.Types.Store (Apecs.Stores.Cache n s)
+ Apecs.Stores: instance Apecs.Types.GlobalStore (Apecs.Stores.Const c)
+ Apecs.Stores: instance Apecs.Types.GlobalStore (Apecs.Stores.Global c)
+ Apecs.Stores: instance Apecs.Types.Store (Apecs.Stores.Global c)
+ Apecs.Types: class (SafeRW s ~ Stores s, Store s) => GlobalStore s
+ Apecs.Types: instance (Apecs.Types.GlobalStore a, Apecs.Types.GlobalStore b) => Apecs.Types.GlobalStore (a, b)
+ Apecs.Types: instance (Apecs.Types.GlobalStore a, Apecs.Types.GlobalStore b, Apecs.Types.GlobalStore c) => Apecs.Types.GlobalStore (a, b, c)
- Apecs: cimapM :: forall w c a. (Has w c, IsRuntime c) => ((Entity c, c) -> System w a) -> System w [a]
+ Apecs: cimapM :: forall w c a. Has w c => ((Entity c, c) -> System w a) -> System w [a]
- Apecs: cimapM_ :: forall w c. (Has w c, IsRuntime c) => ((Entity c, c) -> System w ()) -> System w ()
+ Apecs: cimapM_ :: forall w c. Has w c => ((Entity c, c) -> System w ()) -> System w ()
- Apecs: class Initializable (Storage c) => Component c where type Storage c = s | s -> c where {
+ Apecs: class (Stores (Storage c) ~ c, Store (Storage c)) => Component c where type Storage c = s | s -> c where {
- Apecs: cmap :: forall world c. (IsRuntime c, Has world c) => (c -> c) -> System world ()
+ Apecs: cmap :: forall world c. Has world c => (c -> c) -> System world ()
- Apecs: cmap' :: forall world c. (Has world c, IsRuntime c) => (c -> Safe c) -> System world ()
+ Apecs: cmap' :: forall world c. Has world c => (c -> Safe c) -> System world ()
- Apecs: cmapM :: forall w c a. (Has w c, IsRuntime c) => (c -> System w a) -> System w [a]
+ Apecs: cmapM :: forall w c a. Has w c => (c -> System w a) -> System w [a]
- Apecs: cmapM_ :: forall w c. (Has w c, IsRuntime c) => (c -> System w ()) -> System w ()
+ Apecs: cmapM_ :: forall w c. Has w c => (c -> System w ()) -> System w ()
- Apecs: destroy :: forall w c. (Has w c, HasMembers (Storage c)) => Entity c -> System w ()
+ Apecs: destroy :: forall w c. Has w c => Entity c -> System w ()
- Apecs: exists :: forall w c. (Has w c, HasMembers (Storage c)) => Entity c -> System w Bool
+ Apecs: exists :: forall w c. Has w c => Entity c -> System w Bool
- Apecs: get :: forall w c. (Store (Storage c), Has w c) => Entity c -> System w (Safe c)
+ Apecs: get :: forall w c. Has w c => Entity c -> System w (Safe c)
- Apecs: initStore :: (Initializable s, InitArgs s ~ ()) => IO s
+ Apecs: initStore :: (Store s, InitArgs s ~ ()) => IO s
- Apecs: initStoreWith :: Initializable s => InitArgs s -> IO s
+ Apecs: initStoreWith :: Store s => InitArgs s -> IO s
- Apecs: modify :: forall w c. (IsRuntime c, Has w c) => Entity c -> (c -> c) -> System w ()
+ Apecs: modify :: forall w c. Has w c => Entity c -> (c -> c) -> System w ()
- Apecs: modifyGlobal :: forall w c. (Has w c, GlobalRW (Storage c) c) => (c -> c) -> System w ()
+ Apecs: modifyGlobal :: forall w c. (Has w c, GlobalStore (Storage c)) => (c -> c) -> System w ()
- Apecs: newEntity :: (IsRuntime c, Has w c, Has w EntityCounter) => c -> System w (Entity c)
+ Apecs: newEntity :: (Store (Storage c), Has w c, Has w EntityCounter) => c -> System w (Entity c)
- Apecs: owners :: forall w c. (Has w c, HasMembers (Storage c)) => System w (Slice c)
+ Apecs: owners :: forall w c. Has w c => System w (Slice c)
- Apecs: readGlobal :: forall w c. (Has w c, GlobalRW (Storage c) c) => System w c
+ Apecs: readGlobal :: forall w c. (Has w c, GlobalStore (Storage c)) => System w c
- Apecs: resetStore :: forall w c p. (Has w c, HasMembers (Storage c)) => p c -> System w ()
+ Apecs: resetStore :: forall w c p. Has w c => p c -> System w ()
- Apecs: rmap :: forall world r w. (Has world w, Has world r, IsRuntime w, IsRuntime r) => (r -> w) -> System world ()
+ Apecs: rmap :: forall world r w. (Has world w, Has world r) => (r -> w) -> System world ()
- Apecs: rmap' :: forall world r w. (Has world w, Has world r, Store (Storage w), IsRuntime r) => (r -> Safe w) -> System world ()
+ Apecs: rmap' :: forall world r w. (Has world w, Has world r, Store (Storage r), Store (Storage w)) => (r -> Safe w) -> System world ()
- Apecs: set :: forall w c e. (IsRuntime c, Has w c) => Entity e -> c -> System w ()
+ Apecs: set :: forall w c e. Has w c => Entity e -> c -> System w ()
- Apecs: set' :: forall w c. (IsRuntime c, Has w c) => Entity c -> Safe c -> System w ()
+ Apecs: set' :: forall w c. Has w c => Entity c -> Safe c -> System w ()
- Apecs: wmap :: forall world r w. (Has world w, Has world r, IsRuntime w, IsRuntime r) => (Safe r -> w) -> System world ()
+ Apecs: wmap :: forall world r w. (Has world w, Has world r, Store (Storage r), Store (Storage w)) => (Safe r -> w) -> System world ()
- Apecs: wmap' :: forall world r w. (Has world w, Has world r, Store (Storage w), IsRuntime r) => (Safe r -> Safe w) -> System world ()
+ Apecs: wmap' :: forall world r w. (Has world w, Has world r, Store (Storage r), Store (Storage w)) => (Safe r -> Safe w) -> System world ()
- Apecs: writeGlobal :: forall w c. (Has w c, GlobalRW (Storage c) c) => c -> System w ()
+ Apecs: writeGlobal :: forall w c. (Has w c, GlobalStore (Storage c)) => c -> System w ()
- Apecs.Logs: getLog :: forall w c l. (IsRuntime c, Has w c, HasLog (Storage c) l, Log l c) => System w (l c)
+ Apecs.Logs: getLog :: forall w c l. (Store (Storage c), Has w c, HasLog (Storage c) l, Log l c) => System w (l c)
- Apecs.Stores: class (Initializable s, HasMembers s, Store s, SafeRW s ~ Maybe (Stores s)) => Cachable s
+ Apecs.Stores: class (Store s, SafeRW s ~ Maybe (Stores s)) => Cachable s
- Apecs.System: cimapM :: forall w c a. (Has w c, IsRuntime c) => ((Entity c, c) -> System w a) -> System w [a]
+ Apecs.System: cimapM :: forall w c a. Has w c => ((Entity c, c) -> System w a) -> System w [a]
- Apecs.System: cimapM_ :: forall w c. (Has w c, IsRuntime c) => ((Entity c, c) -> System w ()) -> System w ()
+ Apecs.System: cimapM_ :: forall w c. Has w c => ((Entity c, c) -> System w ()) -> System w ()
- Apecs.System: cmap :: forall world c. (IsRuntime c, Has world c) => (c -> c) -> System world ()
+ Apecs.System: cmap :: forall world c. Has world c => (c -> c) -> System world ()
- Apecs.System: cmap' :: forall world c. (Has world c, IsRuntime c) => (c -> Safe c) -> System world ()
+ Apecs.System: cmap' :: forall world c. Has world c => (c -> Safe c) -> System world ()
- Apecs.System: cmapM :: forall w c a. (Has w c, IsRuntime c) => (c -> System w a) -> System w [a]
+ Apecs.System: cmapM :: forall w c a. Has w c => (c -> System w a) -> System w [a]
- Apecs.System: cmapM_ :: forall w c. (Has w c, IsRuntime c) => (c -> System w ()) -> System w ()
+ Apecs.System: cmapM_ :: forall w c. Has w c => (c -> System w ()) -> System w ()
- Apecs.System: destroy :: forall w c. (Has w c, HasMembers (Storage c)) => Entity c -> System w ()
+ Apecs.System: destroy :: forall w c. Has w c => Entity c -> System w ()
- Apecs.System: exists :: forall w c. (Has w c, HasMembers (Storage c)) => Entity c -> System w Bool
+ Apecs.System: exists :: forall w c. Has w c => Entity c -> System w Bool
- Apecs.System: get :: forall w c. (Store (Storage c), Has w c) => Entity c -> System w (Safe c)
+ Apecs.System: get :: forall w c. Has w c => Entity c -> System w (Safe c)
- Apecs.System: imapM :: forall w c a. (Has w c, HasMembers (Storage c)) => (Entity c -> System w a) -> System w [a]
+ Apecs.System: imapM :: forall w c a. Has w c => (Entity c -> System w a) -> System w [a]
- Apecs.System: imapM_ :: forall w c. (Has w c, HasMembers (Storage c)) => (Entity c -> System w ()) -> System w ()
+ Apecs.System: imapM_ :: forall w c. Has w c => (Entity c -> System w ()) -> System w ()
- Apecs.System: modify :: forall w c. (IsRuntime c, Has w c) => Entity c -> (c -> c) -> System w ()
+ Apecs.System: modify :: forall w c. Has w c => Entity c -> (c -> c) -> System w ()
- Apecs.System: modifyGlobal :: forall w c. (Has w c, GlobalRW (Storage c) c) => (c -> c) -> System w ()
+ Apecs.System: modifyGlobal :: forall w c. (Has w c, GlobalStore (Storage c)) => (c -> c) -> System w ()
- Apecs.System: owners :: forall w c. (Has w c, HasMembers (Storage c)) => System w (Slice c)
+ Apecs.System: owners :: forall w c. Has w c => System w (Slice c)
- Apecs.System: readGlobal :: forall w c. (Has w c, GlobalRW (Storage c) c) => System w c
+ Apecs.System: readGlobal :: forall w c. (Has w c, GlobalStore (Storage c)) => System w c
- Apecs.System: resetStore :: forall w c p. (Has w c, HasMembers (Storage c)) => p c -> System w ()
+ Apecs.System: resetStore :: forall w c p. Has w c => p c -> System w ()
- Apecs.System: rmap :: forall world r w. (Has world w, Has world r, IsRuntime w, IsRuntime r) => (r -> w) -> System world ()
+ Apecs.System: rmap :: forall world r w. (Has world w, Has world r) => (r -> w) -> System world ()
- Apecs.System: rmap' :: forall world r w. (Has world w, Has world r, Store (Storage w), IsRuntime r) => (r -> Safe w) -> System world ()
+ Apecs.System: rmap' :: forall world r w. (Has world w, Has world r, Store (Storage r), Store (Storage w)) => (r -> Safe w) -> System world ()
- Apecs.System: set :: forall w c e. (IsRuntime c, Has w c) => Entity e -> c -> System w ()
+ Apecs.System: set :: forall w c e. Has w c => Entity e -> c -> System w ()
- Apecs.System: set' :: forall w c. (IsRuntime c, Has w c) => Entity c -> Safe c -> System w ()
+ Apecs.System: set' :: forall w c. Has w c => Entity c -> Safe c -> System w ()
- Apecs.System: wmap :: forall world r w. (Has world w, Has world r, IsRuntime w, IsRuntime r) => (Safe r -> w) -> System world ()
+ Apecs.System: wmap :: forall world r w. (Has world w, Has world r, Store (Storage r), Store (Storage w)) => (Safe r -> w) -> System world ()
- Apecs.System: wmap' :: forall world r w. (Has world w, Has world r, Store (Storage w), IsRuntime r) => (Safe r -> Safe w) -> System world ()
+ Apecs.System: wmap' :: forall world r w. (Has world w, Has world r, Store (Storage r), Store (Storage w)) => (Safe r -> Safe w) -> System world ()
- Apecs.System: writeGlobal :: forall w c. (Has w c, GlobalRW (Storage c) c) => c -> System w ()
+ Apecs.System: writeGlobal :: forall w c. (Has w c, GlobalStore (Storage c)) => c -> System w ()
- Apecs.Types: class Initializable (Storage c) => Component c where type Storage c = s | s -> c where {
+ Apecs.Types: class (Stores (Storage c) ~ c, Store (Storage c)) => Component c where type Storage c = s | s -> c where {
- Apecs.Types: class HasMembers s => Store s where type SafeRW s type Stores s explModify s ety f = do { etyExists <- explExists s ety; when etyExists $ explGetUnsafe s ety >>= explSet s ety . f } explCmap s f = explMembers s >>= mapM_ (\ ety -> explModify s ety f) explCmapM_ s sys = do { sl <- liftIO $ explMembers s; forM_ sl $ \ ety -> do { x :: Stores s <- liftIO $ explGetUnsafe s ety; sys x } } explCimapM_ s sys = do { sl <- liftIO $ explMembers s; forM_ sl $ \ ety -> do { x :: Stores s <- liftIO $ explGetUnsafe s ety; sys (ety, x) } } explCmapM s sys = do { sl <- liftIO $ explMembers s; for (toList sl) $ \ ety -> do { x :: Stores s <- liftIO $ explGetUnsafe s ety; sys x } } explCimapM s sys = do { sl <- liftIO $ explMembers s; for (toList sl) $ \ ety -> do { x :: Stores s <- liftIO $ explGetUnsafe s ety; sys (ety, x) } } where {
+ Apecs.Types: class Store s where type Stores s type SafeRW s type InitArgs s explReset s = do { sl <- explMembers s; mapM_ (explDestroy s) sl } explImapM_ s ma = liftIO (explMembers s) >>= mapM_ ma . toList explImapM s ma = liftIO (explMembers s) >>= mapM ma . toList explModify s ety f = do { etyExists <- explExists s ety; when etyExists $ explGetUnsafe s ety >>= explSet s ety . f } explCmap s f = explMembers s >>= mapM_ (\ ety -> explModify s ety f) explCmapM_ s sys = do { sl <- liftIO $ explMembers s; forM_ sl $ \ ety -> do { x :: Stores s <- liftIO $ explGetUnsafe s ety; sys x } } explCimapM_ s sys = do { sl <- liftIO $ explMembers s; forM_ sl $ \ ety -> do { x :: Stores s <- liftIO $ explGetUnsafe s ety; sys (ety, x) } } explCmapM s sys = do { sl <- liftIO $ explMembers s; for (toList sl) $ \ ety -> do { x :: Stores s <- liftIO $ explGetUnsafe s ety; sys x } } explCimapM s sys = do { sl <- liftIO $ explMembers s; for (toList sl) $ \ ety -> do { x :: Stores s <- liftIO $ explGetUnsafe s ety; sys (ety, x) } } where {
- Apecs.Types: explDestroy :: HasMembers s => s -> Int -> IO ()
+ Apecs.Types: explDestroy :: Store s => s -> Int -> IO ()
- Apecs.Types: explExists :: HasMembers s => s -> Int -> IO Bool
+ Apecs.Types: explExists :: Store s => s -> Int -> IO Bool
- Apecs.Types: explImapM :: (HasMembers s, MonadIO m) => s -> (Int -> m a) -> m [a]
+ Apecs.Types: explImapM :: (Store s, MonadIO m) => s -> (Int -> m a) -> m [a]
- Apecs.Types: explImapM_ :: (HasMembers s, MonadIO m) => s -> (Int -> m a) -> m ()
+ Apecs.Types: explImapM_ :: (Store s, MonadIO m) => s -> (Int -> m a) -> m ()
- Apecs.Types: explMembers :: HasMembers s => s -> IO (Vector Int)
+ Apecs.Types: explMembers :: Store s => s -> IO (Vector Int)
- Apecs.Types: explReset :: HasMembers s => s -> IO ()
+ Apecs.Types: explReset :: Store s => s -> IO ()
- Apecs.Types: initStoreWith :: Initializable s => InitArgs s -> IO s
+ Apecs.Types: initStoreWith :: Store s => InitArgs s -> IO s
- Apecs.Types: type family Stores s;
+ Apecs.Types: type family InitArgs s;
- Apecs.Util: initStore :: (Initializable s, InitArgs s ~ ()) => IO s
+ Apecs.Util: initStore :: (Store s, InitArgs s ~ ()) => IO s
- Apecs.Util: newEntity :: (IsRuntime c, Has w c, Has w EntityCounter) => c -> System w (Entity c)
+ Apecs.Util: newEntity :: (Store (Storage c), Has w c, Has w EntityCounter) => c -> System w (Entity c)

Files

apecs.cabal view
@@ -1,5 +1,5 @@ name:                apecs-version:             0.2.1.1+version:             0.2.2.0 homepage:            https://github.com/jonascarpay/apecs#readme license:             BSD3 license-file:        LICENSE
bench/Main.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE Strict, ScopedTypeVariables, DataKinds, TypeFamilies, MultiParamTypeClasses, TypeOperators #-}+{-# LANGUAGE FlexibleContexts, FlexibleInstances #-}  import Criterion import qualified Criterion.Main as C@@ -7,70 +8,74 @@ import Apecs as A import Apecs.Stores import Apecs.Util+import qualified Apecs.Slice as S  import Linear -newtype Position = Position (V2 Float) deriving (Eq, Show)-instance Component Position where-  type Storage Position = Cache 10000 (Map Position)+data Group w1 w2 = Group+  { groupName :: String+  , naiveWorld :: IO w1+  , naiveInit :: System w1 ()+  , naiveRun  :: System w1 ()+  , improvedWorld :: IO w1+  , improvedInit :: System w1 ()+  , improvedRun  :: System w1 () } -newtype Velocity = Velocity (V2 Float) deriving (Eq, Show)-instance Component Velocity where-  type Storage Velocity = Cache 1000 (Map Velocity)+toBench (Group name w1 i1 r1 w2 i2 r2) =+  bgroup name+    [ bgroup "naive"    [bench "init" $ whnfIO (w1 >>= runSystem i1), bench "init and run" $ whnfIO (w2 >>= runSystem (i1 >> r1))]+    , bgroup "improved" [bench "init" $ whnfIO (w1 >>= runSystem i1), bench "init and run" $ whnfIO (w2 >>= runSystem (i2 >> r2))]+    ] -data World = World-  { positions     :: Storage Position-  , velocities    :: Storage Velocity-  , entityCounter :: Storage EntityCounter-  }+data W1 c = W1 {w1c1 :: (Storage c), w1ec :: Storage EntityCounter}+instance Component c => Has (W1 c) c where getStore = System $ asks w1c1+instance Has (W1 c) EntityCounter where getStore = System $ asks w1ec -instance World `Has` Position where-  getStore = System $ asks positions+w1with args = W1 <$> initStoreWith args <*> initCounter+w1 = w1with ()+w2with a1 a2 = W2 <$> initStoreWith a1 <*> initStoreWith a2 <*> initCounter+w2 = w2with () () -instance World `Has` Velocity where-  getStore = System $ asks velocities+data W2 a b = W2 { w2c1 :: Storage a , w2c2 :: Storage b, w2ec :: Storage EntityCounter}+instance (Component a, Component b) => Has (W2 a b) a where getStore = System $ asks w2c1+instance (Component a, Component b) => Has (W2 a b) b where getStore = System $ asks w2c2+instance Has (W2 a b) EntityCounter where getStore = System $ asks w2ec -instance World `Has` EntityCounter where-  getStore = System $ asks entityCounter+--Explicit vs implicit map+newtype Counter = Counter Int+instance Component Counter where type Storage Counter = Map Counter -emptyWorld :: IO World-emptyWorld = liftM3 World initStore initStore initCounter+mapExample = Group+  { groupName     = "Single component map"+  , naiveWorld    = w1 :: IO (W1 Counter)+  , naiveInit     = replicateM_ 10 (newEntity (Counter 0))+  , naiveRun      = owners >>= S.mapM_ (\(e :: Entity Counter) -> set e (Counter 1))+  , improvedWorld = w1 :: IO (W1 Counter)+  , improvedInit  = replicateM_ 10 (newEntity (Counter 0))+  , improvedRun   = cmap (const (Counter 1))+  } -cStep (Velocity v, Position p) = (Velocity v, Position (p+v))-rStep (Velocity v, Position p) = Position (p+v) -rStep' :: (Velocity, Position) -> Safe Position-rStep' (Velocity v, Position p) = Safe (Just (Position (p+v)))--wStep' :: Safe (Velocity, Position) -> Safe Position-wStep' (Safe (Just (Velocity v), Just (Position p))) = Safe (Just (Position (p+v)))--wStep :: Safe (Velocity, Position) -> Position-wStep (Safe (Just (Velocity v), Just (Position p))) = Position (p+v)+-- ecs_bench+newtype ECSPos = ECSPos (V2 Float) deriving (Eq, Show)+instance Component ECSPos where type Storage ECSPos = Cache 10000 (Map ECSPos) -{-# INLINE vstep #-}-vstep :: System World ()-vstep = cimapM_ $ \(e,(Velocity v,Position p)) -> set (cast e) (Position (p+v))+newtype ECSVel = ECSVel (V2 Float) deriving (Eq, Show)+instance Component ECSVel where type Storage ECSVel = Cache 1000 (Map ECSVel) -explicit = do sl :: Slice (Velocity, Position) <- owners-              sliceForMC_ sl $ \(e,Safe (Just (Velocity v), Just (Position p))) -> set (cast e) (Position $ p + v)+pvInit = do replicateM_ 1000 (newEntity (ECSPos 0, ECSVel 1))+            replicateM_ 9000 (newEntity (ECSPos 0)) -cStep1 (Velocity p) = (Velocity (p+1))+pvStep = rmap $ \(ECSVel v, ECSPos p) -> ECSPos (p+v) -initialize :: System World ()-initialize = do replicateM_ 1000 $ newEntity (Position 0, Velocity 1)-                replicateM_ 9000 $ newEntity (Position 0)+pvWorld :: IO (W2 ECSPos ECSVel)+pvWorld = w2  main :: IO ()-main = C.defaultMain [ bench "init" $ whnfIO (emptyWorld >>= runSystem initialize)-                     , bgroup "init and step"-                       [ bench "cmap"   $ whnfIO (emptyWorld >>= runSystem (initialize >> cmap  cStep))-                       , bench "cmap1"  $ whnfIO (emptyWorld >>= runSystem (initialize >> cmap  cStep1))-                       , bench "rmap"   $ whnfIO (emptyWorld >>= runSystem (initialize >> rmap  rStep))-                       , bench "rmap'"  $ whnfIO (emptyWorld >>= runSystem (initialize >> rmap' rStep'))-                       , bench "wmap"   $ whnfIO (emptyWorld >>= runSystem (initialize >> wmap  wStep))-                       , bench "wmap'"  $ whnfIO (emptyWorld >>= runSystem (initialize >> wmap' wStep'))-                       , bench "vstep"  $ whnfIO (emptyWorld >>= runSystem (initialize >> vstep))-                       , bench "forMC_" $ whnfIO (emptyWorld >>= runSystem (initialize >> explicit))-                       ]-                     ]+main = C.defaultMain+  [ bgroup "ecs_bench"+    [ bench "init" $ whnfIO (pvWorld >>= runSystem pvInit)+    , bench "step" $ whnfIO (pvWorld >>= runSystem (pvInit >> pvStep))+    ]+  , toBench mapExample+  ]
src/Apecs.hs view
@@ -28,9 +28,6 @@     runSystem, runWith,     initStore, runGC, EntityCounter, initCounter, newEntity, -  -- All slice functions-  module SL,-   -- Reader   asks, ask, liftIO, lift, ) where@@ -39,7 +36,6 @@  import Apecs.Types import Apecs.System-import Apecs.Slice as SL import Apecs.Stores import Apecs.Util 
src/Apecs/Logs.hs view
@@ -20,7 +20,7 @@  import Apecs.Types import Apecs.Stores-import Apecs.Slice+import qualified Apecs.Slice as Sl  -- | A PureLog is a piece of state @l c@ that is updated when components @c@ are written or destroyed. --   Note that @l :: * -> *@@@ -45,7 +45,7 @@  -- | Produces the log indicated by the return type. {-# INLINE getLog #-}-getLog :: forall w c l. (IsRuntime c, Has w c, HasLog (Storage c) l, Log l c) => System w (l c)+getLog :: forall w c l. (Store (Storage c), Has w c, HasLog (Storage c) l, Log l c) => System w (l c) getLog = do s :: Storage c <- getStore             return (explGetLog s) @@ -62,14 +62,14 @@   {-# INLINE logReset #-}   logReset (FromPure lref) = writeIORef lref pureEmpty --- | A @Logger l@ of some store updates its @Log l@ with the writes and deletes to @Store s@+-- | A @Logger l@ of some store updates its @Log l@ with the writes and deletes to store @s@ data Logger l s = Logger (l (Stores s)) s -instance (Log l (Stores s), Cachable s) => Initializable (Logger l s) where+instance (Log l (Stores s), Cachable s) => Store (Logger l s) where   type InitArgs (Logger l s) = InitArgs s+  type Stores (Logger l s) = Stores s   initStoreWith args = Logger <$> logEmpty <*> initStoreWith args -instance (Log l (Stores s), Cachable s) => HasMembers (Logger l s) where   {-# INLINE explDestroy #-}   explDestroy (Logger l s) ety = do     mc <- explGet s ety@@ -88,9 +88,7 @@   {-# INLINE explImapM #-}   explImapM (Logger _ s) = explImapM s -instance (Log l (Stores s), Cachable s) => Store (Logger l s) where   type SafeRW (Logger l s) = SafeRW s-  type Stores (Logger l s) = Stores s    {-# INLINE explGetUnsafe #-}   explGetUnsafe (Logger _ s) ety = explGetUnsafe s ety@@ -199,9 +197,9 @@ byIndex (EnumTable vec) c   | c < 0                  = return mempty   | c >= VM.length vec - 1 = return mempty-  | otherwise = liftIO$ sliceFromList . S.toList <$> VM.read vec c+  | otherwise = liftIO$ Sl.fromList . S.toList <$> VM.read vec c  -- | Query the @EnumTable@ by an example enum. --   Will not perform bound checks, so crashes if `fromEnum c < 0 && fromEnum c > fromEnum maxBound `. byEnum :: Enum c => EnumTable c -> c -> System w (Slice c)-byEnum (EnumTable vec) c = liftIO$ sliceFromList . S.toList <$> VM.read vec (fromEnum c)+byEnum (EnumTable vec) c = liftIO$ Sl.fromList . S.toList <$> VM.read vec (fromEnum c)
src/Apecs/Slice.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE FlexibleContexts, FlexibleInstances #-} +-- | This module is designed to be imported with qualified module Apecs.Slice where  import qualified Data.Vector.Unboxed as U@@ -10,85 +11,85 @@ import Apecs.Types  -- | Slice version of foldM_-{-# INLINE sliceFoldM_ #-}-sliceFoldM_ :: (a -> Entity c -> System w a) -> a -> Slice b -> System w ()-sliceFoldM_ f seed (Slice sl) = U.foldM'_ ((.Entity) . f) seed sl+{-# INLINE foldM_ #-}+foldM_ :: (a -> Entity c -> System w a) -> a -> Slice b -> System w ()+foldM_ f seed (Slice sl) = U.foldM'_ ((.Entity) . f) seed sl  -- | Gets the size of a slice (O(n))-{-# INLINE sliceSize #-}-sliceSize :: Slice a -> Int-sliceSize (Slice vec) = U.length vec+{-# INLINE size #-}+size :: Slice a -> Int+size (Slice vec) = U.length vec  -- | Tests whether a slice is empty (O(1))-{-# INLINE sliceNull #-}-sliceNull :: Slice a -> Bool-sliceNull (Slice vec) = U.null vec+{-# INLINE null #-}+null :: Slice a -> Bool+null (Slice vec) = U.null vec  -- | Construct a slice from a list of IDs-{-# INLINE sliceFromList #-}-sliceFromList :: [Int] -> Slice a-sliceFromList = Slice . U.fromList+{-# INLINE fromList #-}+fromList :: [Int] -> Slice a+fromList = Slice . U.fromList  -- | Monadically filter a slice-{-# INLINE sliceFilterM #-}-sliceFilterM :: (Entity c -> System w Bool) -> Slice c -> System w (Slice c)-sliceFilterM fm (Slice vec) = Slice <$> U.filterM (fm . Entity) vec+{-# INLINE filterM #-}+filterM :: (Entity c -> System w Bool) -> Slice c -> System w (Slice c)+filterM fm (Slice vec) = Slice <$> U.filterM (fm . Entity) vec  -- | Concatenates two slices. Equivalent to mappend-{-# INLINE sliceConcat #-}-sliceConcat :: Slice a -> Slice b -> Slice c-sliceConcat (Slice a) (Slice b) = Slice (a U.++ b)+{-# INLINE concat #-}+concat :: Slice a -> Slice b -> Slice c+concat (Slice a) (Slice b) = Slice (a U.++ b)  -- Slice traversal -- | Slice version of forM_-{-# INLINE sliceForM_ #-}-sliceForM_ :: Monad m => Slice c -> (Entity c -> m b) -> m ()-sliceForM_ (Slice vec) ma = U.forM_ vec (ma . Entity)+{-# INLINE forM_ #-}+forM_ :: Monad m => Slice c -> (Entity c -> m b) -> m ()+forM_ (Slice vec) ma = U.forM_ vec (ma . Entity)  -- | Slice version of forM-{-# INLINE sliceForM #-}-sliceForM :: Monad m => Slice c -> (Entity c -> m a) -> m [a]-sliceForM (Slice vec) ma = traverse (ma . Entity) (U.toList vec)+{-# INLINE forM #-}+forM :: Monad m => Slice c -> (Entity c -> m a) -> m [a]+forM (Slice vec) ma = traverse (ma . Entity) (U.toList vec)  -- | Iterates over a slice, and reads the components of the Slice's type argument.-{-# INLINE sliceForMC #-}-sliceForMC :: forall w c a. (Store (Storage c), Has w c) => Slice c -> ((Entity c,Safe c) -> System w a) -> System w [a]-sliceForMC (Slice vec) sys = do+{-# INLINE forMC #-}+forMC :: forall w c a. Has w c => Slice c -> ((Entity c,Safe c) -> System w a) -> System w [a]+forMC (Slice vec) sys = do   s :: Storage c <- getStore   for (U.toList vec) $ \e -> do     r <- liftIO$ explGet s e     sys (Entity e, Safe r)  -- | Iterates over a slice, and reads the components of the Slice's type argument.-{-# INLINE sliceForMC_ #-}-sliceForMC_ :: forall w c a. (Store (Storage c), Has w c) => Slice c -> ((Entity c,Safe c) -> System w a) -> System w ()-sliceForMC_ (Slice vec) sys = do+{-# INLINE forMC_ #-}+forMC_ :: forall w c a. Has w c => Slice c -> ((Entity c,Safe c) -> System w a) -> System w ()+forMC_ (Slice vec) sys = do   s :: Storage c <- getStore   U.forM_ vec $ \e -> do     r <- liftIO$ explGet s e     sys (Entity e, Safe r)  -- | Slice version of mapM_-{-# INLINE sliceMapM_ #-}-sliceMapM_ :: Monad m => (Entity c -> m a) -> Slice c -> m ()-sliceMapM_ ma (Slice vec) = U.mapM_ (ma . Entity) vec+{-# INLINE mapM_ #-}+mapM_ :: Monad m => (Entity c -> m a) -> Slice c -> m ()+mapM_ ma (Slice vec) = U.mapM_ (ma . Entity) vec  -- | Slice version of mapM-{-# INLINE sliceMapM #-}-sliceMapM :: Monad m => (Entity c -> m a) -> Slice c -> m [a]-sliceMapM ma (Slice vec) = traverse (ma . Entity) (U.toList vec)+{-# INLINE mapM #-}+mapM :: Monad m => (Entity c -> m a) -> Slice c -> m [a]+mapM ma (Slice vec) = traverse (ma . Entity) (U.toList vec)  -- | Iterates over a slice, and reads the components of the Slice's type argument.-{-# INLINE sliceMapMC #-}-sliceMapMC :: forall w c a. (Store (Storage c), Has w c) => ((Entity c,Safe c) -> System w a) -> Slice c -> System w [a]-sliceMapMC sys (Slice vec) = do+{-# INLINE mapMC #-}+mapMC :: forall w c a. Has w c => ((Entity c,Safe c) -> System w a) -> Slice c -> System w [a]+mapMC sys (Slice vec) = do   s :: Storage c <- getStore   for (U.toList vec) $ \e -> do     r <- liftIO$ explGet s e     sys (Entity e, Safe r)  -- | Iterates over a slice, and reads the components of the Slice's type argument.-{-# INLINE sliceMapMC_ #-}-sliceMapMC_ :: forall w c a. (Store (Storage c), Has w c) => ((Entity c, Safe c) -> System w a) -> Slice c -> System w ()-sliceMapMC_ sys vec = sliceForMC_ vec sys+{-# INLINE mapMC_ #-}+mapMC_ :: forall w c a. Has w c => ((Entity c, Safe c) -> System w a) -> Slice c -> System w ()+mapMC_ sys vec = forMC_ vec sys 
src/Apecs/Stores.hs view
@@ -25,13 +25,18 @@  import Apecs.Types +{-# INLINE defaultSetMaybe #-}+defaultSetMaybe :: (Store s, SafeRW s ~ Maybe (Stores s)) => s -> Int -> Maybe (Stores s) -> IO ()+defaultSetMaybe s e Nothing  = explDestroy s e+defaultSetMaybe s e (Just c) = explSet s e c+ -- | A map from Data.Intmap.Strict. O(n log(n)) for most operations. --   Yields safe runtime representations of type @Maybe c@. newtype Map c = Map (IORef (M.IntMap c))-instance Initializable (Map c) where+instance Store (Map c) where   type InitArgs (Map c) = ()+  type Stores (Map c) = c   initStoreWith _ = Map <$> newIORef mempty-instance HasMembers (Map c) where   explDestroy (Map ref) ety = modifyIORef' ref (M.delete ety)   explMembers (Map ref)     = U.fromList . M.keys <$> readIORef ref   explExists  (Map ref) ety = M.member ety <$> readIORef ref@@ -40,14 +45,11 @@   {-# INLINE explMembers #-}   {-# INLINE explExists #-}   {-# INLINE explReset #-}-instance Store (Map c) where   type SafeRW (Map c) = Maybe c-  type Stores (Map c) = c   explGetUnsafe (Map ref) ety = fromJust . M.lookup ety <$> readIORef ref   explGet       (Map ref) ety = M.lookup ety <$> readIORef ref   explSet       (Map ref) ety x = modifyIORef' ref $ M.insert ety x-  explSetMaybe  s ety Nothing = explDestroy s ety-  explSetMaybe  s ety (Just x) = explSet s ety x+  explSetMaybe = defaultSetMaybe   explModify    (Map ref) ety f = modifyIORef' ref $ M.adjust f ety   explCmap      (Map ref) f = modifyIORef' ref $ M.map f   explCmapM_    (Map ref) ma = liftIO (readIORef ref) >>= mapM_ ma@@ -72,10 +74,10 @@ -- | A store that keeps membership, but holds no values. --   Produces @flag@ runtime values. newtype Set c = Set (IORef S.IntSet)-instance Initializable (Set c) where+instance Flag c => Store (Set c) where   type InitArgs (Set c) = ()+  type Stores (Set c) = c   initStoreWith _ = Set <$> newIORef mempty-instance HasMembers (Set c) where   explDestroy (Set ref) ety = modifyIORef' ref (S.delete ety)   explMembers (Set ref) = U.fromList . S.toList <$> readIORef ref   explReset (Set ref) = writeIORef ref mempty@@ -88,9 +90,7 @@   {-# INLINE explReset #-}   {-# INLINE explImapM_ #-}   {-# INLINE explImapM #-}-instance (Flag c) => Store (Set c) where   type SafeRW (Set c) = Bool-  type Stores (Set c) = c   explGetUnsafe _ _ = return flag   explGet (Set ref) ety = S.member ety <$> readIORef ref   explSet (Set ref) ety _ = modifyIORef' ref $ S.insert ety@@ -112,10 +112,10 @@ -- | A Unique contains exactly one component belonging to some entity. --   Writing to it overwrites both the previous component and its owner. data Unique c = Unique (IORef Int) (IORef c)-instance Initializable (Unique c) where+instance Store (Unique c) where   type InitArgs (Unique c) = ()+  type Stores (Unique c) = c   initStoreWith _ = Unique <$> newIORef (-1) <*> newIORef undefined-instance HasMembers (Unique c) where   explDestroy (Unique eref _) ety = do e <- readIORef eref; when (e==ety) (writeIORef eref (-1))   explMembers (Unique eref _) = U.singleton <$> readIORef eref   explReset   (Unique eref _) = writeIORef eref (-1)@@ -131,17 +131,14 @@   {-# INLINE explImapM_ #-}   {-# INLINE explImapM #-} -instance Store (Unique c) where   type SafeRW (Unique c) = Maybe c-  type Stores (Unique c) = c   explGetUnsafe (Unique _ cref) _ = readIORef cref   explGet       (Unique eref cref) ety = do     e <- readIORef eref     if e == ety then Just <$> readIORef cref else return Nothing    explSet       (Unique eref cref) ety x = writeIORef eref ety >> writeIORef cref x-  explSetMaybe  s ety Nothing = explDestroy s ety-  explSetMaybe  s ety (Just x) = explSet s ety x+  explSetMaybe = defaultSetMaybe   explCmap      (Unique _    cref) f = modifyIORef' cref f   explModify    (Unique eref cref) ety f = do     e <- readIORef eref@@ -175,55 +172,55 @@  -- | Constant value. Not very practical, but fun to write. newtype Const c = Const c-instance Initializable (Const c) where+instance Store (Const c) where   type InitArgs (Const c) = c+  type Stores (Const c) = c   initStoreWith c = return$ Const c-instance GlobalRW (Const c) c where-  explGlobalRead  (Const c) = return c-  explGlobalWrite  _ _ = return ()-  explGlobalModify _ _ = return ()-instance HasMembers (Const c) where   explDestroy _ _ = return ()   explExists  _ _  = return False   explMembers _ = return mempty   explReset _ = return ()-instance Store (Const c) where   type SafeRW (Const c) = c-  type Stores (Const c) = c   explGetUnsafe (Const c) _ = return c   explGet       (Const c) _ = return c   explSet       _ _ _ = return ()   explSetMaybe  _ _ _ = return ()   explModify    _ _ _ = return ()   explCmap       _ _ = return ()+instance GlobalStore (Const c) where  -- | Global value. --   Must be given an initial value upon construction. newtype Global c = Global (IORef c)-instance Initializable (Global c) where+instance GlobalStore (Global c) where+instance Store (Global c) where   type InitArgs (Global c) = c+  type Stores   (Global c) = c   initStoreWith c = Global <$> newIORef c -instance GlobalRW (Global c) c where-  explGlobalRead   (Global ref) = readIORef    ref-  explGlobalWrite  (Global ref) = writeIORef   ref-  explGlobalModify (Global ref) = modifyIORef' ref-  {-# INLINE explGlobalRead #-}-  {-# INLINE explGlobalWrite #-}-  {-# INLINE explGlobalModify #-}+  type SafeRW (Global c) = c+  explDestroy _ _ = return ()+  explExists _ _ = return False+  explGetUnsafe (Global ref) _ = readIORef ref+  explGet (Global ref) _ = readIORef ref+  explSet (Global ref) _ c = writeIORef ref c+  explSetMaybe = explSet+  explMembers = return mempty + -- | A cache around another store. --   The wrapped store must produce safe representations using Maybe. --   Note that iterating over a cache is linear in its size, so large, sparsely populated caches will actually decrease performance. data Cache (n :: Nat) s =   Cache Int (UM.IOVector Int) (VM.IOVector (Stores s)) s -class (Initializable s, HasMembers s, Store s, SafeRW s ~ Maybe (Stores s)) => Cachable s+class (Store s, SafeRW s ~ Maybe (Stores s)) => Cachable s instance Cachable (Map s) instance (KnownNat n, Cachable s) => Cachable (Cache n s) -instance (KnownNat n, Cachable s) => Initializable (Cache n s) where+instance (KnownNat n, Cachable s) => Store (Cache n s) where   type InitArgs (Cache n s) = (InitArgs s)+  type Stores (Cache n s) = Stores s   initStoreWith args = do     let n = fromIntegral$ natVal (Proxy @n)     tags <- UM.replicate n (-1)@@ -231,7 +228,6 @@     child <- initStoreWith args     return (Cache n tags cache child) -instance Cachable s => HasMembers (Cache n s) where   {-# INLINE explDestroy #-}   explDestroy (Cache n tags _ s) ety = do     tag <- UM.unsafeRead tags (ety `mod` n)@@ -266,9 +262,7 @@     as2 <- explImapM s ma     return (as1 ++ as2) -instance Cachable s => Store (Cache n s) where   type SafeRW (Cache n s) = SafeRW s-  type Stores (Cache n s) = Stores s    {-# INLINE explGetUnsafe #-}   explGetUnsafe (Cache n tags cache s) ety = do@@ -297,8 +291,7 @@     VM.unsafeWrite cache index x    {-# INLINE explSetMaybe #-}-  explSetMaybe c ety Nothing  = explDestroy c ety-  explSetMaybe c ety (Just x) = explSet c ety x+  explSetMaybe = defaultSetMaybe    {-# INLINE explCmap #-}   explCmap (Cache n tags cache s) f = do
src/Apecs/System.hs view
@@ -24,7 +24,7 @@  -- | A slice containing all entities with component @c@ {-# INLINE owners #-}-owners :: forall w c. (Has w c, HasMembers (Storage c)) => System w (Slice c)+owners :: forall w c. Has w c => System w (Slice c) owners = do s :: Storage c <- getStore             liftIO$ Slice <$> explMembers s @@ -32,18 +32,19 @@ --   For composite components, this indicates whether the component --   has all its constituents {-# INLINE exists #-}-exists :: forall w c. (Has w c, HasMembers (Storage c)) => Entity c -> System w Bool+exists :: forall w c. Has w c => Entity c -> System w Bool exists (Entity n) = do s :: Storage c <- getStore                        liftIO$ explExists s n  -- | Destroys the component @c@ for the given entity {-# INLINE destroy #-}-destroy :: forall w c. (Has w c, HasMembers (Storage c)) => Entity c -> System w ()+destroy :: forall w c. Has w c => Entity c -> System w () destroy (Entity n) = do s :: Storage c <- getStore                         liftIO$ explDestroy s n  -- | Removes all components. Equivalent to manually iterating and deleting, but usually optimized.-resetStore :: forall w c p. (Has w c, HasMembers (Storage c)) => p c -> System w ()+{-# INLINE resetStore #-}+resetStore :: forall w c p. Has w c => p c -> System w () resetStore _ = do s :: Storage c <- getStore                   liftIO$ explReset s @@ -51,26 +52,27 @@ -- | Gets the component for a given entity. --   This is a safe access, because the entity might not have the requested components. {-# INLINE get #-}-get :: forall w c. (Store (Storage c), Has w c) => Entity c -> System w (Safe c)+get :: forall w c. Has w c => Entity c -> System w (Safe c) get (Entity ety) = do s :: Storage c <- getStore                       liftIO$ Safe <$> explGet s ety  -- | Writes a component to a given entity. Will overwrite existing components. {-# INLINE set #-}-set :: forall w c e. (IsRuntime c, Has w c) => Entity e -> c -> System w ()+set :: forall w c e. Has w c => Entity e -> c -> System w () set (Entity ety) x = do   s :: Storage c <- getStore   liftIO$ explSet s ety x  -- | Same as @set@, but uses Safe to possibly delete a component-set' :: forall w c. (IsRuntime c, Has w c) => Entity c -> Safe c -> System w ()+{-# INLINE set' #-}+set' :: forall w c. Has w c => Entity c -> Safe c -> System w () set' (Entity ety) (Safe c) = do   s :: Storage c <- getStore   liftIO$ explSetMaybe s ety c  -- | Applies a function if possible. Equivalent to reading, mapping, and writing, but stores can provide optimized implementations. {-# INLINE modify #-}-modify :: forall w c. (IsRuntime c, Has w c) => Entity c -> (c -> c) -> System w ()+modify :: forall w c. Has w c => Entity c -> (c -> c) -> System w () modify (Entity ety) f = do   s :: Storage c <- getStore   liftIO$ explModify s ety f@@ -78,56 +80,51 @@ {-# INLINE imapM_ #-} -- | Monadically iterate a system over all entities that have that component. --   Note that writing to the store while iterating over it is undefined behaviour.-imapM_ :: forall w c. (Has w c, HasMembers (Storage c))-       => (Entity c -> System w ()) -> System w ()+imapM_ :: forall w c. Has w c => (Entity c -> System w ()) -> System w () imapM_ sys = do s :: Storage c <- getStore                 explImapM_ s (sys . Entity)  {-# INLINE imapM #-} -- | Monadically iterate a system over all entities that have that component. --   Note that writing to the store while iterating over it is undefined behaviour.-imapM :: forall w c a. (Has w c, HasMembers (Storage c))+imapM :: forall w c a. Has w c       => (Entity c -> System w a) -> System w [a] imapM sys = do s :: Storage c <- getStore                explImapM s (sys . Entity)  -- | Maps a pure function over all components {-# INLINE cmap #-}-cmap :: forall world c. (IsRuntime c, Has world c) => (c -> c) -> System world ()+cmap :: forall world c. Has world c => (c -> c) -> System world () cmap f = do s :: Storage c <- getStore             liftIO$ explCmap s f  -- | mapM_ version of cmap {-# INLINE cmapM_ #-}-cmapM_ :: forall w c. (Has w c, IsRuntime c)-       => (c -> System w ()) -> System w ()+cmapM_ :: forall w c. Has w c => (c -> System w ()) -> System w () cmapM_ sys = do s :: Storage c <- getStore                 explCmapM_ s sys  -- | indexed cmapM_, also gives the current entity. {-# INLINE cimapM_ #-}-cimapM_ :: forall w c. (Has w c, IsRuntime c)-        => ((Entity c, c) -> System w ()) -> System w ()+cimapM_ :: forall w c. Has w c => ((Entity c, c) -> System w ()) -> System w () cimapM_ sys = do s :: Storage c <- getStore                  explCimapM_ s (\(e,c) -> sys (Entity e,c))  -- | mapM version of cmap. Can be used to get a list of entities {-# INLINE cmapM #-}-cmapM :: forall w c a. (Has w c, IsRuntime c)-      => (c -> System w a) -> System w [a]+cmapM :: forall w c a. Has w c => (c -> System w a) -> System w [a] cmapM sys = do s :: Storage c <- getStore                explCmapM s sys  -- | indexed cmapM, also gives the current entity. {-# INLINE cimapM #-}-cimapM :: forall w c a. (Has w c, IsRuntime c)-       => ((Entity c, c) -> System w a) -> System w [a]+cimapM :: forall w c a. Has w c => ((Entity c, c) -> System w a) -> System w [a] cimapM sys = do s :: Storage c <- getStore                 explCimapM s (\(e,c) -> sys (Entity e,c))  -- | Maps a function that might delete its components-cmap' :: forall world c. (Has world c, IsRuntime c)-      => (c -> Safe c) -> System world ()+{-# INLINE cmap' #-}+cmap' :: forall world c. Has world c => (c -> Safe c) -> System world () cmap' f = do s :: Storage c <- getStore              liftIO$ do sl <- explMembers s                         U.forM_ sl $ \e -> do@@ -136,7 +133,7 @@  -- | Maps a function over all entities with a @r@, and writes their @w@ {-# INLINE rmap #-}-rmap :: forall world r w. (Has world w, Has world r, IsRuntime w, IsRuntime r)+rmap :: forall world r w. (Has world w, Has world r)       => (r -> w) -> System world () rmap f = do sr :: Storage r <- getStore             sc :: Storage w <- getStore@@ -147,7 +144,7 @@  -- | Maps a function over all entities with a @r@, and writes or deletes their @w@ {-# INLINE rmap' #-}-rmap' :: forall world r w. (Has world w, Has world r, Store (Storage w), IsRuntime r)+rmap' :: forall world r w. (Has world w, Has world r, Store (Storage r), Store (Storage w))       => (r -> Safe w) -> System world () rmap' f = do sr :: Storage r <- getStore              sw :: Storage w <- getStore@@ -158,7 +155,7 @@  -- | For all entities with a @w@, this map reads their @r@ and writes their @w@ {-# INLINE wmap #-}-wmap :: forall world r w. (Has world w, Has world r, IsRuntime w, IsRuntime r)+wmap :: forall world r w. (Has world w, Has world r, Store (Storage r), Store (Storage w))      => (Safe r -> w) -> System world () wmap f = do sr :: Storage r <- getStore             sw :: Storage w <- getStore@@ -169,7 +166,7 @@  -- | For all entities with a @w@, this map reads their @r@ and writes or deletes their @w@ {-# INLINE wmap' #-}-wmap' :: forall world r w. (Has world w, Has world r, Store (Storage w), IsRuntime r)+wmap' :: forall world r w. (Has world w, Has world r, Store (Storage r), Store (Storage w))       => (Safe r -> Safe w) -> System world () wmap' f = do sr :: Storage r <- getStore              sw :: Storage w <- getStore@@ -180,19 +177,19 @@  -- | Reads a global value {-# INLINE readGlobal #-}-readGlobal :: forall w c. (Has w c, GlobalRW (Storage c) c) => System w c+readGlobal :: forall w c. (Has w c, GlobalStore (Storage c)) => System w c readGlobal = do s :: Storage c <- getStore-                liftIO$ explGlobalRead s+                liftIO$ explGet s 0  -- | Writes a global value {-# INLINE writeGlobal #-}-writeGlobal :: forall w c. (Has w c, GlobalRW (Storage c) c) => c -> System w ()+writeGlobal :: forall w c. (Has w c, GlobalStore (Storage c)) => c -> System w () writeGlobal c = do s :: Storage c <- getStore-                   liftIO$ explGlobalWrite s c+                   liftIO$ explSet s 0 c  -- | Modifies a global value {-# INLINE modifyGlobal #-}-modifyGlobal :: forall w c. (Has w c, GlobalRW (Storage c) c) => (c -> c) -> System w ()+modifyGlobal :: forall w c. (Has w c, GlobalStore (Storage c)) => (c -> c) -> System w () modifyGlobal f = do s :: Storage c <- getStore-                    liftIO$ explGlobalModify s f+                    liftIO$ explModify s 0 f 
src/Apecs/Types.hs view
@@ -22,24 +22,28 @@  -- | A component is defined by the type of its storage --   The storage in turn supplies runtime types for the component.---   For the component to be valid, its Storage must be in instance of Initializable.-class Initializable (Storage c) => Component c where+--   For the component to be valid, its Storage must be in instance of Store.+class (Stores (Storage c) ~ c, Store (Storage c)) => Component c where   type Storage c = s | s -> c  -- | A world `Has` a component if it can produce its Storage class Component c => Has w c where   getStore :: System w (Storage c) --- Storage types--- | Common for every storage. Represents a container that can be initialized.-class Initializable s where-  -- | The initialization argument required by this store-  type InitArgs s-  -- Initialize the store with its initialization arguments.-  initStoreWith :: InitArgs s -> IO s+-- | Represents a safe access to @c@. A safe access is either a read that might fail, or a write that might delete.+newtype Safe c = Safe {getSafe :: SafeRW (Storage c)} --- | A store that is indexed by entities.-class HasMembers s where+-- | Holds components indexed by entities+class Store s where+  -- | The type of components stored by this Store+  type Stores s+  -- | Return type for safe reads writes to the store+  type SafeRW s++  -- | Retrieves a component from the store+  explGet       :: s -> Int -> IO (SafeRW s)+  -- | Writes a component+  explSet       :: s -> Int -> Stores s -> IO ()   -- | Destroys the component for the given index.   explDestroy :: s -> Int -> IO ()   -- | Returns whether there is a component for the given index@@ -47,6 +51,16 @@   -- | Returns an unboxed vector of member indices   explMembers :: s -> IO (U.Vector Int) +  -- | Unsafe index to the store. Undefined if the component does not exist+  explGetUnsafe :: s -> Int -> IO (Stores s)+  -- | Either writes or deletes a component+  explSetMaybe  :: s -> Int -> SafeRW s -> IO ()++  -- | The initialization argument required by this store+  type InitArgs s+  -- Initialize the store with its initialization arguments.+  initStoreWith :: InitArgs s -> IO s+   -- | Removes all components.   --   Equivalent to calling @explDestroy@ on each member   {-# INLINE explReset #-}@@ -65,24 +79,6 @@   {-# INLINE explImapM #-}   explImapM s ma = liftIO (explMembers s) >>= mapM ma . U.toList --- | Represents a safe access to @c@. A safe access is either a read that might fail, or a write that might delete.-newtype Safe c = Safe {getSafe :: SafeRW (Storage c)}---- | Class of storages that associates components with entities.-class HasMembers s => Store s where-  -- | Return type for safe reads writes to the store-  type SafeRW s-  -- | The type of components stored by this Store-  type Stores s-  -- | Unsafe index to the store. Undefined if the component does not exist-  explGetUnsafe :: s -> Int -> IO (Stores s)-  -- | Retrieves a component from the store-  explGet       :: s -> Int -> IO (SafeRW s)-  -- | Writes a component-  explSet       :: s -> Int -> Stores s -> IO ()-  -- | Either writes or deletes a component-  explSetMaybe  :: s -> Int -> SafeRW s -> IO ()-   -- | Modifies an element in the store.   --   Equivalent to reading a value, and then writing the result of the function application.   {-# INLINE explModify #-}@@ -126,20 +122,8 @@       x :: Stores s <- liftIO$ explGetUnsafe s ety       sys (ety,x) --- | A constraint that indicates that the runtime representation of @c@ is @c@---   This will almost always be the case, but it _might_ not be so we need this constraint.-type IsRuntime c = (Store (Storage c), Stores (Storage c) ~ c)- -- | Class of storages for global values-class GlobalRW s c where-  {-# MINIMAL explGlobalRead, explGlobalWrite #-}-  explGlobalRead :: s -> IO c-  explGlobalWrite :: s -> c -> IO ()--  {-# INLINE explGlobalModify #-}-  explGlobalModify :: s -> (c -> c) -> IO ()-  explGlobalModify s f = do r <- explGlobalRead s-                            explGlobalWrite s (f r)+class (SafeRW s ~ Stores s, Store s) => GlobalStore s where  -- | Casts for entities and slices class Cast a b where@@ -155,15 +139,16 @@ -- (,) instance (Component a, Component b) => Component (a,b) where   type Storage (a, b) = (Storage a, Storage b)+ instance (Has w a, Has w b) => Has w (a,b) where   {-# INLINE getStore #-}   getStore = (,) <$> getStore <*> getStore -instance (Initializable a, Initializable b) => Initializable (a,b) where+instance (Store a, Store b) => Store (a,b) where   type InitArgs (a, b) = (InitArgs a, InitArgs b)+  type Stores (a, b) = (Stores a, Stores b)   initStoreWith (aa, ab) = (,) <$> initStoreWith aa <*> initStoreWith ab -instance (HasMembers a, HasMembers b) => HasMembers (a,b) where   explMembers (sa,sb) = explMembers sa >>= U.filterM (explExists sb)   explReset   (sa,sb) = explReset sa >> explReset sb   explDestroy (sa,sb) ety = explDestroy sa ety >> explDestroy sb ety@@ -173,9 +158,7 @@   {-# INLINE explDestroy #-}   {-# INLINE explExists #-} -instance (Store a, Store b) => Store (a, b) where   type SafeRW (a, b) = (SafeRW a, SafeRW b)-  type Stores (a, b) = (Stores a, Stores b)   explGetUnsafe  (sa,sb) ety = (,) <$> explGetUnsafe sa ety <*> explGetUnsafe sb ety   explGet        (sa,sb) ety = (,) <$> explGet sa ety <*> explGet sb ety   explSet        (sa,sb) ety (wa,wb) = explSet sa ety wa >> explSet sb ety wb@@ -185,11 +168,7 @@   {-# INLINE explSet #-}   {-# INLINE explSetMaybe #-} -instance (GlobalRW a ca, GlobalRW b cb) => GlobalRW (a,b) (ca,cb) where-  explGlobalRead  (sa,sb) = (,) <$> explGlobalRead sa <*> explGlobalRead sb-  explGlobalWrite (sa,sb) (wa,wb) = explGlobalWrite sa wa >> explGlobalWrite sb wb-  {-# INLINE explGlobalRead #-}-  {-# INLINE explGlobalWrite #-}+instance (GlobalStore a, GlobalStore b) => GlobalStore (a,b) where  -- (,,) instance (Component a, Component b, Component c) => Component (a,b,c) where@@ -198,11 +177,11 @@   {-# INLINE getStore #-}   getStore = (,,) <$> getStore <*> getStore <*> getStore -instance (Initializable a, Initializable b, Initializable c) => Initializable (a,b,c) where+instance (Store a, Store b, Store c) => Store (a,b,c) where   type InitArgs (a, b, c) = (InitArgs a, InitArgs b, InitArgs c)+  type Stores (a, b, c) = (Stores a, Stores b, Stores c)   initStoreWith (aa, ab, ac) = (,,) <$> initStoreWith aa <*> initStoreWith ab <*> initStoreWith ac -instance (HasMembers a, HasMembers b, HasMembers c) => HasMembers (a,b,c) where   explMembers (sa,sb,sc) = explMembers sa >>= U.filterM (explExists sb) >>= U.filterM (explExists sc)   explReset   (sa,sb,sc) = explReset sa >> explReset sb >> explReset sc   explDestroy (sa,sb,sc) ety = explDestroy sa ety >> explDestroy sb ety >> explDestroy sc ety@@ -212,9 +191,7 @@   {-# INLINE explDestroy #-}   {-# INLINE explExists #-} -instance (Store a, Store b, Store c) => Store (a, b, c) where   type SafeRW (a, b, c) = (SafeRW a, SafeRW b, SafeRW c)-  type Stores (a, b, c) = (Stores a, Stores b, Stores c)   explGetUnsafe  (sa,sb,sc) ety = (,,) <$> explGetUnsafe sa ety <*> explGetUnsafe sb ety <*> explGetUnsafe sc ety   explGet        (sa,sb,sc) ety = (,,) <$> explGet sa ety <*> explGet sb ety <*> explGet sc ety   explSet        (sa,sb,sc) ety (wa,wb,wc) = explSet sa ety wa >> explSet sb ety wb >> explSet sc ety wc@@ -224,8 +201,4 @@   {-# INLINE explSet #-}   {-# INLINE explSetMaybe #-} -instance (GlobalRW a ca, GlobalRW b cb, GlobalRW c cc) => GlobalRW (a,b,c) (ca,cb,cc) where-  explGlobalRead  (sa,sb,sc) = (,,) <$> explGlobalRead sa <*> explGlobalRead sb <*> explGlobalRead sc-  explGlobalWrite (sa,sb,sc) (wa,wb,wc) = explGlobalWrite sa wa >> explGlobalWrite sb wb >> explGlobalWrite sc wc-  {-# INLINE explGlobalRead #-}-  {-# INLINE explGlobalWrite #-}+instance (GlobalStore a, GlobalStore b, GlobalStore c) => GlobalStore (a,b,c) where
src/Apecs/Util.hs view
@@ -28,7 +28,7 @@ import Apecs.System  -- | Initializes a store with (), useful since most stores have () as their initialization argument-initStore :: (Initializable s, InitArgs s ~ ()) => IO s+initStore :: (Store s, InitArgs s ~ ()) => IO s initStore = initStoreWith ()  unEntity :: Entity a -> Int@@ -52,7 +52,7 @@  -- | Writes the given components to a new entity, and yields that entity {-# INLINE newEntity #-}-newEntity :: (IsRuntime c, Has w c, Has w EntityCounter)+newEntity :: (Store (Storage c), Has w c, Has w EntityCounter)           => c -> System w (Entity c) newEntity c = do ety <- nextEntity                  set ety c
test/Main.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE FlexibleContexts, FlexibleInstances #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE DataKinds #-}  {-# OPTIONS_GHC -w #-} @@ -22,13 +23,15 @@  type Vec = (Double, Double) +---+ newtype Position = Position Vec deriving (Arbitrary, Eq, Show) instance Component Position where   type Storage Position = S.Logger (S.FromPure Members) (S.Map Position)  newtype CachePos = CachePos Vec deriving (Arbitrary, Eq, Show) instance Component CachePos where-  type Storage CachePos = S.Map CachePos+  type Storage CachePos = S.Cache 1 (S.Map CachePos)   newtype Velocity = Velocity Vec deriving (Arbitrary, Eq, Show)@@ -51,7 +54,7 @@  newtype RandomEntity a = RandomEntity (Entity a) deriving (Eq, Show) instance Arbitrary (RandomEntity a) where-  arbitrary = RandomEntity . Entity <$> arbitrary+  arbitrary = RandomEntity . Entity . abs <$> arbitrary  newtype W1 c = W1 {w1c1 :: (Storage c)} instance Component c => Has (W1 c) c where getStore = System $ asks w1c1@@ -60,6 +63,17 @@ instance (Component a, Component b) => Has (W2 a b) a where getStore = System $ asks w2c1 instance (Component a, Component b) => Has (W2 a b) b where getStore = System $ asks w2c2 +counter :: [CachePos] -> CachePos -> Property+counter cs c = monadicIO $ run f >>= assert+  where+    f = do+      w :: W2 CachePos EntityCounter <- W2 <$> initStore <*> initCounter+      runWith w $ do+        forM_ cs newEntity+        e <- newEntity c+        Safe r <- get e+        return (r == Just c)+ getSetPos :: [(RandomEntity Position, Position)] -> RandomEntity Position -> Position -> Property getSetPos cs (RandomEntity e) p = monadicIO $ run f >>= assert   where@@ -105,3 +119,4 @@   quickCheck getSetPos   quickCheck getSetVCPos   quickCheck cmapVP+  quickCheck counter
tutorials/RTS.md view
@@ -239,23 +239,21 @@ For simplicity's sake, I chose to arrange them randomly in a square, with area proportional to the number of selected units. ```haskell handleEvent (SDL.MouseButtonEvent (SDL.MouseButtonEventData _ SDL.Pressed _ SDL.ButtonRight _ (P (V2 px py)))) = do-  sl :: Slice Selected <- slice All-  let r = (*3) . subtract 1 . sqrt . fromIntegral$ sliceSize sl+  sl :: Slice Selected <- owners+  let r = (*3) . subtract 1 . sqrt . fromIntegral$ S.size sl -  sliceForM_ sl $ \e -> do+  S.forM_ sl $ \e -> do     dx <- liftIO$ randomRIO (-r,r)     dy <- liftIO$ randomRIO (-r,r)     set e (Target (V2 (fromIntegral px+dx) (fromIntegral py+dy)))  handleEvent _ = return () ```-`slice` performs a query, and returns a `Slice`, which is just a list of entities.-The only query we can currently perform is `All`, which returns all owners of the specified component.-Other queries can be performed by using a more elaborate `Storage` type, but that's for a later tutorial.+`owners` returns a `Slice` of all members that have that particular component.+A `Slice` is a list of entities. The reason we need a slice instead of a map is that we need to know the amount of selected units.- There's a few more interesting functions here.-`sliceForM_` monadically iteraters over a `Slice`.+`S.forM_` monadically iteraters over a `Slice`. `set entity component` then explicitly writes a component for an entity, overwriting whatever might have been there.  #### Rendering