Skip to content

Commit 72a2a2f

Browse files
committed
Add MonadCatch and MonadMask instances to RouteResultT and DelayedIO
Fix #1829
1 parent 2cb8d77 commit 72a2a2f

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

servant-server/src/Servant/Server/Internal/DelayedIO.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
module Servant.Server.Internal.DelayedIO where
66

77
import Control.Monad.Base (MonadBase (..))
8-
import Control.Monad.Catch (MonadThrow (..))
8+
import Control.Monad.Catch (MonadThrow (..), MonadCatch(..), MonadMask)
99
import Control.Monad.Reader (MonadReader (..), ReaderT (..), runReaderT)
1010
import Control.Monad.Trans (MonadIO (..), MonadTrans (..))
1111
import Control.Monad.Trans.Control (MonadBaseControl (..))
@@ -34,6 +34,8 @@ newtype DelayedIO a = DelayedIO {runDelayedIO' :: ReaderT Request (ResourceT (Ro
3434
, MonadReader Request
3535
, MonadResource
3636
, MonadThrow
37+
, MonadCatch
38+
, MonadMask
3739
)
3840

3941
instance MonadBase IO DelayedIO where
@@ -53,6 +55,7 @@ instance MonadBaseControl IO DelayedIO where
5355
runInBase (runInternalState (runReaderT (runDelayedIO' x) req) s)
5456
restoreM = DelayedIO . lift . withInternalState . const . restoreM
5557

58+
5659
runDelayedIO :: DelayedIO a -> Request -> ResourceT IO (RouteResult a)
5760
runDelayedIO m req = transResourceT runRouteResultT $ runReaderT (runDelayedIO' m) req
5861

servant-server/src/Servant/Server/Internal/RouteResult.hs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module Servant.Server.Internal.RouteResult where
88

99
import Control.Monad (ap)
1010
import Control.Monad.Base (MonadBase (..))
11-
import Control.Monad.Catch (MonadThrow (..))
11+
import Control.Monad.Catch (ExitCase (..), MonadCatch (..), MonadMask (..), MonadThrow (..))
1212
import Control.Monad.Trans (MonadIO (..), MonadTrans (..))
1313
import Control.Monad.Trans.Control
1414
( ComposeSt
@@ -75,3 +75,43 @@ instance MonadTransControl RouteResultT where
7575

7676
instance MonadThrow m => MonadThrow (RouteResultT m) where
7777
throwM = lift . throwM
78+
79+
instance MonadCatch m => MonadCatch (RouteResultT m) where
80+
catch (RouteResultT m) f = RouteResultT $ catch m (runRouteResultT . f)
81+
82+
instance MonadMask m => MonadMask (RouteResultT m) where
83+
mask f = RouteResultT $ mask $ \u -> runRouteResultT $ f (q u)
84+
where
85+
q
86+
:: (m (RouteResult a) -> m (RouteResult a))
87+
-> RouteResultT m a
88+
-> RouteResultT m a
89+
q u (RouteResultT b) = RouteResultT (u b)
90+
uninterruptibleMask f = RouteResultT $ uninterruptibleMask $ \u -> runRouteResultT $ f (q u)
91+
where
92+
q
93+
:: (m (RouteResult a) -> m (RouteResult a))
94+
-> RouteResultT m a
95+
-> RouteResultT m a
96+
q u (RouteResultT b) = RouteResultT (u b)
97+
98+
generalBracket acquire release use = RouteResultT $ do
99+
(eb, ec) <-
100+
generalBracket
101+
(runRouteResultT acquire)
102+
( \resourceRoute exitCase -> case resourceRoute of
103+
Fail e -> pure $ Fail e -- nothing to release, acquire didn't succeed
104+
FailFatal e -> pure $ FailFatal e
105+
Route resource -> case exitCase of
106+
ExitCaseSuccess (Route b) -> runRouteResultT (release resource (ExitCaseSuccess b))
107+
ExitCaseException e -> runRouteResultT (release resource (ExitCaseException e))
108+
_ -> runRouteResultT (release resource ExitCaseAbort)
109+
)
110+
( \case
111+
Fail e -> pure $ Fail e -- nothing to release, acquire didn't succeed
112+
FailFatal e -> pure $ FailFatal e
113+
Route resource -> runRouteResultT (use resource)
114+
)
115+
-- The order in which we perform those two effects doesn't matter,
116+
-- since the error message is the same regardless.
117+
pure ((,) <$> eb <*> ec)

0 commit comments

Comments
 (0)