module Data.IORef

import Prelude

-- We should test this at some point

ptype IORef : U → U
pfunc primNewIORef uses (MkIORes) : ∀ a. a → IO (IORef a) := `(_, a) => (w) => Prelude_MkIORes([a], w)`
pfunc primReadIORef uses (MkIORes) : ∀ a. IORef a → IO a := `(_, ref) => (w) => Prelude_MkIORes(ref[0], w)`
pfunc primWriteIORef uses (MkIORes MkUnit) : ∀ a. IORef a → a → IO Unit := `(_, ref, a) => (w) => {
  ref[0] = a
  return Prelude_MkIORes(Prelude_MkUnit,w)
}`

newIORef : ∀ io a. {{HasIO io}} → a → io (IORef a)
newIORef a = liftIO $ primNewIORef a

readIORef : ∀ io a. {{HasIO io}} → IORef a → io a
readIORef ref = liftIO $ primReadIORef ref

writeIORef : ∀ io a. {{HasIO io}} → IORef a -> a -> io Unit
writeIORef ref a = liftIO $ primWriteIORef ref a

-- Idris HasIO constraints to monad, we don't have those constraints yet
modifyIORef : ∀ io a. {{Monad io}} {{HasIO io}} → IORef a -> (a -> a) -> io Unit
modifyIORef {io} ref f =
  bind {io} (readIORef ref) $ \a => writeIORef ref (f a)
