module Dingo.Internal.SessionTypes
( SessionState
, SessionT(..)
, addWidget
, getWidgetStateM
, lookupCallback
, lookupResource
, mkSessionState
, newCallbackId
, newWidgetId
, registerCallback
, registerResourceBundle
, registerWidgetType
, runSessionT
, setWidgetStateM
, callbackCounter
, widgetCounter
, widgetSet
) where
import Control.Monad (liftM, unless)
import Control.Monad.IO.Class (MonadIO(..))
import Control.Monad.Trans.Class (MonadTrans(..))
import Control.Monad.Trans.State (StateT, runStateT)
import Data.ByteString (ByteString)
import Data.Label (mkLabels, (:->))
import qualified Data.Label as L
import Data.Label.PureM (gets, puts, modify)
import Data.Map (Map)
import qualified Data.Map as M
import Data.Monoid (mappend)
import Data.Set (Set)
import qualified Data.Set as S
import Data.Text (Text)
import Dingo.Internal.Base (CallbackId, WidgetId, succCallbackId, succWidgetId, zeroCallbackId, zeroWidgetId)
import Dingo.Internal.ResourceBundle.Internal (ResourceBundle, ResourceBundleSet, elemResourceBundleSet, findResourceInBundleSet, resourceBundleSetFromList)
import Dingo.Internal.TypeableShim (TypeId)
import Dingo.Internal.WidgetSet (WidgetSet, emptyWidgetSet, setWidgetState, getWidgetState)
import Dingo.Internal.WidgetTypes (Widget)
data SessionState c =
SessionState { _callbackCounter :: CallbackId
, _widgetCounter :: WidgetId
, _sessionCallbacks :: Map CallbackId c
, _widgetSet :: WidgetSet
, _widgetTypeSet :: Set TypeId
, _resourceBundleSet :: ResourceBundleSet
}
newtype SessionT c m a = SessionT { unSession :: Session c m a }
deriving (Functor, Monad)
type Session c = StateT (SessionState c)
$(mkLabels [''SessionState])
mkSessionState :: c -> [ResourceBundle] -> SessionState c
mkSessionState c0 bootResourceBundles =
SessionState cid1 wid1 bootstrapCallbacks emptyWidgetSet S.empty $ resourceBundleSetFromList bootResourceBundles
where
wid0 = zeroWidgetId
wid1 = succWidgetId wid0
cid0 = zeroCallbackId
cid1 = succCallbackId cid0
bootstrapCallbacks = M.singleton cid0 c0
instance MonadTrans (SessionT c) where
lift m = SessionT $ lift m
instance (MonadIO m) => MonadIO (SessionT w m) where
liftIO = lift . liftIO
runSessionT :: Monad m => SessionState c -> SessionT c m a -> m (a, SessionState c)
runSessionT s0 (SessionT s) = runStateT s s0
freshIdentifier :: Monad m => (a -> a) -> (SessionState c :-> a) -> SessionT c m a
freshIdentifier succ_ label = SessionT $ do
i <- gets label
puts label $ succ_ i
return i
newCallbackId :: Monad m => SessionT c m CallbackId
newCallbackId = freshIdentifier succCallbackId callbackCounter
newWidgetId :: Monad m => SessionT c m WidgetId
newWidgetId = freshIdentifier succWidgetId widgetCounter
registerCallback :: Monad m => c -> SessionT c m CallbackId
registerCallback callback = SessionT $ do
callbackId <- unSession newCallbackId
modify sessionCallbacks (M.insertWith' const callbackId callback)
return callbackId
registerWidgetType :: (Monad m, Functor m) => TypeId -> SessionT c m Bool
registerWidgetType widgetTypeId = SessionT $ do
e <- fmap (S.member widgetTypeId) $ gets widgetTypeSet
unless e $ modify widgetTypeSet $ S.insert widgetTypeId
return $ not e
registerResourceBundle :: (Monad m, Functor m) => ResourceBundle -> SessionT c m Bool
registerResourceBundle resourceBundle = SessionT $ do
e <- fmap (elemResourceBundleSet resourceBundle) $ gets resourceBundleSet
unless e $ modify resourceBundleSet (\x -> mappend x (resourceBundleSetFromList [resourceBundle]))
return $ not e
lookupResource :: Text -> [Text] -> SessionState c -> Maybe ByteString
lookupResource bundleId path sessionState =
findResourceInBundleSet bundleId path r
where
r = L.get resourceBundleSet sessionState
lookupCallback :: (Monad m) => CallbackId -> SessionT c m (Maybe c)
lookupCallback callbackId = SessionT $ liftM (M.lookup callbackId) $ gets sessionCallbacks
addWidget :: Widget w s => (WidgetId -> SessionT b IO ((w, s), a)) -> SessionT b IO ((w, s), a)
addWidget f = do
widgetId <- newWidgetId
((c,s),a) <- f widgetId
SessionT $ modify widgetSet (setWidgetState c s)
return ((c,s),a)
getWidgetStateM :: (Monad m, Widget w s) => w -> SessionT b m (Maybe s)
getWidgetStateM c = SessionT $ do
cs <- gets widgetSet
return $ getWidgetState cs c
setWidgetStateM :: (Monad m, Widget w s) => w -> s -> SessionT b m ()
setWidgetStateM c s = SessionT $ modify widgetSet (setWidgetState c s)