packages feed

imm-0.5.0.0: Imm/Util.hs

module Imm.Util where

-- {{{ Imports
import Imm.Error

import qualified Control.Exception as E
import Control.Monad.Base
import Control.Monad.Error

import qualified Data.ByteString.Lazy as BL
import Data.Functor
import Data.Maybe
import Data.Text.Lazy.Encoding hiding(decodeUtf8)
import qualified Data.Text.Lazy as TL
import Data.Time as T
import Data.Time.RFC2822
import Data.Time.RFC3339

import Network.URI as N

import System.FilePath
import System.Locale
import System.Timeout as S
-- }}}


-- | Like '</>' with first argument in IO to build platform-dependent paths.
(>/>) :: (MonadBase IO m) => IO FilePath -> FilePath -> m FilePath
(>/>) a b = io $ (</> b) <$> a

-- {{{ Monadic utilities
-- | Shortcut to 'liftBase' with 'IO' as base monad
io :: MonadBase IO m => IO a -> m a
io = liftBase

-- | Monad-agnostic version of 'Control.Exception.try'
try :: (MonadBase IO m, MonadError ImmError m) => IO a -> m a
try = (io . E.try) >=> either (throwError . IOE) return

-- | Monad-agnostic version of 'System.timeout'
timeout :: (MonadBase IO m, MonadError ImmError m) => Int -> IO a -> m a
timeout n f = maybe (throwError TimeOut) (io . return) =<< (io $ S.timeout n (io f))
-- }}}

-- {{{ Monad-agnostic version of various error-prone functions
-- | Monad-agnostic version of Data.Text.Encoding.decodeUtf8
decodeUtf8 :: MonadError ImmError m => BL.ByteString -> m TL.Text
decodeUtf8 = either (throwError . UnicodeError) return . decodeUtf8'

-- | Monad-agnostic version of 'Network.URI.parseURI'
parseURI :: (MonadError ImmError m) => String -> m URI
parseURI uri = maybe (throwError $ ParseUriError uri) return $ N.parseURI uri

-- | Monad-agnostic version of 'Data.Time.Format.parseTime'
parseTime :: (MonadError ImmError m) => String -> m UTCTime
parseTime string = maybe (throwError $ ParseTimeError string) return $ T.parseTime defaultTimeLocale "%c" string
-- }}}