packages feed

halive-0.1.5: src/Halive/Utils.hs

{-# LANGUAGE ScopedTypeVariables #-}
module Halive.Utils where
import Foreign.Store
import Data.Word

import Control.Monad.State
import System.Environment

import Data.Map (Map)
import qualified Data.Map as Map
import Data.Typeable
import Data.Dynamic

type StoreMap = Map String Dynamic

isHaliveActive :: MonadIO m => m Bool
isHaliveActive = liftIO $ do
    r <- lookupEnv "Halive Active"
    case r of
        Just "Yes" -> return True
        _          -> return False

-- | Takes a unique name representing your value,
-- along with an IO action to create the first instance
-- of your value to be used on subsequent recompilations.
reacquire :: (Typeable a, MonadIO m) => String -> m a -> m a
reacquire name create = do
    -- See if the value exists already
    storeMap <- getStoreMap
    case fromDynamic =<< Map.lookup name storeMap of
        -- If so, return the value inside
        Just value -> return value
        -- Otherwise, create the value, store it, and return it.
        Nothing -> do
            value <- create
            persist name value
            return value

persistState :: (MonadState s m, MonadIO m, Typeable s) => String -> m ()
persistState name = persist name =<< get

storeMapID :: Word32
storeMapID = 0

getStoreMap :: MonadIO m => m StoreMap
getStoreMap = do
    -- See if we've created the storeMap already
    maybeStore <- liftIO (lookupStore storeMapID)
    case maybeStore of
        -- If so, return the existing storeMap inside
        Just store -> liftIO (readStore store)
        -- Otherwise, create the value, store it, and return it.
        Nothing -> do
            let storeMap = mempty
            writeStoreMap storeMap
            return storeMap

modifyStoreMap :: MonadIO m => (StoreMap -> StoreMap) -> m ()
modifyStoreMap f = do
    storeMap <- getStoreMap
    writeStoreMap (f storeMap)

writeStoreMap :: MonadIO m => StoreMap -> m ()
writeStoreMap = liftIO . writeStore (Store storeMapID)

persist :: (Typeable a, MonadIO m) => String -> a -> m ()
persist name value =
    modifyStoreMap (Map.insert name (toDyn value))