{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Data.Propagator.Naive
( Prop
, newProp
, newConstProp
, freezeProp
, readProp
, watchProp
, setProp
, lift1
, lift2
, liftList
)
where
import Control.Monad
import Data.POrder
import Data.Maybe
import qualified Data.Propagator.Class as Class
#ifdef DEJAFU
#define Ctxt MonadConc m =>
#define Prop_ Prop m
#define IORef_ IORef m
#define MVar_ MVar m
#define M m
import Control.Concurrent.Classy
#else
#define Ctxt
#define Prop_ Prop
#define IORef_ IORef
#define MVar_ MVar
#define M IO
import Control.Exception
import Control.Concurrent.MVar
import Data.IORef
#endif
data Prop_ a = Prop
{ forall a. Prop a -> IORef a
_val :: IORef_ a
, forall a. Prop a -> MVar ()
_lock :: MVar_ ()
, forall a. Prop a -> IORef (Maybe (IO ()))
_onChange :: IORef_ (Maybe (M ()))
}
newProp :: Ctxt a -> M (Prop_ a)
newProp :: forall a. a -> IO (Prop a)
newProp a
x = do
IORef a
m <- forall a. a -> IO (IORef a)
newIORef a
x
MVar ()
l <- forall a. a -> IO (MVar a)
newMVar ()
IORef (Maybe (IO ()))
notify <- forall a. a -> IO (IORef a)
newIORef (forall a. a -> Maybe a
Just (forall (f :: * -> *) a. Applicative f => a -> f a
pure ()))
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a. IORef a -> MVar () -> IORef (Maybe (IO ())) -> Prop a
Prop IORef a
m MVar ()
l IORef (Maybe (IO ()))
notify
newConstProp :: Ctxt a -> M (Prop_ a)
newConstProp :: forall a. a -> IO (Prop a)
newConstProp a
x = do
IORef a
m <- forall a. a -> IO (IORef a)
newIORef a
x
MVar ()
l <- forall a. a -> IO (MVar a)
newMVar ()
IORef (Maybe (IO ()))
notify <- forall a. a -> IO (IORef a)
newIORef forall a. Maybe a
Nothing
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a. IORef a -> MVar () -> IORef (Maybe (IO ())) -> Prop a
Prop IORef a
m MVar ()
l IORef (Maybe (IO ()))
notify
readProp :: Ctxt Prop_ a -> M a
readProp :: forall a. Prop a -> IO a
readProp (Prop IORef a
m MVar ()
_ IORef (Maybe (IO ()))
_ ) = forall a. IORef a -> IO a
readIORef IORef a
m
isFrozen :: Ctxt Prop_ a -> M Bool
isFrozen :: forall a. Prop a -> IO Bool
isFrozen (Prop IORef a
_ MVar ()
_ IORef (Maybe (IO ()))
notify) = do
forall a. Maybe a -> Bool
isNothing forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. IORef a -> IO a
readIORef IORef (Maybe (IO ()))
notify
freezeProp :: Ctxt Prop_ a -> M ()
freezeProp :: forall a. Prop a -> IO ()
freezeProp (Prop IORef a
_ MVar ()
_ IORef (Maybe (IO ()))
notify) = do
forall a. IORef a -> a -> IO ()
writeIORef IORef (Maybe (IO ()))
notify forall a. Maybe a
Nothing
setProp :: Ctxt POrder a => Prop_ a -> M a -> M ()
setProp :: forall a. POrder a => Prop a -> IO a -> IO ()
setProp p :: Prop a
p@(Prop IORef a
m MVar ()
l IORef (Maybe (IO ()))
notify) IO a
getX = do
Bool
frozen <- forall a. Prop a -> IO Bool
isFrozen Prop a
p
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
frozen forall a b. (a -> b) -> a -> b
$ forall a e. Exception e => e -> a
throw WriteToFrozenPropagatorException
Class.WriteToFrozenPropagatorException
() <- forall a. MVar a -> IO a
takeMVar MVar ()
l
a
old <- forall a. IORef a -> IO a
readIORef IORef a
m
a
new <- IO a
getX
forall a. IORef a -> a -> IO ()
writeIORef IORef a
m a
new
forall a. MVar a -> a -> IO ()
putMVar MVar ()
l ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (a
old forall a. POrder a => a -> a -> Bool
`eqOfLe` a
new) forall a b. (a -> b) -> a -> b
$
forall a. IORef a -> IO a
readIORef IORef (Maybe (IO ()))
notify forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Maybe (IO ())
Nothing -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Just IO ()
act -> IO ()
act
watchProp :: Ctxt Prop_ a -> M () -> M ()
watchProp :: forall a. Prop a -> IO () -> IO ()
watchProp (Prop IORef a
_ MVar ()
_ IORef (Maybe (IO ()))
notify) IO ()
f =
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef IORef (Maybe (IO ()))
notify forall a b. (a -> b) -> a -> b
$ \case
Maybe (IO ())
Nothing -> (forall a. Maybe a
Nothing, ())
Just IO ()
a -> (forall a. a -> Maybe a
Just (IO ()
f forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO ()
a), ())
lift1 :: Ctxt POrder b => (a -> b) -> Prop_ a -> Prop_ b -> M ()
lift1 :: forall b a. POrder b => (a -> b) -> Prop a -> Prop b -> IO ()
lift1 a -> b
f Prop a
p1 Prop b
p = do
let update :: IO ()
update = forall a. POrder a => Prop a -> IO a -> IO ()
setProp Prop b
p forall a b. (a -> b) -> a -> b
$ a -> b
f forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Prop a -> IO a
readProp Prop a
p1
forall a. Prop a -> IO () -> IO ()
watchProp Prop a
p1 IO ()
update
IO ()
update
lift2 :: Ctxt POrder c => (a -> b -> c) -> Prop_ a -> Prop_ b -> Prop_ c -> M ()
lift2 :: forall c a b.
POrder c =>
(a -> b -> c) -> Prop a -> Prop b -> Prop c -> IO ()
lift2 a -> b -> c
f Prop a
p1 Prop b
p2 Prop c
p = do
let update :: IO ()
update = forall a. POrder a => Prop a -> IO a -> IO ()
setProp Prop c
p forall a b. (a -> b) -> a -> b
$ a -> b -> c
f forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Prop a -> IO a
readProp Prop a
p1 forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall a. Prop a -> IO a
readProp Prop b
p2
forall a. Prop a -> IO () -> IO ()
watchProp Prop a
p1 IO ()
update
forall a. Prop a -> IO () -> IO ()
watchProp Prop b
p2 IO ()
update
IO ()
update
liftList :: Ctxt POrder b => ([a] -> b) -> [Prop_ a] -> Prop_ b -> M ()
liftList :: forall b a. POrder b => ([a] -> b) -> [Prop a] -> Prop b -> IO ()
liftList [a] -> b
f [Prop a]
ps Prop b
p = do
let update :: IO ()
update = forall a. POrder a => Prop a -> IO a -> IO ()
setProp Prop b
p forall a b. (a -> b) -> a -> b
$ [a] -> b
f forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM forall a. Prop a -> IO a
readProp [Prop a]
ps
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\Prop a
p' -> forall a. Prop a -> IO () -> IO ()
watchProp Prop a
p' IO ()
update) [Prop a]
ps
IO ()
update
#ifndef DEJAFU
instance Bottom a => Class.Propagator (Prop_ a) a where
newProp :: IO (Prop a)
newProp = forall a. a -> IO (Prop a)
newProp forall a. Bottom a => a
bottom
newConstProp :: a -> IO (Prop a)
newConstProp = forall a. a -> IO (Prop a)
newConstProp
freezeProp :: Prop a -> IO ()
freezeProp = forall a. Prop a -> IO ()
freezeProp
readProp :: Prop a -> IO a
readProp = forall a. Prop a -> IO a
readProp
#endif