module Data.Pool
(
Pool (..)
, PoolConfig (..)
, defaultPoolConfig
, newPool
, withResource
)
where
import Control.Concurrent.QSem (QSem, newQSem, signalQSem, waitQSem)
import Control.Exception (bracket)
import Control.Monad.IO.Class (MonadIO (liftIO))
import Control.Monad.IO.Unlift (MonadUnliftIO (withRunInIO))
data Pool a = UnsafeMkPool
{ forall a. Pool a -> PoolConfig a
poolConfig :: !(PoolConfig a)
, forall a. Pool a -> QSem
poolSem :: QSem
}
data PoolConfig a = MkPoolConfig
{ forall a. PoolConfig a -> IO a
createResource :: IO a
, forall a. PoolConfig a -> a -> IO ()
destroyResource :: a -> IO ()
, forall a. PoolConfig a -> Int
maxResources :: !Int
}
defaultPoolConfig
:: IO a
-> (a -> IO ())
-> Int
-> PoolConfig a
defaultPoolConfig :: forall a. IO a -> (a -> IO ()) -> Int -> PoolConfig a
defaultPoolConfig = IO a -> (a -> IO ()) -> Int -> PoolConfig a
forall a. IO a -> (a -> IO ()) -> Int -> PoolConfig a
MkPoolConfig
newPool :: MonadIO m => PoolConfig a -> m (Pool a)
newPool :: forall (m :: * -> *) a. MonadIO m => PoolConfig a -> m (Pool a)
newPool PoolConfig a
cfg = do
QSem
sem <- IO QSem -> m QSem
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO QSem -> m QSem) -> IO QSem -> m QSem
forall a b. (a -> b) -> a -> b
$ Int -> IO QSem
newQSem (PoolConfig a -> Int
forall a. PoolConfig a -> Int
maxResources PoolConfig a
cfg)
Pool a -> m (Pool a)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PoolConfig a -> QSem -> Pool a
forall a. PoolConfig a -> QSem -> Pool a
UnsafeMkPool PoolConfig a
cfg QSem
sem)
withResource :: MonadUnliftIO m => Pool a -> (a -> m r) -> m r
withResource :: forall (m :: * -> *) a r.
MonadUnliftIO m =>
Pool a -> (a -> m r) -> m r
withResource Pool a
pool a -> m r
k = ((forall a. m a -> IO a) -> IO r) -> m r
forall b. ((forall a. m a -> IO a) -> IO b) -> m b
forall (m :: * -> *) b.
MonadUnliftIO m =>
((forall a. m a -> IO a) -> IO b) -> m b
withRunInIO (((forall a. m a -> IO a) -> IO r) -> m r)
-> ((forall a. m a -> IO a) -> IO r) -> m r
forall a b. (a -> b) -> a -> b
$ \forall a. m a -> IO a
inIO ->
IO a -> (a -> IO ()) -> (a -> IO r) -> IO r
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket
( do
QSem -> IO ()
waitQSem (QSem -> IO ()) -> QSem -> IO ()
forall a b. (a -> b) -> a -> b
$ Pool a -> QSem
forall a. Pool a -> QSem
poolSem Pool a
pool
PoolConfig a -> IO a
forall a. PoolConfig a -> IO a
createResource (PoolConfig a -> IO a) -> PoolConfig a -> IO a
forall a b. (a -> b) -> a -> b
$ Pool a -> PoolConfig a
forall a. Pool a -> PoolConfig a
poolConfig Pool a
pool
)
( \a
res -> do
PoolConfig a -> a -> IO ()
forall a. PoolConfig a -> a -> IO ()
destroyResource (Pool a -> PoolConfig a
forall a. Pool a -> PoolConfig a
poolConfig Pool a
pool) a
res
QSem -> IO ()
signalQSem (QSem -> IO ()) -> QSem -> IO ()
forall a b. (a -> b) -> a -> b
$ Pool a -> QSem
forall a. Pool a -> QSem
poolSem Pool a
pool
)
(m r -> IO r
forall a. m a -> IO a
inIO (m r -> IO r) -> (a -> m r) -> a -> IO r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> m r
k)