1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
|
-- |
-- Module : Data.ByteArray.Pack.Internal
-- License : BSD-Style
-- Copyright : Copyright © 2014 Nicolas DI PRIMA
--
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : unknown
--
module Data.ByteArray.Pack.Internal
( Result(..)
, Packer(..)
, actionPacker
, actionPackerWithRemain
) where
import Foreign.Ptr (Ptr)
import Data.ByteArray.MemView
import Data.Memory.Internal.Imports
-- | Packing result:
--
-- * PackerMore: the next state of Packing with an arbitrary value
-- * PackerFail: an error happened
data Result a =
PackerMore a MemView
| PackerFail String
deriving (Show)
-- | Simple ByteArray Packer
newtype Packer a = Packer { runPacker_ :: MemView -> IO (Result a) }
instance Functor Packer where
fmap = fmapPacker
instance Applicative Packer where
pure = returnPacker
(<*>) = appendPacker
instance Monad Packer where
return = pure
(>>=) = bindPacker
fmapPacker :: (a -> b) -> Packer a -> Packer b
fmapPacker f p = Packer $ \cache -> do
rv <- runPacker_ p cache
return $ case rv of
PackerMore v cache' -> PackerMore (f v) cache'
PackerFail err -> PackerFail err
{-# INLINE fmapPacker #-}
returnPacker :: a -> Packer a
returnPacker v = Packer $ \cache -> return $ PackerMore v cache
{-# INLINE returnPacker #-}
bindPacker :: Packer a -> (a -> Packer b) -> Packer b
bindPacker p fp = Packer $ \cache -> do
rv <- runPacker_ p cache
case rv of
PackerMore v cache' -> runPacker_ (fp v) cache'
PackerFail err -> return $ PackerFail err
{-# INLINE bindPacker #-}
appendPacker :: Packer (a -> b) -> Packer a -> Packer b
appendPacker p1f p2 = p1f >>= \p1 -> p2 >>= \v -> return (p1 v)
{-# INLINE appendPacker #-}
-- | run a sized action
actionPacker :: Int -> (Ptr Word8 -> IO a) -> Packer a
actionPacker s action = Packer $ \m@(MemView ptr size) ->
case compare size s of
LT -> return $ PackerFail "Not enough space in destination"
_ -> do
v <- action ptr
return $ PackerMore v (m `memViewPlus` s)
{-# INLINE actionPacker #-}
-- | run a sized action
actionPackerWithRemain :: Int -> (Ptr Word8 -> Int -> IO (Int, a)) -> Packer a
actionPackerWithRemain s action = Packer $ \m@(MemView ptr size) ->
case compare size s of
LT -> return $ PackerFail "Not enough space in destination"
_ -> do
(remain, v) <- action ptr size
return $ if remain > s
then PackerFail "remaining bytes higher than the destination's size"
else PackerMore v (m `memViewPlus` (s+remain))
{-# INLINE actionPackerWithRemain #-}
|