module Freckle.App.GlobalCache
( GlobalCache
, newGlobalCache
, globallyCache
, withGlobalCacheCleanup
) where
import Freckle.App.Prelude
import Control.Concurrent.MVar (mkWeakMVar, modifyMVar_, newMVar)
import Data.IORef
newtype GlobalCache a = GlobalCache
{ GlobalCache a -> IORef (Maybe a)
_unGlobalCache :: IORef (Maybe a)
}
newGlobalCache :: IO (GlobalCache a)
newGlobalCache :: IO (GlobalCache a)
newGlobalCache = IORef (Maybe a) -> GlobalCache a
forall a. IORef (Maybe a) -> GlobalCache a
GlobalCache (IORef (Maybe a) -> GlobalCache a)
-> IO (IORef (Maybe a)) -> IO (GlobalCache a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe a -> IO (IORef (Maybe a))
forall a. a -> IO (IORef a)
newIORef Maybe a
forall a. Maybe a
Nothing
globallyCache :: GlobalCache a -> IO a -> IO a
globallyCache :: GlobalCache a -> IO a -> IO a
globallyCache (GlobalCache IORef (Maybe a)
var) IO a
construct = do
Maybe a
mv <- IORef (Maybe a) -> IO (Maybe a)
forall a. IORef a -> IO a
readIORef IORef (Maybe a)
var
IO a -> (a -> IO a) -> Maybe a -> IO a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (a -> IO a
cache (a -> IO a) -> IO a -> IO a
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO a
construct) a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
mv
where cache :: a -> IO a
cache a
v = IORef (Maybe a) -> (Maybe a -> (Maybe a, a)) -> IO a
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef (Maybe a)
var ((Maybe a -> (Maybe a, a)) -> IO a)
-> (Maybe a -> (Maybe a, a)) -> IO a
forall a b. (a -> b) -> a -> b
$ (Maybe a, a) -> Maybe a -> (Maybe a, a)
forall a b. a -> b -> a
const (a -> Maybe a
forall a. a -> Maybe a
Just a
v, a
v)
withGlobalCacheCleanup :: GlobalCache a -> IO b -> IO ()
withGlobalCacheCleanup :: GlobalCache a -> IO b -> IO ()
withGlobalCacheCleanup (GlobalCache IORef (Maybe a)
var) IO b
action = do
MVar ()
cleanup <- () -> IO (MVar ())
forall a. a -> IO (MVar a)
newMVar ()
IO (Weak (MVar ())) -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO (Weak (MVar ())) -> IO ()) -> IO (Weak (MVar ())) -> IO ()
forall a b. (a -> b) -> a -> b
$ MVar () -> IO () -> IO (Weak (MVar ()))
forall a. MVar a -> IO () -> IO (Weak (MVar a))
mkWeakMVar MVar ()
cleanup (IO () -> IO (Weak (MVar ()))) -> IO () -> IO (Weak (MVar ()))
forall a b. (a -> b) -> a -> b
$ IORef (Maybe a) -> Maybe a -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Maybe a)
var Maybe a
forall a. Maybe a
Nothing
IO b -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void IO b
action
MVar () -> (() -> IO ()) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ MVar ()
cleanup (IO () -> () -> IO ()
forall a b. a -> b -> a
const (IO () -> () -> IO ()) -> IO () -> () -> IO ()
forall a b. (a -> b) -> a -> b
$ () -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ())