packages feed

dep-t-value-0.1.0.0: lib/Dep/Value/Cached.hs

{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ViewPatterns #-}
-- | Cache 'Value's to avoid repeated calls to the underlying value-obtaining action, which migh be expensive.
--
-- Typically, this module only needs to be imported when creating the global application environment.
module Dep.Value.Cached
  ( 
    -- * caching 'Value's
    Ref,
    allocateRef,
    cache,
  )
where

import Control.Concurrent.MVar
import Control.Exception
import Control.Monad.IO.Class
import Control.Monad.IO.Unlift
import Control.Monad.Trans.Cont
import Dep.Has
import Dep.Value
import Data.ByteString
import Data.Typeable
import Data.Proxy

type Ref v = MVar (Maybe v)

allocateRef :: MonadIO m => ContT () m (Ref v)
allocateRef = ContT \f -> do
  ref <- liftIO $ newMVar Nothing
  f ref

cache :: MonadUnliftIO m => Ref v -> Value v m -> Value v m
cache ref Value {value} = Value do
  run <- askRunInIO
  liftIO $ modifyMVar ref \case
    Just v -> do
      pure (Just v, v)
    Nothing -> do
      v <- run value
      pure (Just v, v)