context-resource-0.2.0.0: library/Context/Resource.hs
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RankNTypes #-}
module Context.Resource
( -- * Introduction
-- $intro
-- * Provider
Provider
, withProvider
-- * Core operations
, withResource
, shareResource
-- * Convenience
, withSharedResource
) where
import Control.Monad.Catch (MonadMask, MonadThrow)
import Control.Monad.IO.Class (MonadIO)
import Prelude
import qualified Context
-- | An opaque resource provider.
--
-- @since 0.1.0.0
newtype Provider m res = Provider
{ store :: Context.Store (WithRes m res)
}
newtype WithRes m res = WithRes (forall r. (res -> m r) -> m r)
-- | Given a @with@-style function to acquire a resource, supplies the caller
-- with a resource 'Provider'. This 'Provider' should ideally be long-lived and
-- threaded throughout the application to the components that need to acquire
-- resources.
--
-- @since 0.1.0.0
withProvider
:: forall m res a
. (MonadIO m, MonadMask m)
=> (forall r. (res -> m r) -> m r)
-> (Provider m res -> m a)
-> m a
withProvider withRes f = do
Context.withStore Context.noPropagation (Just (WithRes withRes)) \store -> do
f Provider { store }
-- | Acquire a resource from the specified 'Provider', for the duration of the
-- specified action.
--
-- @since 0.1.0.0
withResource
:: forall m res a
. (MonadIO m, MonadThrow m)
=> Provider m res
-> (res -> m a)
-> m a
withResource Provider { store } f = do
WithRes withRes <- Context.mine store
withRes f
-- | Tell the specified 'Provider' to share the specified resource for the
-- duration of the specified action. All calls to 'withResource' (or
-- 'withSharedResource') within the action will return the shared resource.
--
-- @since 0.1.0.0
shareResource
:: forall m res a
. (MonadIO m, MonadMask m)
=> Provider m res
-> res
-> m a
-> m a
shareResource Provider { store } resource action = do
Context.use store (WithRes ($ resource)) action
-- | Acquire a resource from the specified 'Provider' and share that resource
-- for the duration of the specified action. All calls to 'withResource' (or
-- 'withSharedResource') within the action will return the shared resource.
--
-- This is a convenience function combining 'withResource' and 'shareResource'.
--
-- @since 0.1.0.0
withSharedResource
:: forall m res a
. (MonadIO m, MonadMask m)
=> Provider m res
-> (res -> m a)
-> m a
withSharedResource provider f = do
withResource provider \resource -> do
shareResource provider resource do
f resource
-- $intro
--
-- This module provides a thread-safe, pool-compatible resource provider
-- abstraction that supports resource-sharing within nested actions. While it
-- was designed with resource pools in mind, the interface supports any
-- @with@-style means of acquiring a resource.
--
-- 'withResource' can be used to acquire a resource from the provider, and
-- 'shareResource' can be used to share a particular resource for the duration
-- of an action. Subsequent calls to 'shareResource' in that action are
-- idempotent. Note that if a resource-shared action spins up new threads, the
-- shared resource will /not/ be shared implicitly across thread boundaries.
--
-- While 'shareResource' offers the most control over resource-sharing,
-- 'withSharedResource' can be used as a convenience in the relatively common
-- case where a resource is acquired and then immediately shared within an
-- inner action.