{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE CPP #-}
module Haxl.Core.StateStore
( StateKey(..)
, StateStore
, stateGet
, stateSet
, stateEmpty
) where
import Data.Map (Map)
import Data.Kind (Type)
import qualified Data.Map.Strict as Map
#if __GLASGOW_HASKELL__ < 804
import Data.Monoid
#endif
import Data.Typeable
import Unsafe.Coerce
class Typeable f => StateKey (f :: Type -> Type) where
data State f
getStateType :: Proxy f -> TypeRep
getStateType = Proxy f -> TypeRep
forall k (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep
newtype StateStore = StateStore (Map TypeRep StateStoreData)
#if __GLASGOW_HASKELL__ >= 804
instance Semigroup StateStore where
<> :: StateStore -> StateStore -> StateStore
(<>) = StateStore -> StateStore -> StateStore
forall a. Monoid a => a -> a -> a
mappend
#endif
instance Monoid StateStore where
mempty :: StateStore
mempty = StateStore
stateEmpty
mappend :: StateStore -> StateStore -> StateStore
mappend (StateStore Map TypeRep StateStoreData
m1) (StateStore Map TypeRep StateStoreData
m2) = Map TypeRep StateStoreData -> StateStore
StateStore (Map TypeRep StateStoreData -> StateStore)
-> Map TypeRep StateStoreData -> StateStore
forall a b. (a -> b) -> a -> b
$ Map TypeRep StateStoreData
m1 Map TypeRep StateStoreData
-> Map TypeRep StateStoreData -> Map TypeRep StateStoreData
forall a. Semigroup a => a -> a -> a
<> Map TypeRep StateStoreData
m2
data StateStoreData = forall f. StateKey f => StateStoreData (State f)
stateEmpty :: StateStore
stateEmpty :: StateStore
stateEmpty = Map TypeRep StateStoreData -> StateStore
StateStore Map TypeRep StateStoreData
forall k a. Map k a
Map.empty
stateSet :: forall f . StateKey f => State f -> StateStore -> StateStore
stateSet :: State f -> StateStore -> StateStore
stateSet State f
st (StateStore Map TypeRep StateStoreData
m) =
Map TypeRep StateStoreData -> StateStore
StateStore (TypeRep
-> StateStoreData
-> Map TypeRep StateStoreData
-> Map TypeRep StateStoreData
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert (Proxy f -> TypeRep
forall (f :: * -> *). StateKey f => Proxy f -> TypeRep
getStateType (Proxy f
forall k (t :: k). Proxy t
Proxy :: Proxy f)) (State f -> StateStoreData
forall (f :: * -> *). StateKey f => State f -> StateStoreData
StateStoreData State f
st) Map TypeRep StateStoreData
m)
stateGet :: forall r . StateKey r => StateStore -> Maybe (State r)
stateGet :: StateStore -> Maybe (State r)
stateGet (StateStore Map TypeRep StateStoreData
m) =
case TypeRep -> Map TypeRep StateStoreData -> Maybe StateStoreData
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup TypeRep
ty Map TypeRep StateStoreData
m of
Maybe StateStoreData
Nothing -> Maybe (State r)
forall a. Maybe a
Nothing
Just (StateStoreData (State f
st :: State f))
| Proxy f -> TypeRep
forall (f :: * -> *). StateKey f => Proxy f -> TypeRep
getStateType (Proxy f
forall k (t :: k). Proxy t
Proxy :: Proxy f) TypeRep -> TypeRep -> Bool
forall a. Eq a => a -> a -> Bool
== TypeRep
ty -> State r -> Maybe (State r)
forall a. a -> Maybe a
Just (State f -> State r
forall a b. a -> b
unsafeCoerce State f
st)
| Bool
otherwise -> Maybe (State r)
forall a. Maybe a
Nothing
where
ty :: TypeRep
ty = Proxy r -> TypeRep
forall (f :: * -> *). StateKey f => Proxy f -> TypeRep
getStateType (Proxy r
forall k (t :: k). Proxy t
Proxy :: Proxy r)