-- | Simple in-memory key-value var -- -- Intended for qualified import. -- -- > import KVStore.Util.Store (Store) -- > import KVStore.Util.Store qualified as Store module KVStore.Util.Store ( Store -- opaque -- * API , new , get , putIfAbsent , replace , remove ) where import Control.Concurrent import Data.Hashable (Hashable) import Data.HashMap.Strict (HashMap) import Data.HashMap.Strict qualified as HashMap {------------------------------------------------------------------------------- Definition -------------------------------------------------------------------------------} newtype Store a b = Wrap { unwrap :: MVar (HashMap a b) } {------------------------------------------------------------------------------- API -------------------------------------------------------------------------------} new :: IO (Store a b) new = Wrap <$> newMVar HashMap.empty -- | Get value associated with the key, if it exists get :: Hashable a => Store a b -> a -> IO (Maybe b) get store key = withStore store $ HashMap.lookup key -- | Remove an key from the map remove :: Hashable a => Store a b -> a -> IO () remove store key = modifyStore_ store $ HashMap.delete key -- | Put a new key/value pair into the var -- -- Returns 'True' on success, or 'False' if they key was already present. putIfAbsent :: Hashable a => Store a b -> a -> b -> IO Bool putIfAbsent store key value = modifyStore store $ \hm -> case HashMap.lookup key hm of Nothing -> (HashMap.insert key value hm, True) Just _ -> (hm, False) -- | Replace the value associated with the key, if the key already exists -- -- Returns 'True' if the value was successfully replaced, or 'False' if the key -- was not present. replace :: Hashable a => Store a b -> a -> b -> IO Bool replace store key newValue = modifyStore store $ \hm -> case HashMap.lookup key hm of Nothing -> (hm, False) Just _ -> (HashMap.insert key newValue hm, True) {------------------------------------------------------------------------------- Internal: wrap pure operations -------------------------------------------------------------------------------} withStore :: Store a b -> (HashMap a b -> r) -> IO r withStore store f = withMVar (unwrap store) $ return . f modifyStore :: Store a b -> (HashMap a b -> (HashMap a b, r)) -> IO r modifyStore store f = modifyMVar (unwrap store) $ return . f modifyStore_ :: Store a b -> (HashMap a b -> HashMap a b) -> IO () modifyStore_ store f = modifyMVar_ (unwrap store) $ return . f