packages feed

apecs-roaring-1.0: src/Apecs/Stores/Flags.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

{-| A store for flag-like components backed by an off-heap 'Index'.

A flag component has exactly one value, so the store keeps only membership.
Derive 'Generic' for the component to let the store produce that value:

@
data Dead = Dead deriving (Generic)
instance Component Dead where type Storage Dead = Flags Dead
@
-}
module Apecs.Stores.Flags
  ( Flags (..)
  , Unit (..)
  , clear
  ) where

import Apecs.Core (Component (..), Elem, ExplDestroy (..), ExplGet (..), ExplInit (..), ExplMembers (..), ExplSet (..), Has (..), SystemT)
import Apecs.Stores.Index (HasIndex (..), Index)
import Apecs.Stores.Index qualified as Index
import Control.Monad.IO.Class (MonadIO (..))
import GHC.Generics (Generic (..), M1 (..), U1 (..))

newtype Flags c = Flags Index

type instance Elem (Flags c) = c

class Unit f where
  unit :: f p

instance Unit U1 where
  unit = U1

instance (Unit f) => Unit (M1 i meta f) where
  unit = M1 unit

instance (MonadIO m) => ExplInit m (Flags c) where
  explInit = liftIO $ Flags <$> Index.new

instance (MonadIO m, Generic c, Unit (Rep c)) => ExplGet m (Flags c) where
  explGet _ _ = pure $ to unit
  {-# INLINE explGet #-}
  explExists (Flags index) = liftIO . Index.member index
  {-# INLINE explExists #-}

instance (MonadIO m) => ExplSet m (Flags c) where
  explSet (Flags index) ety _ = liftIO $ Index.insert index ety
  {-# INLINE explSet #-}

instance (MonadIO m) => ExplDestroy m (Flags c) where
  explDestroy (Flags index) = liftIO . Index.delete index
  {-# INLINE explDestroy #-}

instance (MonadIO m) => ExplMembers m (Flags c) where
  explMembers (Flags index) = liftIO $ Index.toVector index
  {-# INLINE explMembers #-}

instance HasIndex (Flags c) where
  getIndex (Flags index) = index

clear :: forall c w m. (Has w m c, Storage c ~ Flags c, MonadIO m) => SystemT w m ()
clear = do
  Flags index <- getStore @w @m @c
  liftIO $ Index.clear index