module Network.CGI.Monad (
MonadCGI(..),
CGIT(..), CGI,
runCGIT,
CGIRequest(..),
throwCGI, catchCGI, tryCGI, handleExceptionCGI,
) where
import Prelude hiding (catch)
import Control.Exception.Extensible as Exception (SomeException, throwIO)
import Control.Monad (liftM)
import Control.Monad.CatchIO (MonadCatchIO, block, catch, try, unblock)
import Control.Monad.Error (MonadError(..))
import Control.Monad.Reader (ReaderT(..), asks)
import Control.Monad.Writer (WriterT(..), tell)
import Control.Monad.Trans (MonadTrans, MonadIO, liftIO, lift)
import Data.Typeable (Typeable(..), Typeable1(..),
mkTyConApp, mkTyCon)
import Network.CGI.Protocol
type CGI a = CGIT IO a
newtype CGIT m a = CGIT { unCGIT :: ReaderT CGIRequest (WriterT Headers m) a }
instance (Typeable1 m, Typeable a) => Typeable (CGIT m a) where
typeOf _ = mkTyConApp (mkTyCon "Network.CGI.Monad.CGIT")
[typeOf1 (undefined :: m a), typeOf (undefined :: a)]
instance (Functor m, Monad m) => Functor (CGIT m) where
fmap f c = CGIT (fmap f (unCGIT c))
instance Monad m => Monad (CGIT m) where
c >>= f = CGIT (unCGIT c >>= unCGIT . f)
return = CGIT . return
fail = CGIT . fail
instance MonadIO m => MonadIO (CGIT m) where
liftIO = lift . liftIO
instance MonadCatchIO m => MonadCatchIO (CGIT m) where
CGIT m `catch` h = CGIT $ m `catch` (unCGIT . h)
block (CGIT m) = CGIT (block m)
unblock (CGIT m) = CGIT (unblock m)
class Monad m => MonadCGI m where
cgiAddHeader :: HeaderName -> String -> m ()
cgiGet :: (CGIRequest -> a) -> m a
instance Monad m => MonadCGI (CGIT m) where
cgiAddHeader n v = CGIT $ lift $ tell [(n,v)]
cgiGet = CGIT . asks
instance MonadTrans CGIT where
lift = CGIT . lift . lift
runCGIT :: Monad m => CGIT m a -> CGIRequest -> m (Headers, a)
runCGIT (CGIT c) = liftM (uncurry (flip (,))) . runWriterT . runReaderT c
instance MonadCatchIO m => MonadError SomeException (CGIT m) where
throwError = throwCGI
catchError = catchCGI
throwCGI :: (MonadCGI m, MonadIO m) => SomeException -> m a
throwCGI = liftIO . throwIO
catchCGI :: (MonadCGI m, MonadCatchIO m) => m a -> (SomeException -> m a) -> m a
catchCGI = catch
tryCGI :: (MonadCGI m, MonadCatchIO m) => m a -> m (Either SomeException a)
tryCGI = try
handleExceptionCGI :: (MonadCGI m, MonadCatchIO m) => m a -> (SomeException -> m a) -> m a
handleExceptionCGI = catchCGI