packages feed

reactive-banana-0.3.0.0: src/Reactive/Banana/Vault.hs

{-----------------------------------------------------------------------------
    Reactive Banana

    Helper Module: A typed, inhomogeneous storage.
    Uses  IORefs  to read and write.
------------------------------------------------------------------------------}
module Reactive.Banana.Vault (
    Vault, Key,
    empty, newKey, lookup, insert, delete,
    ) where

import Prelude hiding (lookup)
import Data.Map (Map)
import qualified Data.Map as Map
import Data.IORef
import Data.Unique

-- | An inhomogeneous, type safe storage.
type Vault = Map Unique Item
-- Values are stored in closures that write to a temporary IORef
-- This way, we can "circumvent" the type system.
type Item  = IO ()

-- Key for the vault
data Key a   = Key Unique (Item' a)
-- Keeps track of the temporary IORef for reading and writing
type Item' a = IORef (Maybe a)

-- | The empty vault.
empty :: Vault
empty = Map.empty

-- | Create a new key for use with a vault.
newKey   :: IO (Key a)
newKey = do
    k   <- newUnique
    ref <- newIORef Nothing
    return $ Key k ref

-- | Lookup the value of a key in the vault.
lookup :: Key a -> Vault -> IO (Maybe a)
lookup (Key k ref) vault = case Map.lookup k vault of
    Nothing   -> return Nothing
    Just item -> do
        item                    -- write into IORef
        mx <- readIORef ref     -- read the value
        writeIORef ref Nothing  -- clear IORef
        return mx

-- | Insert a value for a given key. Overwrites any previous value.
insert :: Key a -> a -> Vault -> IO Vault
insert (Key k ref) x vault = return $
    Map.insert k (writeIORef ref $ Just x) vault

-- | Delete a key from the vault.
delete :: Key a -> Vault -> IO Vault
delete (Key k ref) vault = return $ Map.delete k vault