libarchive-3.0.0.0: src/Codec/Archive/Monad.hs
module Codec.Archive.Monad ( handle
, ignore
, lenient
, touchForeignPtrM
, runArchiveM
, throwArchiveM
-- * Bracketed resources within 'ArchiveM'
, withCStringArchiveM
, useAsCStringLenArchiveM
, allocaBytesArchiveM
, bracketM
, ArchiveM
) where
import Codec.Archive.Types
import Control.Exception (bracket, throw)
import Control.Monad (void)
import Control.Monad.Except (ExceptT, runExceptT, throwError)
import Control.Monad.IO.Class
import qualified Data.ByteString as BS
import qualified Data.ByteString.Unsafe as BS
import Foreign.C.String
import Foreign.ForeignPtr (ForeignPtr, touchForeignPtr)
import Foreign.Marshal.Alloc (allocaBytes)
import Foreign.Ptr (Ptr)
type ArchiveM = ExceptT ArchiveResult IO
touchForeignPtrM :: ForeignPtr a -> ArchiveM ()
touchForeignPtrM = liftIO . touchForeignPtr
-- for things we don't think is going to fail
ignore :: IO ArchiveResult -> ArchiveM ()
ignore = void . liftIO
-- | Throws 'ArchiveResult' on error.
--
-- @since 2.2.5.0
throwArchiveM :: ArchiveM a -> IO a
throwArchiveM = fmap (either throw id) . runArchiveM
runArchiveM :: ArchiveM a -> IO (Either ArchiveResult a)
runArchiveM = runExceptT
-- TODO: ArchiveFailed Writer monad?
-- archive_clear_error
lenient :: IO ArchiveResult -> ArchiveM ()
lenient act = do
res <- liftIO act
case res of
ArchiveFatal -> throw res
ArchiveEOF -> throw res
_ -> pure ()
handle :: IO ArchiveResult -> ArchiveM ()
handle act = do
res <- liftIO act
case res of
ArchiveOk -> pure ()
ArchiveRetry -> pure ()
-- FIXME: ArchiveFailed may be ok
x -> throwError x
flipExceptIO :: IO (Either a b) -> ExceptT a IO b
flipExceptIO act = do
res <- liftIO act
case res of
Right x -> pure x
Left y -> throwError y
genBracket :: (a -> (b -> IO (Either c d)) -> IO (Either c d)) -- ^ Function like 'withCString' we are trying to lift
-> a -- ^ Fed to @b@
-> (b -> ExceptT c IO d) -- ^ The action
-> ExceptT c IO d
genBracket f x = flipExceptIO . f x . (runExceptT .)
allocaBytesArchiveM :: Int -> (Ptr a -> ExceptT b IO c) -> ExceptT b IO c
allocaBytesArchiveM = genBracket allocaBytes
withCStringArchiveM :: String -> (CString -> ExceptT a IO b) -> ExceptT a IO b
withCStringArchiveM = genBracket withCString
useAsCStringLenArchiveM :: BS.ByteString -> (CStringLen -> ExceptT a IO b) -> ExceptT a IO b
useAsCStringLenArchiveM = genBracket BS.unsafeUseAsCStringLen
bracketM :: IO a -- ^ Allocate/aquire a resource
-> (a -> IO b) -- ^ Free/release a resource (assumed not to fail)
-> (a -> ArchiveM c)
-> ArchiveM c
bracketM get free act =
flipExceptIO $
bracket get free (runArchiveM.act)