{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}

{-# OPTIONS_GHC -Wno-orphans #-}

module Nix.Var where

import           Control.Monad.Ref
import           Data.GADT.Compare
import           Data.IORef
import           Data.Maybe
import           Data.STRef
import           Type.Reflection ((:~:)(Refl))

import           Unsafe.Coerce

type Var m = Ref m

type MonadVar m = MonadAtomicRef m

eqVar :: forall m a . GEq (Ref m) => Ref m a -> Ref m a -> Bool
eqVar :: Ref m a -> Ref m a -> Bool
eqVar a :: Ref m a
a b :: Ref m a
b = Maybe (a :~: a) -> Bool
forall a. Maybe a -> Bool
isJust (Maybe (a :~: a) -> Bool) -> Maybe (a :~: a) -> Bool
forall a b. (a -> b) -> a -> b
$ Ref m a -> Ref m a -> Maybe (a :~: a)
forall k (f :: k -> *) (a :: k) (b :: k).
GEq f =>
f a -> f b -> Maybe (a :~: b)
geq Ref m a
a Ref m a
b

newVar :: MonadRef m => a -> m (Ref m a)
newVar :: a -> m (Ref m a)
newVar = a -> m (Ref m a)
forall (m :: * -> *) a. MonadRef m => a -> m (Ref m a)
newRef

readVar :: MonadRef m => Ref m a -> m a
readVar :: Ref m a -> m a
readVar = Ref m a -> m a
forall (m :: * -> *) a. MonadRef m => Ref m a -> m a
readRef

writeVar :: MonadRef m => Ref m a -> a -> m ()
writeVar :: Ref m a -> a -> m ()
writeVar = Ref m a -> a -> m ()
forall (m :: * -> *) a. MonadRef m => Ref m a -> a -> m ()
writeRef

atomicModifyVar :: MonadAtomicRef m => Ref m a -> (a -> (a, b)) -> m b
atomicModifyVar :: Ref m a -> (a -> (a, b)) -> m b
atomicModifyVar = Ref m a -> (a -> (a, b)) -> m b
forall (m :: * -> *) a b.
MonadAtomicRef m =>
Ref m a -> (a -> (a, b)) -> m b
atomicModifyRef

--TODO: Upstream GEq instances
instance GEq IORef where
  a :: IORef a
a geq :: IORef a -> IORef b -> Maybe (a :~: b)
`geq` b :: IORef b
b = if IORef a
a IORef a -> IORef a -> Bool
forall a. Eq a => a -> a -> Bool
== IORef b -> IORef a
forall a b. a -> b
unsafeCoerce IORef b
b then (a :~: b) -> Maybe (a :~: b)
forall a. a -> Maybe a
Just ((a :~: b) -> Maybe (a :~: b)) -> (a :~: b) -> Maybe (a :~: b)
forall a b. (a -> b) -> a -> b
$ (Any :~: Any) -> a :~: b
forall a b. a -> b
unsafeCoerce Any :~: Any
forall k (a :: k). a :~: a
Refl else Maybe (a :~: b)
forall a. Maybe a
Nothing

instance GEq (STRef s) where
  a :: STRef s a
a geq :: STRef s a -> STRef s b -> Maybe (a :~: b)
`geq` b :: STRef s b
b = if STRef s a
a STRef s a -> STRef s a -> Bool
forall a. Eq a => a -> a -> Bool
== STRef s b -> STRef s a
forall a b. a -> b
unsafeCoerce STRef s b
b then (a :~: b) -> Maybe (a :~: b)
forall a. a -> Maybe a
Just ((a :~: b) -> Maybe (a :~: b)) -> (a :~: b) -> Maybe (a :~: b)
forall a b. (a -> b) -> a -> b
$ (Any :~: Any) -> a :~: b
forall a b. a -> b
unsafeCoerce Any :~: Any
forall k (a :: k). a :~: a
Refl else Maybe (a :~: b)
forall a. Maybe a
Nothing