{-# LANGUAGE OverloadedStrings #-} module Yam.App.Context( YamContext(..) , HasYamContext(..) , requireExtension , getExtensionOrDefault , setExtension , lockExtenstion , emptyContext ) where import Yam.Import import Yam.Logger import qualified Control.Concurrent.Map as M import Data.Dynamic type YamExtension = M.Map Text Dynamic newtype YamContext = YamContext {extensions :: YamExtension} emptyContext :: IO YamContext emptyContext = YamContext <$> M.empty class MonadIO m => HasYamContext m where yamContext :: m YamContext extensionLockKey :: Text extensionLockKey = "Extension.Lock" extension :: HasYamContext m => m YamExtension extension = extensions <$> yamContext requireExtension :: (HasYamContext m, Typeable a) => Text -> m a requireExtension key = extension >>= liftIO . M.lookup key >>= get . (fromDynamic =<<) where get Nothing = error $ "Module " <> cs key <> " not loaded" get (Just r) = return r getExtensionOrDefault :: (HasYamContext m, Typeable a) => a -> Text -> m a getExtensionOrDefault a key = (fromMaybe a . (fromDynamic =<<)) <$> (extension >>= liftIO . M.lookup key) setExtension :: (MonadLogger m, HasYamContext m, Typeable a) => Text -> a -> m () setExtension key a = do checkLock void $ extension >>= liftIO . M.insert key (toDyn a) when (extensionLockKey /= key) (debugLn $ "Register extension <<" <> key <> ">>") checkLock :: HasYamContext m => m () checkLock = getExtensionOrDefault False extensionLockKey >>= go where go True = error "Extension has freezed, cannot modify now" go _ = return () lockExtenstion :: (MonadLogger m, HasYamContext m) => m () lockExtenstion = setExtension extensionLockKey True