acid-state-0.6.0: src/Data/Acid/Memory/Pure.hs
{-# LANGUAGE DeriveDataTypeable, BangPatterns #-}
-----------------------------------------------------------------------------
-- |
-- Module : Data.Acid.Memory.Pure
-- Copyright : PublicDomain
--
-- Maintainer : lemmih@gmail.com
-- Portability : non-portable (uses GHC extensions)
--
-- AcidState container without a transaction log. Mostly used for testing.
--
module Data.Acid.Memory.Pure
( IsAcidic(..)
, AcidState
, Event(..)
, EventResult
, EventState
, UpdateEvent
, QueryEvent
, Update
, Query
, openAcidState
, update
, update_
, query
, runQuery
) where
import Data.Acid.Core
import Data.Acid.Common
import Control.Monad.State ( runState )
{-| State container offering full ACID (Atomicity, Consistency, Isolation and Durability)
guarantees.
[@Atomicity@] State changes are all-or-nothing. This is what you'd expect of any state
variable in Haskell and AcidState doesn't change that.
[@Consistency@] No event or set of events will break your data invariants.
[@Isolation@] Transactions cannot interfere with each other even when issued in parallel.
[@Durability@] Successful transaction are guaranteed to survive system failure (both
hardware and software).
-}
data AcidState st
= AcidState { localMethods :: MethodMap st
, localState :: st
}
-- | Issue an Update event and wait for its result. Once this call returns, you are
-- guaranteed that the changes to the state are durable. Events may be issued in
-- parallel.
--
-- It's a run-time error to issue events that aren't supported by the AcidState.
update :: UpdateEvent event => AcidState (EventState event) -> event -> ( AcidState (EventState event)
, EventResult event)
update acidState event
= case runState hotMethod (localState acidState) of
!(result, !newState) -> ( acidState { localState = newState }
, result )
where hotMethod = lookupHotMethod (localMethods acidState) event
-- | Same as 'update' but ignoring the event result.
update_ :: UpdateEvent event => AcidState (EventState event) -> event -> AcidState (EventState event)
update_ acidState event
= fst (update acidState event)
-- | Issue a Query event and wait for its result.
query :: QueryEvent event => AcidState (EventState event) -> event -> EventResult event
query acidState event
= case runState hotMethod (localState acidState) of
!(result, !_st) -> result
where hotMethod = lookupHotMethod (localMethods acidState) event
-- | Create an AcidState given an initial value.
openAcidState :: IsAcidic st
=> st -- ^ Initial state value.
-> AcidState st
openAcidState initialState
= AcidState { localMethods = mkMethodMap (eventsToMethods acidEvents)
, localState = initialState }