io-storage-0.3/0000755000175000017500000000000011236420037012123 5ustar willwillio-storage-0.3/System/0000755000175000017500000000000011236420037013407 5ustar willwillio-storage-0.3/System/IO/0000755000175000017500000000000011236420037013716 5ustar willwillio-storage-0.3/System/IO/Storage.hs0000644000175000017500000000746011236420037015665 0ustar willwill{- | Conceptually, this library provides a way to arbitrarily extend the global state represented by the IO monad. Viewed another way, this library provides a basic facility for setting and retrieving values from global variables. The interface takes the form of a very basic key-value store, with multiple different stores made available through the 'withStore' function. Stores are referenced by arbitrary strings, and keys within those stores are treated likewise. The 'putValue', 'getValue', and 'delValue' functions allow you to store, retrieve, and delete data from the store. Internally, data is stored within an IORef which is created using the 'unsafePerformIO hack', but this is hidden within the library so that it can easily be modified if and when a more 'proper' solution is implemented. -} module System.IO.Storage ( withStore , putValue , getValue , getDefaultValue , delValue ) where import Data.IORef ( IORef, newIORef, modifyIORef, readIORef ) import Data.List as L ( lookup, deleteFirstsBy ) import Data.Map as M ( Map, empty, lookup, insert, delete ) import Data.Dynamic ( Dynamic, toDyn, fromDyn, fromDynamic ) import Data.Typeable ( Typeable ) import Data.Function ( on ) import Control.Exception ( bracket ) import System.IO.Unsafe ( unsafePerformIO ) type ValueStore = M.Map String Dynamic -- | This is the magic bit that makes the data-stores global to the -- entire program. Sure, it cheats a little, but who doesn't? globalPeg :: IORef [(String, IORef ValueStore)] {-# NOINLINE globalPeg #-} globalPeg = unsafePerformIO (newIORef []) -- | Create a named key-value store, and then execute the given -- IO action within its extent. Calls to 'withStore' can be -- nested, and calling it again with the name of a data-store -- that has already been initialized will cause the original -- to be shadowed for the duration of the call to 'withStore'. withStore :: String -> IO a -> IO a withStore storeName action = do store <- newIORef M.empty let emptyStore = (storeName, store) let create = modifyIORef globalPeg (emptyStore:) let delete = modifyIORef globalPeg deleteStore bracket create (const delete) (const action) where deleteStore xs = deleteFirstsBy ((==) `on` fst) xs dummyStore dummyStore = [(storeName, undefined)] getPrimitive :: String -> String -> IO (Maybe Dynamic) getPrimitive storeName key = do storeList <- readIORef globalPeg case storeName `L.lookup` storeList of Nothing -> return Nothing Just st -> do map <- readIORef st return $ key `M.lookup` map -- | Get a value from the given data-store, if it exists. If it -- doesn't exist, obviously, 'Nothing' will be returned. getValue :: Typeable a => String -> String -> IO (Maybe a) getValue storeName key = do value <- getPrimitive storeName key case value of Nothing -> return $ Nothing Just dy -> return $ fromDynamic dy -- | Get a value from the given store, with a default if it -- doesn't exist. getDefaultValue :: Typeable a => String -> String -> a -> IO a getDefaultValue storeName key val = do value <- getPrimitive storeName key case value of Nothing -> return $ val Just dy -> return $ fromDyn dy val -- | Put a value into the given data-store. putValue :: Typeable a => String -> String -> a -> IO () putValue storeName key value = do storeList <- readIORef globalPeg case storeName `L.lookup` storeList of Nothing -> return () Just st -> modifyIORef st . M.insert key . toDyn $ value -- | Delete a value from the given data-store. delValue :: String -> String -> IO () delValue storeName key = do storeList <- readIORef globalPeg case storeName `L.lookup` storeList of Nothing -> return () Just st -> modifyIORef st . M.delete $ key io-storage-0.3/io-storage.cabal0000644000175000017500000000203511236420037015160 0ustar willwillname: io-storage version: 0.3 category: Database, Data, System synopsis: A key-value store in the IO monad. description: This library allows an application to extend the 'global state' hidden inside the IO monad with semi-arbitrary data. Data is required to be 'Typeable'. The library provides an essentially unbounded number of key-value stores indexed by strings, with each key within the stores also being a string. homepage: http://github.com/willdonnelly/io-storage bug-reports: http://github.com/willdonnelly/io-storage/issues stability: alpha author: Will Donnelly maintainer: Will Donnelly copyright: (c) 2009 Will Donnelly license: BSD3 license-file: LICENSE build-type: Simple cabal-version: >= 1.6 library exposed-modules: System.IO.Storage build-depends: base >= 4 && < 5, containers source-repository head type: git location: git://github.com/willdonnelly/io-storage.git io-storage-0.3/Setup.hs0000644000175000017500000000011011236420037013547 0ustar willwill#!/usr/bin/env runhaskell import Distribution.Simple main = defaultMain io-storage-0.3/LICENSE0000644000175000017500000000275311236420037013137 0ustar willwillCopyright (c) 2009, Will Donnelly All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.