{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE NoImplicitPrelude #-}
-- |
-- Module : Data.PrimRef
-- Copyright : (c) 2013 Aleksey Khudyakov
-- License : BSD3
--
-- Maintainer : alexey.skladnoy@gmail.com
-- Stability : experimental
-- Portability : portable
--
-- Mutable references in monads which are instances of 'MonadPrim'.
module Data.PrimRef (
-- * PrimRefs
PrimRef
, newPrimRef
, readPrimRef
, writePrimRef
, modifyPrimRef
, modifyPrimRef'
) where
import Control.Monad.Primitive (PrimMonad(..))
import GHC.Base (MutVar#,newMutVar#,readMutVar#,writeMutVar#)
import Prelude (($),($!))
-- | Mutable variable which full analog of 'Data.IORef.IORef' or
-- 'Data.STRef.STRef' but could use either of the monads.
-- Unfortunately there's no way to convert @PrimRef@ to @STRef@ or
-- @IORef@.
data PrimRef m a = PrimRef (MutVar# (PrimState m) a)
-- | Create new mutable variable with initial value @a@.
newPrimRef :: PrimMonad m => a -> m (PrimRef m a)
newPrimRef a = primitive $ \s1# ->
case newMutVar# a s1# of
(# s2#, var# #) -> (# s2#, PrimRef var# #)
-- | Read value of @PrimRef@.
readPrimRef :: PrimMonad m => PrimRef m a -> m a
readPrimRef (PrimRef var#)
= primitive $ \s1# -> readMutVar# var# s1#
-- | Write value to @PrimRef@.
writePrimRef :: PrimMonad m => PrimRef m a -> a -> m ()
writePrimRef (PrimRef var#) a
= primitive $ \s1# ->
case writeMutVar# var# a s1# of
s2# -> (# s2#, () #)
-- | Modify content of @PrimRef@ using function.
modifyPrimRef :: PrimMonad m => PrimRef m a -> (a -> a) -> m ()
modifyPrimRef var f = do
x <- readPrimRef var
writePrimRef var $ f x
-- | Modify content of @PrimRef@ using function and evaluate result of
-- function application to WHNF before storing it in the variable.
modifyPrimRef' :: PrimMonad m => PrimRef m a -> (a -> a) -> m ()
modifyPrimRef' var f = do
x <- readPrimRef var
writePrimRef var $! f x