content: {-# LANGUAGE MagicHash    #-}
  {-# LANGUAGE TypeFamilies #-}
  -- | Use @ByteArray@s containing one element for mutable references.
  --
  -- This is similar to @URef@s, but avoids the overhead of storing the length of
  -- the @Vector@, which we statically know will always be 1. This allows it to
  -- be a bit faster.
  --
  -- Motivated by: <http://stackoverflow.com/questions/27261813/why-is-my-little-stref-int-require-allocating-gigabytes> and ArrayRef.
  module Data.Mutable.PRef
      ( -- * Types
        PRef
      , IOPRef
        -- * Functions
      , asPRef
      , MutableRef (..)
      ) where
  
  import Data.Mutable.Class
  import Data.Primitive           (sizeOf)
  import Data.Primitive.ByteArray (MutableByteArray, newByteArray, readByteArray,
                                   writeByteArray)
  import Data.Primitive.Types     (Prim)
  
  -- | A primitive ByteArray reference, supporting any monad.
  --
  -- Since 0.2.0
  newtype PRef s a = PRef (MutableByteArray s)
  
  -- |
  -- Since 0.2.0
  asPRef :: PRef s a -> PRef s a
  asPRef x = x
  {-# INLINE asPRef #-}
  
  -- | A primitive ByteArray IO reference.
  type IOPRef = PRef (PrimState IO)
  
  instance MutableContainer (PRef s a) where
      type MCState (PRef s a) = s
  instance Prim a => MutableRef (PRef s a) where
      type RefElement (PRef s a) = a
  
      newRef x = do
          ba <- newByteArray (sizeOf $! x)
          writeByteArray ba 0 x
          return $! PRef ba
      {-# INLINE newRef #-}
  
      readRef (PRef ba) = readByteArray ba 0
      {-# INLINE readRef #-}
  
      writeRef (PRef ba) = writeByteArray ba 0
      {-# INLINE writeRef #-}
  
      modifyRef (PRef ba) f = do
          x <- readByteArray ba 0
          writeByteArray ba 0 $! f x
      {-# INLINE modifyRef #-}
  
      modifyRef' = modifyRef
      {-# INLINE modifyRef' #-}
  