flat-0.6: src/Flat/Decoder/Run.hs
module Flat.Decoder.Run(strictDecoder,listTDecoder) where
import Control.Exception (Exception, try)
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as BS
import Flat.Decoder.Prim (dBool)
import Flat.Decoder.Types (DecodeException, Get (runGet),
GetResult (..), S (S), tooMuchSpace)
import Foreign (Ptr, plusPtr, withForeignPtr)
import ListT (ListT (..))
import System.IO.Unsafe (unsafePerformIO)
-- | Given a decoder and an input buffer returns either the decoded value or an error (if the input buffer is not fully consumed)
strictDecoder :: Get a -> B.ByteString -> Int -> Either DecodeException a
strictDecoder get bs usedBits=
strictDecoder_ get bs usedBits $ \(GetResult s'@(S ptr' o') a) endPtr ->
if ptr' /= endPtr || o' /= 0
then tooMuchSpace endPtr s'
else return a
strictDecoder_ ::
Exception e
=> Get a1
-> BS.ByteString
-> Int
-> (GetResult a1 -> Ptr b -> IO a)
-> Either e a
strictDecoder_ get (BS.PS base off len) usedBits check =
unsafePerformIO . try $
withForeignPtr base $ \base0 ->
let ptr = base0 `plusPtr` off
endPtr = ptr `plusPtr` len
in do res <- runGet get endPtr (S ptr usedBits)
check res endPtr
{-# NOINLINE strictDecoder_ #-}
-- strictRawDecoder :: Exception e => Get t -> B.ByteString -> Either e (t,B.ByteString, NumBits)
-- strictRawDecoder get (BS.PS base off len) = unsafePerformIO . try $
-- withForeignPtr base $ \base0 ->
-- let ptr = base0 `plusPtr` off
-- endPtr = ptr `plusPtr` len
-- in do
-- GetResult (S ptr' o') a <- runGet get endPtr (S ptr 0)
-- return (a, BS.PS base (ptr' `minusPtr` base0) (endPtr `minusPtr` ptr'), o')
{-|
Decode a list of values, one value at a time.
Useful in case that the decoded values takes a lot more memory than the encoded ones.
See <../test/Big.hs> for a test and an example of use.
See also "Flat.AsBin".
@since 0.5
-}
listTDecoder :: Get a -> BS.ByteString -> IO (ListT IO a)
listTDecoder get (BS.PS base off len) =
withForeignPtr base $ \base0 -> do
let ptr = base0 `plusPtr` off
endPtr = ptr `plusPtr` len
s = S ptr 0
go s = do
GetResult s' b <- runGet dBool endPtr s
if b
then do
GetResult s'' a <- runGet get endPtr s'
return $ Just (a, ListT $ go s'')
else return Nothing
return $ ListT (go s)