{-# LANGUAGE MultiWayIf #-}
module Codec.Compression.Zstd.Streaming
(
Result(..)
, compress
, decompress
, maxCLevel
) where
import Codec.Compression.Zstd.FFI hiding (compress, decompress)
import Codec.Compression.Zstd.FFI.Types (peekPos)
import qualified Data.ByteString as B
import Data.ByteString.Internal (ByteString(..), mallocByteString)
import Foreign.Marshal.Alloc (finalizerFree, malloc)
import Foreign.C.Types (CSize)
import Foreign.ForeignPtr
import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
import Foreign.Storable (poke)
import Foreign.Ptr (Ptr, plusPtr)
import Data.Word (Word8)
data Result
= Produce ByteString (IO Result)
| Consume (ByteString -> IO Result)
| Error String String
| Done ByteString
instance Show Result where
show :: Result -> String
show (Produce ByteString
bs IO Result
_) = String
"Produce " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ByteString -> String
forall a. Show a => a -> String
show ByteString
bs String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" _"
show (Consume ByteString -> IO Result
_) = String
"Consume _"
show (Error String
n String
d) = String
"Error " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ShowS
forall a. Show a => a -> String
show String
n String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ShowS
forall a. Show a => a -> String
show String
d
show (Done ByteString
bs) = String
"Done " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ByteString -> String
forall a. Show a => a -> String
show ByteString
bs
compress :: Int
-> IO Result
compress :: Int -> IO Result
compress Int
level
| Int
level Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
1 Bool -> Bool -> Bool
|| Int
level Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
maxCLevel =
Result -> IO Result
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> String -> Result
Error String
"compress" String
"unsupported compression level")
| Bool
otherwise =
IO (Ptr CStream)
-> FinalizerPtr CStream
-> Int
-> (Ptr CStream -> IO CSize)
-> ConsumeBlock CStream Any
-> Finish CStream Any
-> IO Result
forall ctx io.
IO (Ptr ctx)
-> FinalizerPtr ctx
-> Int
-> (Ptr ctx -> IO CSize)
-> ConsumeBlock ctx io
-> Finish ctx io
-> IO Result
streaming
IO (Ptr CStream)
createCStream
FinalizerPtr CStream
p_freeCStream
Int
outSize
(\Ptr CStream
cs -> Ptr CStream -> CInt -> IO CSize
initCStream Ptr CStream
cs (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
level))
ConsumeBlock CStream Any
compressStream
Finish CStream Any
forall t.
Num t =>
ForeignPtr CStream
-> ForeignPtr (Buffer Out) -> t -> ForeignPtr Word8 -> IO Result
finish
where
outSize :: Int
outSize = CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cstreamOutSize
finish :: ForeignPtr CStream
-> ForeignPtr (Buffer Out) -> t -> ForeignPtr Word8 -> IO Result
finish ForeignPtr CStream
cfp ForeignPtr (Buffer Out)
obfp t
opos ForeignPtr Word8
dfp = do
let cptr :: Ptr CStream
cptr = ForeignPtr CStream -> Ptr CStream
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtr ForeignPtr CStream
cfp
obuf :: Ptr (Buffer Out)
obuf = ForeignPtr (Buffer Out) -> Ptr (Buffer Out)
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtr ForeignPtr (Buffer Out)
obfp
String -> IO CSize -> (CSize -> IO Result) -> IO Result
check String
"endStream" (Ptr CStream -> Ptr (Buffer Out) -> IO CSize
endStream Ptr CStream
cptr Ptr (Buffer Out)
obuf) ((CSize -> IO Result) -> IO Result)
-> (CSize -> IO Result) -> IO Result
forall a b. (a -> b) -> a -> b
$ \CSize
leftover -> do
ForeignPtr CStream -> IO ()
forall a. ForeignPtr a -> IO ()
touchForeignPtr ForeignPtr CStream
cfp
ForeignPtr (Buffer Out) -> IO ()
forall a. ForeignPtr a -> IO ()
touchForeignPtr ForeignPtr (Buffer Out)
obfp
if | CSize
leftover CSize -> CSize -> Bool
forall a. Ord a => a -> a -> Bool
<= CSize
0 -> do
Int
opos1 <- CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CSize -> Int) -> IO CSize -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Ptr (Buffer Out) -> IO CSize
forall io. Ptr (Buffer io) -> IO CSize
peekPos Ptr (Buffer Out)
obuf
ByteString -> Result
Done (ByteString -> Result) -> IO ByteString -> IO Result
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Int -> ForeignPtr Word8 -> Int -> IO ByteString
shrink Int
outSize ForeignPtr Word8
dfp Int
opos1
| CSize
leftover CSize -> CSize -> Bool
forall a. Ord a => a -> a -> Bool
> CSize
0 -> do
Int
opos1 <- CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CSize -> Int) -> IO CSize -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Ptr (Buffer Out) -> IO CSize
forall io. Ptr (Buffer io) -> IO CSize
peekPos Ptr (Buffer Out)
obuf
ForeignPtr Word8
dfp1 <- Int -> IO (ForeignPtr Word8)
forall a. Int -> IO (ForeignPtr a)
mallocByteString (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
leftover)
Ptr (Buffer Out) -> Buffer Out -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr (Buffer Out)
obuf (Ptr Word8 -> CSize -> Buffer Out
forall a io. Ptr a -> CSize -> Buffer io
buffer (ForeignPtr Word8 -> Ptr Word8
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtr ForeignPtr Word8
dfp1) CSize
leftover)
ForeignPtr (Buffer Out) -> IO ()
forall a. ForeignPtr a -> IO ()
touchForeignPtr ForeignPtr (Buffer Out)
obfp
ByteString
bs <- Int -> ForeignPtr Word8 -> Int -> IO ByteString
shrink Int
outSize ForeignPtr Word8
dfp Int
opos1
Result -> IO Result
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString -> IO Result -> Result
Produce ByteString
bs (ForeignPtr CStream
-> ForeignPtr (Buffer Out) -> t -> ForeignPtr Word8 -> IO Result
finish ForeignPtr CStream
cfp ForeignPtr (Buffer Out)
obfp t
0 ForeignPtr Word8
dfp1))
type ConsumeBlock ctx io = Ptr ctx -> Ptr (Buffer Out)
-> Ptr (Buffer In) -> IO CSize
type Finish ctx io = ForeignPtr ctx -> ForeignPtr (Buffer Out)
-> Int -> ForeignPtr Word8 -> IO Result
streaming :: IO (Ptr ctx)
-> FinalizerPtr ctx
-> Int
-> (Ptr ctx -> IO CSize)
-> ConsumeBlock ctx io
-> Finish ctx io
-> IO Result
streaming :: IO (Ptr ctx)
-> FinalizerPtr ctx
-> Int
-> (Ptr ctx -> IO CSize)
-> ConsumeBlock ctx io
-> Finish ctx io
-> IO Result
streaming IO (Ptr ctx)
createStream FinalizerPtr ctx
freeStream Int
outSize Ptr ctx -> IO CSize
initStream ConsumeBlock ctx io
consumeBlock Finish ctx io
finish = do
Ptr ctx
cx <- String -> IO (Ptr ctx) -> IO (Ptr ctx)
forall a. String -> IO (Ptr a) -> IO (Ptr a)
checkAlloc String
"createStream" IO (Ptr ctx)
createStream
ForeignPtr ctx
cxfp <- FinalizerPtr ctx -> Ptr ctx -> IO (ForeignPtr ctx)
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr ctx
freeStream Ptr ctx
cx
String -> IO CSize -> (CSize -> IO Result) -> IO Result
check String
"initStream" (Ptr ctx -> IO CSize
initStream Ptr ctx
cx) ((CSize -> IO Result) -> IO Result)
-> (CSize -> IO Result) -> IO Result
forall a b. (a -> b) -> a -> b
$ \CSize
_ -> do
ForeignPtr (Buffer In)
ibfp <- FinalizerPtr (Buffer In)
-> Ptr (Buffer In) -> IO (ForeignPtr (Buffer In))
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr (Buffer In)
forall a. FinalizerPtr a
finalizerFree (Ptr (Buffer In) -> IO (ForeignPtr (Buffer In)))
-> IO (Ptr (Buffer In)) -> IO (ForeignPtr (Buffer In))
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO (Ptr (Buffer In))
forall a. Storable a => IO (Ptr a)
malloc
ForeignPtr (Buffer Out)
obfp <- FinalizerPtr (Buffer Out)
-> Ptr (Buffer Out) -> IO (ForeignPtr (Buffer Out))
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr (Buffer Out)
forall a. FinalizerPtr a
finalizerFree (Ptr (Buffer Out) -> IO (ForeignPtr (Buffer Out)))
-> IO (Ptr (Buffer Out)) -> IO (ForeignPtr (Buffer Out))
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO (Ptr (Buffer Out))
forall a. Storable a => IO (Ptr a)
malloc
ForeignPtr Word8
dfp <- ForeignPtr (Buffer Out) -> IO (ForeignPtr Word8)
forall io a. ForeignPtr (Buffer io) -> IO (ForeignPtr a)
newOutput ForeignPtr (Buffer Out)
obfp
ForeignPtr ctx
-> ForeignPtr (Buffer In)
-> ForeignPtr (Buffer Out)
-> Int
-> ForeignPtr Word8
-> IO Result
advanceInput ForeignPtr ctx
cxfp ForeignPtr (Buffer In)
ibfp ForeignPtr (Buffer Out)
obfp Int
0 ForeignPtr Word8
dfp
where
advanceInput :: ForeignPtr ctx
-> ForeignPtr (Buffer In)
-> ForeignPtr (Buffer Out)
-> Int
-> ForeignPtr Word8
-> IO Result
advanceInput ForeignPtr ctx
cxfp ForeignPtr (Buffer In)
ibfp ForeignPtr (Buffer Out)
obfp Int
opos ForeignPtr Word8
dfp = do
let prompt :: ByteString -> IO Result
prompt (PS ForeignPtr Word8
fp Int
off Int
len)
| Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Finish ctx io
finish ForeignPtr ctx
cxfp ForeignPtr (Buffer Out)
obfp Int
opos ForeignPtr Word8
dfp
| Bool
otherwise = do
ForeignPtr Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
fp ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
sp0 ->
ForeignPtr (Buffer In) -> (Ptr (Buffer In) -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr (Buffer In)
ibfp ((Ptr (Buffer In) -> IO ()) -> IO ())
-> (Ptr (Buffer In) -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr (Buffer In)
ibuf ->
Ptr (Buffer In) -> Buffer In -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr (Buffer In)
ibuf (Ptr Any -> CSize -> Buffer In
forall a io. Ptr a -> CSize -> Buffer io
buffer (Ptr Word8
sp0 Ptr Word8 -> Int -> Ptr Any
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
off) (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len))
ForeignPtr ctx
-> ForeignPtr (Buffer In)
-> CSize
-> Int
-> ForeignPtr (Buffer Out)
-> Int
-> ForeignPtr Word8
-> ForeignPtr Word8
-> IO Result
consume ForeignPtr ctx
cxfp ForeignPtr (Buffer In)
ibfp CSize
0 Int
len ForeignPtr (Buffer Out)
obfp Int
0 ForeignPtr Word8
dfp ForeignPtr Word8
fp
Result -> IO Result
forall (m :: * -> *) a. Monad m => a -> m a
return ((ByteString -> IO Result) -> Result
Consume ByteString -> IO Result
prompt)
newOutput :: ForeignPtr (Buffer io) -> IO (ForeignPtr a)
newOutput ForeignPtr (Buffer io)
obfp = do
ForeignPtr a
dfp <- Int -> IO (ForeignPtr a)
forall a. Int -> IO (ForeignPtr a)
mallocByteString Int
outSize
ForeignPtr a -> (Ptr a -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr a
dfp ((Ptr a -> IO ()) -> IO ()) -> (Ptr a -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr a
dp ->
ForeignPtr (Buffer io) -> (Ptr (Buffer io) -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr (Buffer io)
obfp ((Ptr (Buffer io) -> IO ()) -> IO ())
-> (Ptr (Buffer io) -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr (Buffer io)
obuf ->
Ptr (Buffer io) -> Buffer io -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr (Buffer io)
obuf (Ptr a -> CSize -> Buffer io
forall a io. Ptr a -> CSize -> Buffer io
buffer Ptr a
dp (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
outSize))
ForeignPtr a -> IO (ForeignPtr a)
forall (m :: * -> *) a. Monad m => a -> m a
return ForeignPtr a
dfp
consume :: ForeignPtr ctx
-> ForeignPtr (Buffer In)
-> CSize
-> Int
-> ForeignPtr (Buffer Out)
-> Int
-> ForeignPtr Word8
-> ForeignPtr Word8
-> IO Result
consume ForeignPtr ctx
cxfp ForeignPtr (Buffer In)
ibfp CSize
ipos Int
ilen ForeignPtr (Buffer Out)
obfp Int
opos ForeignPtr Word8
dfp ForeignPtr Word8
fp = do
if | CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
ipos Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
ilen -> ForeignPtr ctx
-> ForeignPtr (Buffer In)
-> ForeignPtr (Buffer Out)
-> Int
-> ForeignPtr Word8
-> IO Result
advanceInput ForeignPtr ctx
cxfp ForeignPtr (Buffer In)
ibfp ForeignPtr (Buffer Out)
obfp Int
opos ForeignPtr Word8
dfp
| Int
opos Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
outSize -> do
let go :: IO Result
go = do
ForeignPtr Word8
ndfp <- ForeignPtr (Buffer Out) -> IO (ForeignPtr Word8)
forall io a. ForeignPtr (Buffer io) -> IO (ForeignPtr a)
newOutput ForeignPtr (Buffer Out)
obfp
ForeignPtr ctx
-> ForeignPtr (Buffer In)
-> CSize
-> Int
-> ForeignPtr (Buffer Out)
-> Int
-> ForeignPtr Word8
-> ForeignPtr Word8
-> IO Result
consume ForeignPtr ctx
cxfp ForeignPtr (Buffer In)
ibfp CSize
ipos Int
ilen ForeignPtr (Buffer Out)
obfp Int
0 ForeignPtr Word8
ndfp ForeignPtr Word8
fp
Result -> IO Result
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString -> IO Result -> Result
Produce (ForeignPtr Word8 -> Int -> Int -> ByteString
PS ForeignPtr Word8
dfp Int
0 Int
opos) IO Result
go)
| Bool
otherwise -> do
let obuf :: Ptr (Buffer Out)
obuf = ForeignPtr (Buffer Out) -> Ptr (Buffer Out)
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtr ForeignPtr (Buffer Out)
obfp
ibuf :: Ptr (Buffer In)
ibuf = ForeignPtr (Buffer In) -> Ptr (Buffer In)
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtr ForeignPtr (Buffer In)
ibfp
String -> IO CSize -> (CSize -> IO Result) -> IO Result
check String
"consumeBlock"
(ForeignPtr ctx -> (Ptr ctx -> IO CSize) -> IO CSize
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr ctx
cxfp ((Ptr ctx -> IO CSize) -> IO CSize)
-> (Ptr ctx -> IO CSize) -> IO CSize
forall a b. (a -> b) -> a -> b
$ \Ptr ctx
cptr ->
ConsumeBlock ctx io
consumeBlock Ptr ctx
cptr Ptr (Buffer Out)
obuf Ptr (Buffer In)
ibuf IO CSize -> IO () -> IO CSize
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ForeignPtr Word8 -> IO ()
forall a. ForeignPtr a -> IO ()
touchForeignPtr ForeignPtr Word8
fp) ((CSize -> IO Result) -> IO Result)
-> (CSize -> IO Result) -> IO Result
forall a b. (a -> b) -> a -> b
$ \CSize
_ -> do
Int
opos1 <- CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CSize -> Int) -> IO CSize -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Ptr (Buffer Out) -> IO CSize
forall io. Ptr (Buffer io) -> IO CSize
peekPos Ptr (Buffer Out)
obuf
CSize
ipos1 <- Ptr (Buffer In) -> IO CSize
forall io. Ptr (Buffer io) -> IO CSize
peekPos Ptr (Buffer In)
ibuf
ForeignPtr (Buffer Out) -> IO ()
forall a. ForeignPtr a -> IO ()
touchForeignPtr ForeignPtr (Buffer Out)
obfp
ForeignPtr (Buffer In) -> IO ()
forall a. ForeignPtr a -> IO ()
touchForeignPtr ForeignPtr (Buffer In)
ibfp
ForeignPtr ctx
-> ForeignPtr (Buffer In)
-> CSize
-> Int
-> ForeignPtr (Buffer Out)
-> Int
-> ForeignPtr Word8
-> ForeignPtr Word8
-> IO Result
consume ForeignPtr ctx
cxfp ForeignPtr (Buffer In)
ibfp CSize
ipos1 Int
ilen ForeignPtr (Buffer Out)
obfp Int
opos1 ForeignPtr Word8
dfp ForeignPtr Word8
fp
decompress :: IO Result
decompress :: IO Result
decompress =
IO (Ptr DStream)
-> FinalizerPtr DStream
-> Int
-> (Ptr DStream -> IO CSize)
-> ConsumeBlock DStream Any
-> Finish DStream Any
-> IO Result
forall ctx io.
IO (Ptr ctx)
-> FinalizerPtr ctx
-> Int
-> (Ptr ctx -> IO CSize)
-> ConsumeBlock ctx io
-> Finish ctx io
-> IO Result
streaming
IO (Ptr DStream)
createDStream
FinalizerPtr DStream
p_freeDStream
Int
outSize
Ptr DStream -> IO CSize
initDStream
ConsumeBlock DStream Any
decompressStream
Finish DStream Any
forall p p. p -> p -> Int -> ForeignPtr Word8 -> IO Result
finish
where
outSize :: Int
outSize = CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
dstreamOutSize
finish :: p -> p -> Int -> ForeignPtr Word8 -> IO Result
finish p
_cxfp p
_obfp Int
opos ForeignPtr Word8
dfp = ByteString -> Result
Done (ByteString -> Result) -> IO ByteString -> IO Result
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Int -> ForeignPtr Word8 -> Int -> IO ByteString
shrink Int
outSize ForeignPtr Word8
dfp Int
opos
shrink :: Int -> ForeignPtr Word8 -> Int -> IO B.ByteString
shrink :: Int -> ForeignPtr Word8 -> Int -> IO ByteString
shrink Int
capacity ForeignPtr Word8
dfp Int
opos
| Int
opos Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = ByteString -> IO ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
B.empty
| let unused :: Int
unused = Int
capacity Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
opos
in Int
unused Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
1024 Bool -> Bool -> Bool
|| Int
unused Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
capacity Int -> Int -> Int
forall a. Integral a => a -> a -> a
`rem` Int
8
= ByteString -> IO ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString -> ByteString
B.copy (ForeignPtr Word8 -> Int -> Int -> ByteString
PS ForeignPtr Word8
dfp Int
0 Int
opos))
| Bool
otherwise = ByteString -> IO ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return (ForeignPtr Word8 -> Int -> Int -> ByteString
PS ForeignPtr Word8
dfp Int
0 Int
opos)
buffer :: Ptr a -> CSize -> Buffer io
buffer :: Ptr a -> CSize -> Buffer io
buffer Ptr a
ptr CSize
size = Ptr a -> CSize -> CSize -> Buffer io
forall io a. Ptr a -> CSize -> CSize -> Buffer io
Buffer Ptr a
ptr CSize
size CSize
0
check :: String -> IO CSize -> (CSize -> IO Result) -> IO Result
check :: String -> IO CSize -> (CSize -> IO Result) -> IO Result
check String
name IO CSize
act CSize -> IO Result
onSuccess = do
CSize
ret <- IO CSize
act
if CSize -> Bool
isError CSize
ret
then Result -> IO Result
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> String -> Result
Error String
name (CSize -> String
getErrorName CSize
ret))
else CSize -> IO Result
onSuccess CSize
ret