ghc-mod/src/Misc.hs

48 lines
1.4 KiB
Haskell
Raw Normal View History

{-# LANGUAGE DeriveDataTypeable, CPP #-}
2014-09-22 12:32:57 +00:00
module Misc (
SymDbReq
2014-09-22 12:32:57 +00:00
, newSymDbReq
, getDb
, checkDb
) where
import Control.Concurrent.Async (Async, async, wait)
import CoreMonad (liftIO)
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
2015-08-03 01:09:56 +00:00
import Prelude
2014-09-22 12:32:57 +00:00
import Language.Haskell.GhcMod
import Language.Haskell.GhcMod.Internal hiding (MonadIO,liftIO)
2014-09-22 12:32:57 +00:00
----------------------------------------------------------------
type SymDbReqAction = (Either GhcModError SymbolDb, GhcModLog)
data SymDbReq = SymDbReq (IORef (Async SymDbReqAction)) (IO SymDbReqAction)
newSymDbReq :: Options -> FilePath -> IO SymDbReq
newSymDbReq opt dir = do
let act = runGhcModT opt $ loadSymbolDb dir
2014-09-22 12:32:57 +00:00
req <- async act
ref <- newIORef req
return $ SymDbReq ref act
getDb :: IOish m => SymDbReq -> GhcModT m SymbolDb
getDb (SymDbReq ref _) = do
req <- liftIO $ readIORef ref
-- 'wait' really waits for the asynchronous action at the fist time.
-- Then it reads a cached value from the second time.
hoistGhcModT =<< liftIO (wait req)
checkDb :: IOish m => SymDbReq -> SymbolDb -> GhcModT m SymbolDb
checkDb (SymDbReq ref act) db = do
outdated <- isOutdated db
2014-09-22 12:32:57 +00:00
if outdated then do
-- async and wait here is unnecessary because this is essentially
-- synchronous. But Async can be used a cache.
req <- liftIO $ async act
liftIO $ writeIORef ref req
hoistGhcModT =<< liftIO (wait req)
else
return db