{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TupleSections #-} module Salak.Dynamic where import Control.Concurrent.MVar import Control.Monad.IO.Class (MonadIO, liftIO) import Control.Monad.State import qualified Data.IntMap.Strict as MI import Data.Text (Text) import Salak.Prop import Salak.Types data ReloadResult = ReloadResult { isError :: Bool , msg :: [String] } deriving (Eq, Show) -- | Reloadable SourcePack data ReloadableSourcePack = ReloadableSourcePack { sourcePack :: MVar SourcePack , reloadAll :: (SourcePack -> IO ([IO ()], [String])) -> IO ReloadResult } reloadableSourcePack :: MonadIO m => SourcePack -> m ReloadableSourcePack reloadableSourcePack sp = do msp <- liftIO $ newMVar sp return $ ReloadableSourcePack msp (reloadAll' msp) where reloadAll' v f = do sp'@(SourcePack _ _ _ it) <- readMVar v as <- filter (not . nullSource . snd) <$> mapM go (MI.toList it) if null as then return (ReloadResult True []) else do let (es, sp'') = extractErr' $ foldl g2 sp' as (ac, es') <- f sp'' if null es' then putMVar v sp'' >> sequence_ ac >> return (ReloadResult True es) else return (ReloadResult False es') go (i, Reload _ f) = (i,) <$> f i g2 (SourcePack ss i s it) (x,s') = SourcePack ss i (replace x s' s) it type ReloadableSourcePackT = StateT ReloadableSourcePack search' :: (MonadIO m, FromProp a) => Text -> ReloadableSourcePackT m (Either String (IO a)) search' k = do ReloadableSourcePack{..} <- get sp <- liftIO $ takeMVar sourcePack case search k sp of Left e -> return (Left e) Right r -> do v <- liftIO $ newMVar r put (ReloadableSourcePack sourcePack (reloadAll . go v)) return $ Right $ readMVar v where go x f sp = do (as,es) <- f sp case search k sp of Left e -> return (as, e:es) Right r -> return (putMVar x r:as, es) reload :: Monad m => ReloadableSourcePackT m (IO ReloadResult) reload = do ReloadableSourcePack{..} <- get return $ reloadAll $ \_ -> return ([], []) runReloadable :: MonadIO m => ReloadableSourcePackT m a -> SourcePack -> m a runReloadable r sp = reloadableSourcePack sp >>= evalStateT r