{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UnboxedTuples #-}
-- |
-- Module      : Data.Prim.Ref
-- Copyright   : (c) Alexey Kuleshevich 2020
-- License     : BSD3
-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
-- Stability   : experimental
-- Portability : non-portable
--
module Data.Prim.Ref
  ( Ref(..)
  , IORef
  , STRef
  -- * Create
  , newRef
  , newDeepRef
  , isSameRef
  -- * Read/write
  , readRef
  , swapRef
  , swapDeepRef
  , writeRef
  , writeDeepRef
  -- * Modify
  -- ** Pure
  , modifyRef
  , modifyDeepRef
  , modifyRef_
  , modifyFetchNewRef
  , modifyFetchOldRef
  -- ** Monadic
  , modifyRefM
  , modifyDeepRefM
  , modifyRefM_
  , modifyFetchNewRefM
  , modifyFetchOldRefM
  -- * Atomic
  , atomicReadRef
  , atomicSwapRef
  , atomicWriteRef
  , atomicModifyRef
  , atomicModifyRef_
  , atomicModifyFetchRef
  , atomicModifyFetchNewRef
  , atomicModifyFetchOldRef
  , atomicModifyFetchBothRef
  -- ** Original
  , casRef
  , atomicModifyRef2
  , atomicModifyRef2_
  , atomicModifyFetchNewRef2
  , atomicModifyFetchOldRef2
  , atomicModifyFetchBothRef2
  , atomicModifyFetchRef2
  -- * Lazy
  -- It is recommended to refrain from usage of lazy functions because they are a memory
  -- leak waiting to happen
  , newLazyRef
  , writeLazyRef
  , swapLazyRef
  , modifyLazyRef
  , modifyLazyRefM
  , atomicWriteLazyRef
  , atomicModifyLazyRef
  , atomicModifyFetchNewLazyRef
  , atomicModifyFetchOldLazyRef
  , atomicModifyFetchBothLazyRef
  , atomicModifyFetchLazyRef
  -- * Conversion
  -- ** STRef
  , toSTRef
  , fromSTRef
  -- ** IORef
  , toIORef
  , fromIORef
  -- * Weak Pointer
  , mkWeakRef
  ) where

import Control.DeepSeq
import Control.Prim.Monad
import Foreign.Prim
import Foreign.Prim.WeakPtr
import qualified GHC.IORef as IO
import qualified GHC.STRef as ST

-- | Mutable variable that can hold any value. This is just like `Data.STRef.STRef`, but
-- with type arguments flipped and is generalized to work in `MonadPrim`. It only stores a
-- reference to the value which means it works on boxed values. If the type can be unboxed
-- with `Data.Prim.Class.Prim` class, consider using
-- [@PVar@](https://hackage.haskell.org/package/pvar) package instead.
--
-- @since 0.3.0
data Ref a s = Ref (MutVar# s a)

-- | Uses `isSameRef`
instance Eq (Ref a s) where
  == :: Ref a s -> Ref a s -> Bool
(==) = Ref a s -> Ref a s -> Bool
forall a s. Ref a s -> Ref a s -> Bool
isSameRef

-- | Compatibility synonym
type IORef a = Ref a RW

-- | Compatibility synonym
type STRef s a = Ref a s

-- | Check whether supplied `Ref`s refer to the exact same one or not.
--
-- @since 0.3.0
isSameRef :: Ref a s -> Ref a s -> Bool
isSameRef :: Ref a s -> Ref a s -> Bool
isSameRef (Ref MutVar# s a
ref1#) (Ref MutVar# s a
ref2#) = Int# -> Bool
isTrue# (MutVar# s a -> MutVar# s a -> Int#
forall d a. MutVar# d a -> MutVar# d a -> Int#
sameMutVar# MutVar# s a
ref1# MutVar# s a
ref2#)
{-# INLINE isSameRef #-}


-- | Create a new mutable variable. Initial value will be forced to WHNF (weak head normal form).
--
-- ==== __Examples__
--
-- >>> import Debug.Trace
-- >>> import Data.Prim.Ref
-- >>> ref <- newRef (trace "Initial value is evaluated" (217 :: Int))
-- Initial value is evaluated
-- >>> modifyFetchOldRef ref succ
-- 217
-- >>> readRef ref
-- 218
--
-- @since 0.3.0
newRef :: MonadPrim s m => a -> m (Ref a s)
newRef :: a -> m (Ref a s)
newRef a
a = a
a a -> m (Ref a s) -> m (Ref a s)
`seq` a -> m (Ref a s)
forall s (m :: * -> *) a. MonadPrim s m => a -> m (Ref a s)
newLazyRef a
a
{-# INLINE newRef #-}


-- | Create a new mutable variable. Same as `newRef`, but ensures that value is evaluated
-- to normal form.
--
-- ==== __Examples__
--
-- >>> import Debug.Trace
-- >>> import Data.Prim.Ref
-- >>> ref <- newDeepRef (Just (trace "Initial value is evaluated" (217 :: Int)))
-- Initial value is evaluated
-- >>> readRef ref
-- Just 217
--
-- @since 0.3.0
newDeepRef :: (NFData a, MonadPrim s m) => a -> m (Ref a s)
newDeepRef :: a -> m (Ref a s)
newDeepRef a
a = a
a a -> m (Ref a s) -> m (Ref a s)
forall a b. NFData a => a -> b -> b
`deepseq` a -> m (Ref a s)
forall s (m :: * -> *) a. MonadPrim s m => a -> m (Ref a s)
newLazyRef a
a
{-# INLINE newDeepRef #-}

-- | Create a new mutable variable. Initial value stays unevaluated.
--
-- ==== __Examples__
--
-- In below example you will see that initial value is never evaluated.
--
-- >>> import Debug.Trace
-- >>> import Data.Prim.Ref
-- >>> ref <- newLazyRef (trace "Initial value is evaluated" (undefined :: Int))
-- >>> writeRef ref 1024
-- >>> modifyFetchNewRef ref succ
-- 1025
--
-- @since 0.3.0
newLazyRef :: MonadPrim s m => a -> m (Ref a s)
newLazyRef :: a -> m (Ref a s)
newLazyRef a
a =
  (State# s -> (# State# s, Ref a s #)) -> m (Ref a s)
forall s (m :: * -> *) a.
MonadPrim s m =>
(State# s -> (# State# s, a #)) -> m a
prim ((State# s -> (# State# s, Ref a s #)) -> m (Ref a s))
-> (State# s -> (# State# s, Ref a s #)) -> m (Ref a s)
forall a b. (a -> b) -> a -> b
$ \State# s
s ->
    case a -> State# s -> (# State# s, MutVar# s a #)
forall a d. a -> State# d -> (# State# d, MutVar# d a #)
newMutVar# a
a State# s
s of
      (# State# s
s', MutVar# s a
ref# #) -> (# State# s
s', MutVar# s a -> Ref a s
forall a s. MutVar# s a -> Ref a s
Ref MutVar# s a
ref# #)
{-# INLINE newLazyRef #-}

----------------
-- Read/Write --
----------------

-- | Read contents of the mutable variable
--
-- ==== __Examples__
--
-- >>> import Data.Prim.Ref
-- >>> ref <- newRef "Hello World!"
-- >>> readRef ref
-- "Hello World!"
--
-- @since 0.3.0
readRef :: MonadPrim s m => Ref a s -> m a
readRef :: Ref a s -> m a
readRef (Ref MutVar# s a
ref#) = (State# s -> (# State# s, a #)) -> m a
forall s (m :: * -> *) a.
MonadPrim s m =>
(State# s -> (# State# s, a #)) -> m a
prim (MutVar# s a -> State# s -> (# State# s, a #)
forall d a. MutVar# d a -> State# d -> (# State# d, a #)
readMutVar# MutVar# s a
ref#)
{-# INLINE readRef #-}


-- | Swap a value of a mutable variable with a new one, while retrieving the old one. New
-- value is evaluated prior to it being written to the variable.
--
-- ==== __Examples__
--
-- >>> ref <- newRef (Left "Initial" :: Either String String)
-- >>> swapRef ref (Right "Last")
-- Left "Initial"
-- >>> readRef ref
-- Right "Last"
--
-- @since 0.3.0
swapRef :: MonadPrim s m => Ref a s -> a -> m a
swapRef :: Ref a s -> a -> m a
swapRef Ref a s
ref a
a = Ref a s -> m a
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> m a
readRef Ref a s
ref m a -> m () -> m a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Ref a s -> a -> m ()
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> a -> m ()
writeRef Ref a s
ref a
a
{-# INLINE swapRef #-}


-- | Swap a value of a mutable variable with a new one lazily, while retrieving the old
-- one. New value is __not__ evaluated prior to it being written to the variable.
--
-- ==== __Examples__
--
-- >>> ref <- newRef "Initial"
-- >>> swapLazyRef ref undefined
-- "Initial"
-- >>> _ <- swapLazyRef ref "Different"
-- >>> readRef ref
-- "Different"
--
-- @since 0.3.0
swapLazyRef :: MonadPrim s m => Ref a s -> a -> m a
swapLazyRef :: Ref a s -> a -> m a
swapLazyRef Ref a s
ref a
a = Ref a s -> m a
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> m a
readRef Ref a s
ref m a -> m () -> m a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Ref a s -> a -> m ()
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> a -> m ()
writeLazyRef Ref a s
ref a
a
{-# INLINE swapLazyRef #-}


-- | Swap a value of a mutable variable with a new one, while retrieving the old one. New
-- value is evaluated to __normal__ form prior to it being written to the variable.
--
-- ==== __Examples__
--
-- >>> ref <- newRef (Just "Initial")
-- >>> swapDeepRef ref (Just (errorWithoutStackTrace "foo"))
-- *** Exception: foo
-- >>> readRef ref
-- Just "Initial"
--
-- @since 0.3.0
swapDeepRef :: (NFData a, MonadPrim s m) => Ref a s -> a -> m a
swapDeepRef :: Ref a s -> a -> m a
swapDeepRef Ref a s
ref a
a = Ref a s -> m a
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> m a
readRef Ref a s
ref m a -> m () -> m a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Ref a s -> a -> m ()
forall a s (m :: * -> *).
(NFData a, MonadPrim s m) =>
Ref a s -> a -> m ()
writeDeepRef Ref a s
ref a
a
{-# INLINE swapDeepRef #-}


-- | Write a value into a mutable variable strictly. If evaluating a value results in
-- exception, original value in the mutable variable will not be affected. Another great
-- benfit of this over `writeLazyRef` is that it helps avoiding memory leaks.
--
-- ==== __Examples__
--
-- >>> ref <- newRef "Original value"
-- >>> import Control.Prim.Exception
-- >>> _ <- try $ writeRef ref undefined :: IO (Either SomeException ())
-- >>> readRef ref
-- "Original value"
-- >>> writeRef ref "New total value"
-- >>> readRef ref
-- "New total value"
--
-- @since 0.3.0
writeRef :: MonadPrim s m => Ref a s -> a -> m ()
writeRef :: Ref a s -> a -> m ()
writeRef Ref a s
ref !a
a = Ref a s -> a -> m ()
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> a -> m ()
writeLazyRef Ref a s
ref a
a
{-# INLINE writeRef #-}


-- | Same as `writeRef`, but will evaluate the argument to Normal Form prior to writing it
-- to the `Ref`
--
-- @since 0.3.0
writeDeepRef :: (NFData a, MonadPrim s m) => Ref a s -> a -> m ()
writeDeepRef :: Ref a s -> a -> m ()
writeDeepRef Ref a s
ref a
a = a
a a -> m () -> m ()
forall a b. NFData a => a -> b -> b
`deepseq` Ref a s -> a -> m ()
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> a -> m ()
writeLazyRef Ref a s
ref a
a
{-# INLINE writeDeepRef #-}

-- | Write a value into a mutable variable lazily.
--
-- ==== __Examples__
--
-- >>> ref <- newRef "Original value"
-- >>> import Debug.Trace
-- >>> writeLazyRef ref (trace "'New string' is evaluated" "New string")
-- >>> x <- readRef ref
-- >>> writeRef ref (trace "'Totally new string' is evaluated" "Totally new string")
-- 'Totally new string' is evaluated
-- >>> putStrLn x
-- 'New string' is evaluated
-- New string
--
-- @since 0.3.0
writeLazyRef :: MonadPrim s m => Ref a s -> a -> m ()
writeLazyRef :: Ref a s -> a -> m ()
writeLazyRef (Ref MutVar# s a
ref#) a
a = (State# s -> State# s) -> m ()
forall s (m :: * -> *).
MonadPrim s m =>
(State# s -> State# s) -> m ()
prim_ (MutVar# s a -> a -> State# s -> State# s
forall d a. MutVar# d a -> a -> State# d -> State# d
writeMutVar# MutVar# s a
ref# a
a)
{-# INLINE writeLazyRef #-}


------------
-- Modify --
------------


-- | Apply a pure function to the contents of a mutable variable strictly. Returns the
-- artifact produced by the modifying function. Artifact is not forced, therfore it cannot
-- affect the outcome of modification. This function is a faster alternative to
-- `atomicModifyRef`, except without any guarantees of atomicity and ordering of mutable
-- operations during concurrent modification of the same `Ref`. For lazy version see
-- `modifyLazyRef` and for strict evaluation to normal form see `modifyDeepRef`.
--
-- @since 0.3.0
modifyRef :: MonadPrim s m => Ref a s -> (a -> (a, b)) -> m b
modifyRef :: Ref a s -> (a -> (a, b)) -> m b
modifyRef Ref a s
ref a -> (a, b)
f = Ref a s -> (a -> m (a, b)) -> m b
forall s (m :: * -> *) a b.
MonadPrim s m =>
Ref a s -> (a -> m (a, b)) -> m b
modifyRefM Ref a s
ref ((a, b) -> m (a, b)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((a, b) -> m (a, b)) -> (a -> (a, b)) -> a -> m (a, b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> (a, b)
f)
{-# INLINE modifyRef #-}

-- | Same as `modifyRef`, except it will evaluate result of computation to normal form.
--
-- @since 0.3.0
modifyDeepRef :: (NFData a, MonadPrim s m) => Ref a s -> (a -> (a, b)) -> m b
modifyDeepRef :: Ref a s -> (a -> (a, b)) -> m b
modifyDeepRef Ref a s
ref a -> (a, b)
f = Ref a s -> (a -> m (a, b)) -> m b
forall a s (m :: * -> *) b.
(NFData a, MonadPrim s m) =>
Ref a s -> (a -> m (a, b)) -> m b
modifyDeepRefM Ref a s
ref ((a, b) -> m (a, b)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((a, b) -> m (a, b)) -> (a -> (a, b)) -> a -> m (a, b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> (a, b)
f)
{-# INLINE modifyDeepRef #-}

-- | Apply a pure function to the contents of a mutable variable strictly.
--
-- @since 0.3.0
modifyRef_ :: MonadPrim s m => Ref a s -> (a -> a) -> m ()
modifyRef_ :: Ref a s -> (a -> a) -> m ()
modifyRef_ Ref a s
ref a -> a
f = Ref a s -> (a -> m a) -> m ()
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> (a -> m a) -> m ()
modifyRefM_ Ref a s
ref (a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> m a) -> (a -> a) -> a -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
f)
{-# INLINE modifyRef_ #-}

-- | Apply a pure function to the contents of a mutable variable strictly. Returns the new value.
--
-- @since 0.3.0
modifyFetchNewRef :: MonadPrim s m => Ref a s -> (a -> a) -> m a
modifyFetchNewRef :: Ref a s -> (a -> a) -> m a
modifyFetchNewRef Ref a s
ref a -> a
f = Ref a s -> (a -> m a) -> m a
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> (a -> m a) -> m a
modifyFetchNewRefM Ref a s
ref (a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> m a) -> (a -> a) -> a -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
f)
{-# INLINE modifyFetchNewRef #-}

-- | Apply a pure function to the contents of a mutable variable strictly. Returns the old value.
--
-- ==== __Examples__
--
-- >>> ref1 <- newRef (10 :: Int)
-- >>> ref2 <- newRef (201 :: Int)
-- >>> modifyRefM_ ref1 (\x -> modifyFetchOldRef ref2 (* x))
-- >>> readRef ref1
-- 201
-- >>> readRef ref2
-- 2010
--
-- @since 0.3.0
modifyFetchOldRef :: MonadPrim s m => Ref a s -> (a -> a) -> m a
modifyFetchOldRef :: Ref a s -> (a -> a) -> m a
modifyFetchOldRef Ref a s
ref a -> a
f = Ref a s -> (a -> m a) -> m a
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> (a -> m a) -> m a
modifyFetchOldRefM Ref a s
ref (a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> m a) -> (a -> a) -> a -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
f)
{-# INLINE modifyFetchOldRef #-}


-- | Apply a pure function to the contents of a mutable variable lazily. Returns the
-- artifact produced by the modifying function.
--
-- @since 0.3.0
modifyLazyRef :: MonadPrim s m => Ref a s -> (a -> (a, b)) -> m b
modifyLazyRef :: Ref a s -> (a -> (a, b)) -> m b
modifyLazyRef Ref a s
ref a -> (a, b)
f = Ref a s -> (a -> m (a, b)) -> m b
forall s (m :: * -> *) a b.
MonadPrim s m =>
Ref a s -> (a -> m (a, b)) -> m b
modifyLazyRefM Ref a s
ref ((a, b) -> m (a, b)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((a, b) -> m (a, b)) -> (a -> (a, b)) -> a -> m (a, b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> (a, b)
f)
{-# INLINE modifyLazyRef #-}



-- | Modify value of a mutable variable with a monadic action. It is not strict in a
-- return value of type @b@, but the ne value written into the mutable variable is
-- evaluated to WHNF.
--
-- ==== __Examples__
--
modifyRefM :: MonadPrim s m => Ref a s -> (a -> m (a, b)) -> m b
modifyRefM :: Ref a s -> (a -> m (a, b)) -> m b
modifyRefM Ref a s
ref a -> m (a, b)
f = do
  (a
a', b
b) <- a -> m (a, b)
f (a -> m (a, b)) -> m a -> m (a, b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Ref a s -> m a
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> m a
readRef Ref a s
ref
  b
b b -> m () -> m b
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Ref a s -> a -> m ()
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> a -> m ()
writeRef Ref a s
ref a
a'
{-# INLINE modifyRefM #-}


-- | Same as `modifyRefM`, except evaluates new value to normal form prior ot it being
-- written to the mutable ref.
modifyDeepRefM :: (NFData a, MonadPrim s m) => Ref a s -> (a -> m (a, b)) -> m b
modifyDeepRefM :: Ref a s -> (a -> m (a, b)) -> m b
modifyDeepRefM Ref a s
ref a -> m (a, b)
f = do
  (a
a', b
b) <- a -> m (a, b)
f (a -> m (a, b)) -> m a -> m (a, b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Ref a s -> m a
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> m a
readRef Ref a s
ref
  b
b b -> m () -> m b
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Ref a s -> a -> m ()
forall a s (m :: * -> *).
(NFData a, MonadPrim s m) =>
Ref a s -> a -> m ()
writeDeepRef Ref a s
ref a
a'
{-# INLINE modifyDeepRefM #-}


-- | Modify value of a mutable variable with a monadic action. Result is written strictly.
--
-- ==== __Examples__
--
-- >>> ref <- newRef (Just "Some value")
-- >>> modifyRefM_ ref $ \ mv -> Nothing <$ mapM_ putStrLn mv
-- Some value
-- >>> readRef ref
-- Nothing
--
-- @since 0.3.0
modifyRefM_ :: MonadPrim s m => Ref a s -> (a -> m a) -> m ()
modifyRefM_ :: Ref a s -> (a -> m a) -> m ()
modifyRefM_ Ref a s
ref a -> m a
f = Ref a s -> m a
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> m a
readRef Ref a s
ref m a -> (a -> m a) -> m a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= a -> m a
f m a -> (a -> m ()) -> m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Ref a s -> a -> m ()
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> a -> m ()
writeRef Ref a s
ref
{-# INLINE modifyRefM_ #-}

-- | Apply a monadic action to the contents of a mutable variable strictly. Returns the old value.
--
-- ==== __Examples__
--
-- >>> refName <- newRef "My name is: "
-- >>> refMyName <- newRef "Alexey"
-- >>> myName <- modifyFetchOldRefM refMyName $ \ name -> "Leo" <$ modifyRef_ refName (++ name)
-- >>> readRef refName >>= putStrLn
-- My name is: Alexey
-- >>> putStrLn myName
-- Alexey
-- >>> readRef refMyName >>= putStrLn
-- Leo
--
-- @since 0.3.0
modifyFetchOldRefM :: MonadPrim s m => Ref a s -> (a -> m a) -> m a
modifyFetchOldRefM :: Ref a s -> (a -> m a) -> m a
modifyFetchOldRefM Ref a s
ref a -> m a
f = do
  a
a <- Ref a s -> m a
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> m a
readRef Ref a s
ref
  a
a a -> m () -> m a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ (Ref a s -> a -> m ()
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> a -> m ()
writeRef Ref a s
ref (a -> m ()) -> m a -> m ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< a -> m a
f a
a)
{-# INLINE modifyFetchOldRefM #-}


-- | Apply a monadic action to the contents of a mutable variable strictly. Returns the new value.
--
-- @since 0.3.0
modifyFetchNewRefM :: MonadPrim s m => Ref a s -> (a -> m a) -> m a
modifyFetchNewRefM :: Ref a s -> (a -> m a) -> m a
modifyFetchNewRefM Ref a s
ref a -> m a
f = do
  a
a <- Ref a s -> m a
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> m a
readRef Ref a s
ref
  a
a' <- a -> m a
f a
a
  a
a' a -> m () -> m a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Ref a s -> a -> m ()
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> a -> m ()
writeRef Ref a s
ref a
a'
{-# INLINE modifyFetchNewRefM #-}

-- | Same as `modifyRefM`, but do not evaluate the new value written into the `Ref`.
--
-- @since 0.3.0
modifyLazyRefM :: MonadPrim s m => Ref a s -> (a -> m (a, b)) -> m b
modifyLazyRefM :: Ref a s -> (a -> m (a, b)) -> m b
modifyLazyRefM Ref a s
ref a -> m (a, b)
f = do
  a
a <- Ref a s -> m a
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> m a
readRef Ref a s
ref
  (a
a', b
b) <- a -> m (a, b)
f a
a
  b
b b -> m () -> m b
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Ref a s -> a -> m ()
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> a -> m ()
writeLazyRef Ref a s
ref a
a'
{-# INLINE modifyLazyRefM #-}

------------
-- Atomic --
------------


-- | Evaluate a value and write it atomically into a `Ref`. This is different from
-- `writeRef` because [a memory barrier](https://en.wikipedia.org/wiki/Memory_barrier)
-- will be issued. Use this instead of `writeRef` in order to guarantee the ordering of
-- operations in a concurrent environment.
--
-- @since 0.3.0
atomicWriteRef :: MonadPrim s m => Ref e s -> e -> m ()
atomicWriteRef :: Ref e s -> e -> m ()
atomicWriteRef Ref e s
ref !e
x = Ref e s -> (e -> e) -> m ()
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> (a -> a) -> m ()
atomicModifyRef_ Ref e s
ref (e -> e -> e
forall a b. a -> b -> a
const e
x)
{-# INLINE atomicWriteRef #-}

-- | This will behave exactly the same as `readRef` when the `Ref` is accessed within a
-- single thread only. However, despite being slower, it can help with with restricting
-- order of operations in cases when multiple threads perform modifications to the `Ref`
-- because it implies a memory barrier.
--
-- @since 0.3.0
atomicReadRef :: MonadPrim s m => Ref e s -> m e
atomicReadRef :: Ref e s -> m e
atomicReadRef Ref e s
ref = Ref e s -> (e -> e) -> m e
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> (a -> a) -> m a
atomicModifyFetchOldRef Ref e s
ref e -> e
forall a. a -> a
id

-- | Same as `atomicWriteRef`, but also returns the old value.
--
-- @since 0.3.0
atomicSwapRef :: MonadPrim s m => Ref e s -> e -> m e
atomicSwapRef :: Ref e s -> e -> m e
atomicSwapRef Ref e s
ref e
x = Ref e s -> (e -> e) -> m e
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> (a -> a) -> m a
atomicModifyFetchOldRef Ref e s
ref (e -> e -> e
forall a b. a -> b -> a
const e
x)
{-# INLINE atomicSwapRef #-}

numTriesCAS :: Int
numTriesCAS :: Int
numTriesCAS = Int
35

-- | Apply a function to the value stored in a mutable `Ref` atomically. Function is
-- applied strictly with respect to the newly returned value, which matches the semantics
-- of `atomicModifyIORef'`, however the difference is that the artifact returned by the
-- action is not evaluated.
--
-- ====__Example__
--
-- >>> 
--
-- @since 0.3.0
atomicModifyRef :: MonadPrim s m => Ref a s -> (a -> (a, b)) -> m b
atomicModifyRef :: Ref a s -> (a -> (a, b)) -> m b
atomicModifyRef Ref a s
ref a -> (a, b)
f = Ref a s -> m a
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> m a
readRef Ref a s
ref m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> a -> m b
loop (Int
0 :: Int)
  where
    loop :: Int -> a -> m b
loop Int
i a
old
      | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
numTriesCAS = do
        case a -> (a, b)
f a
old of
          (!a
new, b
result) -> do
            (Bool
success, a
current) <- Ref a s -> a -> a -> m (Bool, a)
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> a -> a -> m (Bool, a)
casRef Ref a s
ref a
old a
new
            if Bool
success
              then b -> m b
forall (f :: * -> *) a. Applicative f => a -> f a
pure b
result
              else Int -> a -> m b
loop (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) a
current
      | Bool
otherwise = Ref a s -> (a -> (a, b)) -> m b
forall s (m :: * -> *) a b.
MonadPrim s m =>
Ref a s -> (a -> (a, b)) -> m b
atomicModifyRef2 Ref a s
ref a -> (a, b)
f
{-# INLINE atomicModifyRef #-}



atomicModifyRef2 :: MonadPrim s m => Ref a s -> (a -> (a, b)) -> m b
atomicModifyRef2 :: Ref a s -> (a -> (a, b)) -> m b
atomicModifyRef2 (Ref MutVar# s a
ref#) a -> (a, b)
f =
#if __GLASGOW_HASKELL__ <= 806
  let g prev =
        case f prev of
          r@(!_new, _result) -> r
   in prim (atomicModifyMutVar# ref# g)
#else
  (State# s -> (# State# s, b #)) -> m b
forall s (m :: * -> *) a.
MonadPrim s m =>
(State# s -> (# State# s, a #)) -> m a
prim ((State# s -> (# State# s, b #)) -> m b)
-> (State# s -> (# State# s, b #)) -> m b
forall a b. (a -> b) -> a -> b
$ \State# s
s ->
    case MutVar# s a
-> (a -> (a, b)) -> State# s -> (# State# s, a, (a, b) #)
forall d a c.
MutVar# d a -> (a -> c) -> State# d -> (# State# d, a, c #)
atomicModifyMutVar2# MutVar# s a
ref# a -> (a, b)
f State# s
s of
      (# State# s
s', a
_old, (!a
_new, b
result) #) -> (# State# s
s', b
result #)
#endif
{-# INLINE atomicModifyRef2 #-}


atomicModifyRef_ :: MonadPrim s m => Ref a s -> (a -> a) -> m ()
atomicModifyRef_ :: Ref a s -> (a -> a) -> m ()
atomicModifyRef_ Ref a s
ref a -> a
f = Ref a s -> m a
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> m a
readRef Ref a s
ref m a -> (a -> m ()) -> m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> a -> m ()
loop (Int
0 :: Int)
  where
    loop :: Int -> a -> m ()
loop Int
i a
old
      | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
numTriesCAS = do
        (Bool
success, a
current) <- Ref a s -> a -> a -> m (Bool, a)
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> a -> a -> m (Bool, a)
casRef Ref a s
ref a
old (a -> m (Bool, a)) -> a -> m (Bool, a)
forall a b. (a -> b) -> a -> b
$! a -> a
f a
old
        Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
success (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ Int -> a -> m ()
loop (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) a
current
      | Bool
otherwise = Ref a s -> (a -> a) -> m ()
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> (a -> a) -> m ()
atomicModifyRef2_ Ref a s
ref a -> a
f
{-# INLINE atomicModifyRef_ #-}

atomicModifyRef2_ :: MonadPrim s m => Ref a s -> (a -> a) -> m ()
atomicModifyRef2_ :: Ref a s -> (a -> a) -> m ()
atomicModifyRef2_ (Ref MutVar# s a
ref#) a -> a
f =
  (State# s -> State# s) -> m ()
forall s (m :: * -> *).
MonadPrim s m =>
(State# s -> State# s) -> m ()
prim_ ((State# s -> State# s) -> m ()) -> (State# s -> State# s) -> m ()
forall a b. (a -> b) -> a -> b
$ \State# s
s ->
    case MutVar# s a -> (a -> a) -> State# s -> (# State# s, a, a #)
forall d a.
MutVar# d a -> (a -> a) -> State# d -> (# State# d, a, a #)
atomicModifyMutVar_# MutVar# s a
ref# a -> a
f State# s
s of
      (# State# s
s', a
_prev, !a
_cur #) -> State# s
s'
{-# INLINE atomicModifyRef2_ #-}

atomicModifyFetchOldRef :: MonadPrim s m => Ref a s -> (a -> a) -> m a
atomicModifyFetchOldRef :: Ref a s -> (a -> a) -> m a
atomicModifyFetchOldRef Ref a s
ref a -> a
f = Ref a s -> m a
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> m a
readRef Ref a s
ref m a -> (a -> m a) -> m a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> a -> m a
loop (Int
0 :: Int)
  where
    loop :: Int -> a -> m a
loop Int
i a
old
      | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
numTriesCAS = do
        (Bool
success, a
current) <- Ref a s -> a -> a -> m (Bool, a)
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> a -> a -> m (Bool, a)
casRef Ref a s
ref a
old (a -> m (Bool, a)) -> a -> m (Bool, a)
forall a b. (a -> b) -> a -> b
$! a -> a
f a
old
        if Bool
success
          then a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
old
          else Int -> a -> m a
loop (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) a
current
      | Bool
otherwise = Ref a s -> (a -> a) -> m a
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> (a -> a) -> m a
atomicModifyFetchOldRef2 Ref a s
ref a -> a
f
{-# INLINE atomicModifyFetchNewRef #-}

atomicModifyFetchOldRef2 :: MonadPrim s m => Ref a s -> (a -> a) -> m a
atomicModifyFetchOldRef2 :: Ref a s -> (a -> a) -> m a
atomicModifyFetchOldRef2 (Ref MutVar# s a
ref#) a -> a
f =
  (State# s -> (# State# s, a #)) -> m a
forall s (m :: * -> *) a.
MonadPrim s m =>
(State# s -> (# State# s, a #)) -> m a
prim ((State# s -> (# State# s, a #)) -> m a)
-> (State# s -> (# State# s, a #)) -> m a
forall a b. (a -> b) -> a -> b
$ \State# s
s ->
    case MutVar# s a -> (a -> a) -> State# s -> (# State# s, a, a #)
forall d a.
MutVar# d a -> (a -> a) -> State# d -> (# State# d, a, a #)
atomicModifyMutVar_# MutVar# s a
ref# a -> a
f State# s
s of
      (# State# s
s', a
_prev, !a
_cur #) -> (# State# s
s', a
_prev #)
{-# INLINE atomicModifyFetchOldRef2 #-}


atomicModifyFetchNewRef :: MonadPrim s m => Ref a s -> (a -> a) -> m a
atomicModifyFetchNewRef :: Ref a s -> (a -> a) -> m a
atomicModifyFetchNewRef Ref a s
ref a -> a
f = Ref a s -> m a
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> m a
readRef Ref a s
ref m a -> (a -> m a) -> m a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> a -> m a
loop (Int
0 :: Int)
  where
    loop :: Int -> a -> m a
loop Int
i a
old
      | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
numTriesCAS = do
        (Bool
success, a
current) <- Ref a s -> a -> a -> m (Bool, a)
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> a -> a -> m (Bool, a)
casRef Ref a s
ref a
old (a -> m (Bool, a)) -> a -> m (Bool, a)
forall a b. (a -> b) -> a -> b
$! a -> a
f a
old
        if Bool
success
          then a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
current
          else Int -> a -> m a
loop (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) a
current
      | Bool
otherwise = Ref a s -> (a -> a) -> m a
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> (a -> a) -> m a
atomicModifyFetchNewRef2 Ref a s
ref a -> a
f
{-# INLINE atomicModifyFetchOldRef #-}

atomicModifyFetchNewRef2 :: MonadPrim s m => Ref a s -> (a -> a) -> m a
atomicModifyFetchNewRef2 :: Ref a s -> (a -> a) -> m a
atomicModifyFetchNewRef2 (Ref MutVar# s a
ref#) a -> a
f =
  (State# s -> (# State# s, a #)) -> m a
forall s (m :: * -> *) a.
MonadPrim s m =>
(State# s -> (# State# s, a #)) -> m a
prim ((State# s -> (# State# s, a #)) -> m a)
-> (State# s -> (# State# s, a #)) -> m a
forall a b. (a -> b) -> a -> b
$ \State# s
s ->
    case MutVar# s a -> (a -> a) -> State# s -> (# State# s, a, a #)
forall d a.
MutVar# d a -> (a -> a) -> State# d -> (# State# d, a, a #)
atomicModifyMutVar_# MutVar# s a
ref# a -> a
f State# s
s of
      (# State# s
s', a
_prev, !a
cur #) -> (# State# s
s', a
cur #)
{-# INLINE atomicModifyFetchNewRef2 #-}



atomicModifyFetchBothRef :: MonadPrim s m => Ref a s -> (a -> a) -> m (a, a)
atomicModifyFetchBothRef :: Ref a s -> (a -> a) -> m (a, a)
atomicModifyFetchBothRef Ref a s
ref a -> a
f = Ref a s -> m a
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> m a
readRef Ref a s
ref m a -> (a -> m (a, a)) -> m (a, a)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> a -> m (a, a)
loop (Int
0 :: Int)
  where
    loop :: Int -> a -> m (a, a)
loop Int
i a
old
      | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
numTriesCAS = do
        (Bool
success, a
current) <- Ref a s -> a -> a -> m (Bool, a)
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> a -> a -> m (Bool, a)
casRef Ref a s
ref a
old (a -> m (Bool, a)) -> a -> m (Bool, a)
forall a b. (a -> b) -> a -> b
$! a -> a
f a
old
        if Bool
success
          then (a, a) -> m (a, a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a
old, a
current)
          else Int -> a -> m (a, a)
loop (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) a
current
      | Bool
otherwise = Ref a s -> (a -> a) -> m (a, a)
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> (a -> a) -> m (a, a)
atomicModifyFetchBothRef2 Ref a s
ref a -> a
f
{-# INLINE atomicModifyFetchBothRef #-}


atomicModifyFetchBothRef2 :: MonadPrim s m => Ref a s -> (a -> a) -> m (a, a)
atomicModifyFetchBothRef2 :: Ref a s -> (a -> a) -> m (a, a)
atomicModifyFetchBothRef2 (Ref MutVar# s a
ref#) a -> a
f =
  (State# s -> (# State# s, (a, a) #)) -> m (a, a)
forall s (m :: * -> *) a.
MonadPrim s m =>
(State# s -> (# State# s, a #)) -> m a
prim ((State# s -> (# State# s, (a, a) #)) -> m (a, a))
-> (State# s -> (# State# s, (a, a) #)) -> m (a, a)
forall a b. (a -> b) -> a -> b
$ \State# s
s ->
    case MutVar# s a -> (a -> a) -> State# s -> (# State# s, a, a #)
forall d a.
MutVar# d a -> (a -> a) -> State# d -> (# State# d, a, a #)
atomicModifyMutVar_# MutVar# s a
ref# a -> a
f State# s
s of
      (# State# s
s', a
prev, !a
cur #) -> (# State# s
s', (a
prev, a
cur) #)
{-# INLINE atomicModifyFetchBothRef2 #-}

-- | Appy a function to the value in mutable `Ref` atomically
--
-- @since 0.3.0
atomicModifyFetchRef :: MonadPrim s m => Ref a s -> (a -> (a, b)) -> m (a, a, b)
atomicModifyFetchRef :: Ref a s -> (a -> (a, b)) -> m (a, a, b)
atomicModifyFetchRef Ref a s
ref a -> (a, b)
f = Ref a s -> m a
forall s (m :: * -> *) a. MonadPrim s m => Ref a s -> m a
readRef Ref a s
ref m a -> (a -> m (a, a, b)) -> m (a, a, b)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> a -> m (a, a, b)
loop (Int
0 :: Int)
  where
    loop :: Int -> a -> m (a, a, b)
loop Int
i a
old
      | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
numTriesCAS = do
        case a -> (a, b)
f a
old of
          (!a
new, b
result) -> do
            (Bool
success, a
current) <- Ref a s -> a -> a -> m (Bool, a)
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> a -> a -> m (Bool, a)
casRef Ref a s
ref a
old a
new
            if Bool
success
              then (a, a, b) -> m (a, a, b)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a
old, a
new, b
result)
              else Int -> a -> m (a, a, b)
loop (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) a
current
      | Bool
otherwise = Ref a s -> (a -> (a, b)) -> m (a, a, b)
forall s (m :: * -> *) a b.
MonadPrim s m =>
Ref a s -> (a -> (a, b)) -> m (a, a, b)
atomicModifyFetchRef2 Ref a s
ref a -> (a, b)
f
{-# INLINE atomicModifyFetchRef #-}


-- TODO: Test this property
-- @atomicModifyIORef' ref (\x -> (x+1, undefined))@
--
-- will increment the 'IORef' and then throw an exception in the calling
-- thread.

atomicModifyFetchRef2 :: MonadPrim s m => Ref a s -> (a -> (a, b)) -> m (a, a, b)
atomicModifyFetchRef2 :: Ref a s -> (a -> (a, b)) -> m (a, a, b)
atomicModifyFetchRef2 Ref a s
ref a -> (a, b)
f =
  Ref a s -> (a -> (a, b)) -> m (a, a, b)
forall s (m :: * -> *) a b.
MonadPrim s m =>
Ref a s -> (a -> (a, b)) -> m (a, a, b)
atomicModifyFetchLazyRef Ref a s
ref ((a -> (a, b)) -> m (a, a, b)) -> (a -> (a, b)) -> m (a, a, b)
forall a b. (a -> b) -> a -> b
$ \a
current ->
    case a -> (a, b)
f a
current of
      r :: (a, b)
r@(!a
_new, b
_res) -> (a, b)
r
{-# INLINE atomicModifyFetchRef2 #-}


-- atomicModifyRef2 :: MonadPrim s m => Ref a s -> (a -> (a, b)) -> m (a, a, b)
-- (Ref ref#) f =
--   let g a =
--         case f a of
--           t@(a', _) -> a' `seq` t
--    in prim $ \s ->
--         case atomicModifyMutVar2# ref# g s of
--           (# s', old, (new, b) #) ->
--             case seq# new s' of
--               (# s'', new' #) ->
--                 case seq# b s'' of
--                   (# s''', b' #) -> (# s''', (old, new', b') #)

-- atomicModifyRef2 :: MonadPrim s m => Ref a s -> (a -> (a, b)) -> m b
-- atomicModifyRef2 (Ref ref#) f =
--   prim $ \s ->
--     case atomicModifyMutVar2# ref# f s of
--       (# s', _old, res #) -> (# s', res #)
-- {-# INLINE atomicModifyRef2 #-}






atomicModifyFetchBothLazyRef :: MonadPrim s m => Ref a s -> (a -> a) -> m (a, a)
atomicModifyFetchBothLazyRef :: Ref a s -> (a -> a) -> m (a, a)
atomicModifyFetchBothLazyRef (Ref MutVar# s a
ref#) a -> a
f =
  (State# s -> (# State# s, (a, a) #)) -> m (a, a)
forall s (m :: * -> *) a.
MonadPrim s m =>
(State# s -> (# State# s, a #)) -> m a
prim ((State# s -> (# State# s, (a, a) #)) -> m (a, a))
-> (State# s -> (# State# s, (a, a) #)) -> m (a, a)
forall a b. (a -> b) -> a -> b
$ \State# s
s ->
    case MutVar# s a -> (a -> a) -> State# s -> (# State# s, a, a #)
forall d a.
MutVar# d a -> (a -> a) -> State# d -> (# State# d, a, a #)
atomicModifyMutVar_# MutVar# s a
ref# a -> a
f State# s
s of
      (# State# s
s', a
prev, a
cur #) -> (# State# s
s', (a
prev, a
cur) #)
{-# INLINE atomicModifyFetchBothLazyRef #-}


casRef :: MonadPrim s m => Ref a s -> a -> a -> m (Bool, a)
casRef :: Ref a s -> a -> a -> m (Bool, a)
casRef (Ref MutVar# s a
ref#) a
expOld a
new =
  (State# s -> (# State# s, (Bool, a) #)) -> m (Bool, a)
forall s (m :: * -> *) a.
MonadPrim s m =>
(State# s -> (# State# s, a #)) -> m a
prim ((State# s -> (# State# s, (Bool, a) #)) -> m (Bool, a))
-> (State# s -> (# State# s, (Bool, a) #)) -> m (Bool, a)
forall a b. (a -> b) -> a -> b
$ \State# s
s ->
    case MutVar# s a -> a -> a -> State# s -> (# State# s, Int#, a #)
forall d a.
MutVar# d a -> a -> a -> State# d -> (# State# d, Int#, a #)
casMutVar# MutVar# s a
ref# a
expOld a
new State# s
s of
      (# State# s
s', Int#
failed#, a
actualOld #) ->
        (# State# s
s', (Int# -> Bool
isTrue# (Int#
failed# Int# -> Int# -> Int#
==# Int#
0#), a
actualOld) #)
{-# INLINE casRef #-}

atomicModifyFetchLazyRef :: MonadPrim s m => Ref a s -> (a -> (a, b)) -> m (a, a, b)
atomicModifyFetchLazyRef :: Ref a s -> (a -> (a, b)) -> m (a, a, b)
atomicModifyFetchLazyRef (Ref MutVar# s a
ref#) a -> (a, b)
f =
  (State# s -> (# State# s, (a, a, b) #)) -> m (a, a, b)
forall s (m :: * -> *) a.
MonadPrim s m =>
(State# s -> (# State# s, a #)) -> m a
prim ((State# s -> (# State# s, (a, a, b) #)) -> m (a, a, b))
-> (State# s -> (# State# s, (a, a, b) #)) -> m (a, a, b)
forall a b. (a -> b) -> a -> b
$ \State# s
s ->
    case MutVar# s a
-> (a -> (a, b)) -> State# s -> (# State# s, a, (a, b) #)
forall d a c.
MutVar# d a -> (a -> c) -> State# d -> (# State# d, a, c #)
atomicModifyMutVar2# MutVar# s a
ref# a -> (a, b)
f State# s
s of
      (# State# s
s', a
old, ~(a
new, b
res) #) -> (# State# s
s', (a
old, a
new, b
res) #)
{-# INLINE atomicModifyFetchLazyRef #-}


atomicModifyLazyRef :: MonadPrim s m => Ref a s -> (a -> (a, b)) -> m b
atomicModifyLazyRef :: Ref a s -> (a -> (a, b)) -> m b
atomicModifyLazyRef (Ref MutVar# s a
ref#) a -> (a, b)
f = (State# s -> (# State# s, b #)) -> m b
forall s (m :: * -> *) a.
MonadPrim s m =>
(State# s -> (# State# s, a #)) -> m a
prim (MutVar# s a -> (a -> (a, b)) -> State# s -> (# State# s, b #)
forall s a b c.
MutVar# s a -> (a -> b) -> State# s -> (# State# s, c #)
atomicModifyMutVar# MutVar# s a
ref# a -> (a, b)
f)
{-# INLINE atomicModifyLazyRef #-}

atomicModifyLazyRef_ :: MonadPrim s m => Ref a s -> (a -> a) -> m ()
atomicModifyLazyRef_ :: Ref a s -> (a -> a) -> m ()
atomicModifyLazyRef_ (Ref MutVar# s a
ref#) a -> a
f =
  (State# s -> State# s) -> m ()
forall s (m :: * -> *).
MonadPrim s m =>
(State# s -> State# s) -> m ()
prim_ ((State# s -> State# s) -> m ()) -> (State# s -> State# s) -> m ()
forall a b. (a -> b) -> a -> b
$ \State# s
s ->
    case MutVar# s a -> (a -> a) -> State# s -> (# State# s, a, a #)
forall d a.
MutVar# d a -> (a -> a) -> State# d -> (# State# d, a, a #)
atomicModifyMutVar_# MutVar# s a
ref# a -> a
f State# s
s of
      (# State# s
s', a
_prev, a
_cur #) -> State# s
s'
{-# INLINE atomicModifyLazyRef_ #-}

atomicModifyFetchOldLazyRef :: MonadPrim s m => Ref a s -> (a -> a) -> m a
atomicModifyFetchOldLazyRef :: Ref a s -> (a -> a) -> m a
atomicModifyFetchOldLazyRef (Ref MutVar# s a
ref#) a -> a
f =
  (State# s -> (# State# s, a #)) -> m a
forall s (m :: * -> *) a.
MonadPrim s m =>
(State# s -> (# State# s, a #)) -> m a
prim ((State# s -> (# State# s, a #)) -> m a)
-> (State# s -> (# State# s, a #)) -> m a
forall a b. (a -> b) -> a -> b
$ \State# s
s ->
    case MutVar# s a -> (a -> a) -> State# s -> (# State# s, a, a #)
forall d a.
MutVar# d a -> (a -> a) -> State# d -> (# State# d, a, a #)
atomicModifyMutVar_# MutVar# s a
ref# a -> a
f State# s
s of
      (# State# s
s', a
prev, a
_cur #) -> (# State# s
s', a
prev #)

atomicModifyFetchNewLazyRef :: MonadPrim s m => Ref a s -> (a -> a) -> m a
atomicModifyFetchNewLazyRef :: Ref a s -> (a -> a) -> m a
atomicModifyFetchNewLazyRef (Ref MutVar# s a
ref#) a -> a
f =
  (State# s -> (# State# s, a #)) -> m a
forall s (m :: * -> *) a.
MonadPrim s m =>
(State# s -> (# State# s, a #)) -> m a
prim ((State# s -> (# State# s, a #)) -> m a)
-> (State# s -> (# State# s, a #)) -> m a
forall a b. (a -> b) -> a -> b
$ \State# s
s ->
    case MutVar# s a -> (a -> a) -> State# s -> (# State# s, a, a #)
forall d a.
MutVar# d a -> (a -> a) -> State# d -> (# State# d, a, a #)
atomicModifyMutVar_# MutVar# s a
ref# a -> a
f State# s
s of
      (# State# s
s', a
_prev, a
cur #) -> (# State# s
s', a
cur #)

atomicWriteLazyRef :: MonadPrim s m => Ref b s -> b -> m ()
atomicWriteLazyRef :: Ref b s -> b -> m ()
atomicWriteLazyRef Ref b s
ref b
x = Ref b s -> (b -> b) -> m ()
forall s (m :: * -> *) a.
MonadPrim s m =>
Ref a s -> (a -> a) -> m ()
atomicModifyLazyRef_ Ref b s
ref (b -> b -> b
forall a b. a -> b -> a
const b
x)


-- | Convert `Ref` to `STRef`
--
-- @since 0.3.0
toSTRef :: Ref a s -> ST.STRef s a
toSTRef :: Ref a s -> STRef s a
toSTRef (Ref MutVar# s a
ref#) = MutVar# s a -> STRef s a
forall s a. MutVar# s a -> STRef s a
ST.STRef MutVar# s a
ref#
{-# INLINE toSTRef #-}

-- | Convert `STRef` to `Ref`
--
-- @since 0.3.0
fromSTRef :: ST.STRef s a -> Ref a s
fromSTRef :: STRef s a -> Ref a s
fromSTRef (ST.STRef MutVar# s a
ref#) = MutVar# s a -> Ref a s
forall a s. MutVar# s a -> Ref a s
Ref MutVar# s a
ref#
{-# INLINE fromSTRef #-}

-- | Convert `Ref` to `IORef`
--
-- @since 0.3.0
toIORef :: Ref a RW -> IO.IORef a
toIORef :: Ref a RW -> IORef a
toIORef = STRef RW a -> IORef a
coerce (STRef RW a -> IORef a)
-> (Ref a RW -> STRef RW a) -> Ref a RW -> IORef a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ref a RW -> STRef RW a
forall a s. Ref a s -> STRef s a
toSTRef
{-# INLINE toIORef #-}

-- | Convert `IORef` to `Ref`
--
-- @since 0.3.0
fromIORef :: IO.IORef a -> Ref a RW
fromIORef :: IORef a -> Ref a RW
fromIORef = STRef RW a -> Ref a RW
forall s a. STRef s a -> Ref a s
fromSTRef (STRef RW a -> Ref a RW)
-> (IORef a -> STRef RW a) -> IORef a -> Ref a RW
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IORef a -> STRef RW a
coerce
{-# INLINE fromIORef #-}




-- | Create a `Weak` pointer associated with the supplied `Ref`.
--
-- Same as `Data.IORef.mkWeakRef` from @base@, but works in any `MonadPrim` with
-- `RealWorld` state token.
--
-- @since 0.3.0
mkWeakRef ::
     forall a b m. MonadUnliftPrim RW m
  => Ref a RW
  -> m b -- ^ An action that will get executed whenever `Ref` gets garbage collected by
         -- the runtime.
  -> m (Weak (Ref a RW))
mkWeakRef :: Ref a RW -> m b -> m (Weak (Ref a RW))
mkWeakRef ref :: Ref a RW
ref@(Ref MutVar# RW a
ref#) !m b
finalizer =
  m b
-> ((State# RW -> (# State# RW, b #))
    -> State# RW -> (# State# RW, Weak (Ref a RW) #))
-> m (Weak (Ref a RW))
forall s (m :: * -> *) a b.
MonadUnliftPrim s m =>
m a
-> ((State# s -> (# State# s, a #))
    -> State# s -> (# State# s, b #))
-> m b
runInPrimBase m b
finalizer (((State# RW -> (# State# RW, b #))
  -> State# RW -> (# State# RW, Weak (Ref a RW) #))
 -> m (Weak (Ref a RW)))
-> ((State# RW -> (# State# RW, b #))
    -> State# RW -> (# State# RW, Weak (Ref a RW) #))
-> m (Weak (Ref a RW))
forall a b. (a -> b) -> a -> b
$ \State# RW -> (# State# RW, b #)
f# State# RW
s ->
    case MutVar# RW a
-> Ref a RW
-> (State# RW -> (# State# RW, b #))
-> State# RW
-> (# State# RW, Weak# (Ref a RW) #)
forall a b c.
a
-> b
-> (State# RW -> (# State# RW, c #))
-> State# RW
-> (# State# RW, Weak# b #)
mkWeak# MutVar# RW a
ref# Ref a RW
ref State# RW -> (# State# RW, b #)
f# State# RW
s of
      (# State# RW
s', Weak# (Ref a RW)
weak# #) -> (# State# RW
s', Weak# (Ref a RW) -> Weak (Ref a RW)
forall v. Weak# v -> Weak v
Weak Weak# (Ref a RW)
weak# #)
{-# INLINE mkWeakRef #-}



-- atomicModifyIORef' :: IORef a -> (a -> (a,b)) -> IO b
-- -- See Note [atomicModifyIORef' definition]
-- atomicModifyIORef' ref f = do
--   (_old, (_new, !res)) <- atomicModifyIORef2 ref $
--     \old -> case f old of
--        r@(!_new, _res) -> r
--   pure res
-- atomicModifyIORef' :: IORef a -> (a -> (a,b)) -> IO b
-- atomicModifyIORef' (IORef (STRef r#)) f =
--   IO
--     (\s ->
--        case atomicModifyMutVar2# r# f s of
--          (# s', old, res@(!_new, _) #) -> (# s', (old, res) #))

-- atomicModifyIORef2 :: IORef a -> (a -> (a,b)) -> IO (a, (a, b))
-- atomicModifyIORef2 ref f = do
--   r@(_old, (_new, _res)) <- atomicModifyIORef2Lazy ref f
--   return r

-- atomicModifyIORef2Lazy :: IORef a -> (a -> (a,b)) -> IO (a, (a, b))
-- atomicModifyIORef2Lazy (IORef (STRef r#)) f =
--   IO (\s -> case atomicModifyMutVar2# r# f s of
--               (# s', old, res #) -> (# s', (old, res) #))