{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE LambdaCase #-}
module Data.ProtoLens.Encoding.Bytes(
Parser,
Builder,
runParser,
isolate,
runBuilder,
getBytes,
putBytes,
getText,
getVarInt,
getVarIntH,
putVarInt,
getFixed32,
getFixed64,
putFixed32,
putFixed64,
wordToFloat,
wordToDouble,
floatToWord,
doubleToWord,
signedInt32ToWord,
wordToSignedInt32,
signedInt64ToWord,
wordToSignedInt64,
atEnd,
runEither,
(<?>),
foldMapBuilder,
) where
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Except (throwE, ExceptT)
import Data.Bits
import Data.ByteString (ByteString)
import Data.ByteString.Builder as Builder
import qualified Data.ByteString.Builder.Internal as Internal
import qualified Data.ByteString.Lazy as L
import Data.Int (Int32, Int64)
#if !MIN_VERSION_base(4,11,0)
import Data.Semigroup ((<>))
#endif
import qualified Data.Vector.Generic as V
import Data.Word (Word8, Word32, Word64)
import Foreign.Marshal (malloc, free)
import Foreign.Storable (peek)
import System.IO (Handle, hGetBuf)
#if MIN_VERSION_base(4,11,0)
import qualified GHC.Float as Float
#else
import Foreign.Ptr (castPtr)
import Foreign.Marshal.Alloc (alloca)
import Foreign.Storable (Storable, poke)
import System.IO.Unsafe (unsafePerformIO)
#endif
import Data.ProtoLens.Encoding.Parser
runBuilder :: Builder -> ByteString
runBuilder :: Builder -> ByteString
runBuilder = ByteString -> ByteString
L.toStrict (ByteString -> ByteString)
-> (Builder -> ByteString) -> Builder -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> ByteString
Builder.toLazyByteString
putBytes :: ByteString -> Builder
putBytes :: ByteString -> Builder
putBytes = ByteString -> Builder
Builder.byteString
getVarInt :: Parser Word64
getVarInt :: Parser Word64
getVarInt = Word64 -> Word64 -> Parser Word64
loopStart Word64
0 Word64
1
where
loopStart :: Word64 -> Word64 -> Parser Word64
loopStart !Word64
n !Word64
s = Parser Word8
getWord8 Parser Word8 -> (Word8 -> Parser Word64) -> Parser Word64
forall a b. Parser a -> (a -> Parser b) -> Parser b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Word64 -> Word64 -> Parser Word64)
-> Word64 -> Word64 -> Word8 -> Parser Word64
forall (m :: * -> *).
Monad m =>
(Word64 -> Word64 -> m Word64)
-> Word64 -> Word64 -> Word8 -> m Word64
getVarIntLoopFinish Word64 -> Word64 -> Parser Word64
loopStart Word64
n Word64
s
getVarIntH :: Handle -> ExceptT String IO Word64
getVarIntH :: Handle -> ExceptT String IO Word64
getVarIntH Handle
h = do
Ptr Word8
buf <- IO (Ptr Word8) -> ExceptT String IO (Ptr Word8)
forall a. IO a -> ExceptT String IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO (Ptr Word8)
forall a. Storable a => IO (Ptr a)
malloc
let loopStart :: Word64 -> Word64 -> ExceptT String m Word64
loopStart !Word64
n !Word64
s =
(IO Int -> ExceptT String m Int
forall a. IO a -> ExceptT String m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Int -> ExceptT String m Int) -> IO Int -> ExceptT String m Int
forall a b. (a -> b) -> a -> b
$ Handle -> Ptr Word8 -> Int -> IO Int
forall a. Handle -> Ptr a -> Int -> IO Int
hGetBuf Handle
h Ptr Word8
buf Int
1) ExceptT String m Int
-> (Int -> ExceptT String m Word64) -> ExceptT String m Word64
forall a b.
ExceptT String m a
-> (a -> ExceptT String m b) -> ExceptT String m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
\case
Int
1 -> (IO Word8 -> ExceptT String m Word8
forall a. IO a -> ExceptT String m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Word8 -> ExceptT String m Word8)
-> IO Word8 -> ExceptT String m Word8
forall a b. (a -> b) -> a -> b
$ Ptr Word8 -> IO Word8
forall a. Storable a => Ptr a -> IO a
peek Ptr Word8
buf) ExceptT String m Word8
-> (Word8 -> ExceptT String m Word64) -> ExceptT String m Word64
forall a b.
ExceptT String m a
-> (a -> ExceptT String m b) -> ExceptT String m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
(Word64 -> Word64 -> ExceptT String m Word64)
-> Word64 -> Word64 -> Word8 -> ExceptT String m Word64
forall (m :: * -> *).
Monad m =>
(Word64 -> Word64 -> m Word64)
-> Word64 -> Word64 -> Word8 -> m Word64
getVarIntLoopFinish Word64 -> Word64 -> ExceptT String m Word64
loopStart Word64
n Word64
s
Int
_ -> String -> ExceptT String m Word64
forall (m :: * -> *) e a. Monad m => e -> ExceptT e m a
throwE String
"Unexpected end of file"
Word64
res <- Word64 -> Word64 -> ExceptT String IO Word64
forall {m :: * -> *}.
MonadIO m =>
Word64 -> Word64 -> ExceptT String m Word64
loopStart Word64
0 Word64
1
IO () -> ExceptT String IO ()
forall a. IO a -> ExceptT String IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> ExceptT String IO ()) -> IO () -> ExceptT String IO ()
forall a b. (a -> b) -> a -> b
$ Ptr Word8 -> IO ()
forall a. Ptr a -> IO ()
free Ptr Word8
buf
Word64 -> ExceptT String IO Word64
forall a. a -> ExceptT String IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Word64
res
getVarIntLoopFinish
:: (Monad m)
=> (Word64 -> Word64 -> m Word64)
-> Word64
-> Word64
-> Word8
-> m Word64
getVarIntLoopFinish :: forall (m :: * -> *).
Monad m =>
(Word64 -> Word64 -> m Word64)
-> Word64 -> Word64 -> Word8 -> m Word64
getVarIntLoopFinish Word64 -> Word64 -> m Word64
ls !Word64
n !Word64
s !Word8
b = do
let n' :: Word64
n' = Word64 -> Word64 -> Word8 -> Word64
decodeVarIntStep Word64
n Word64
s Word8
b
if Word8 -> Bool
testMsb Word8
b
then Word64 -> Word64 -> m Word64
ls Word64
n' (Word64
128Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
*Word64
s)
else Word64 -> m Word64
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Word64 -> m Word64) -> Word64 -> m Word64
forall a b. (a -> b) -> a -> b
$! Word64
n'
decodeVarIntStep :: Word64 -> Word64 -> Word8 -> Word64
decodeVarIntStep :: Word64 -> Word64 -> Word8 -> Word64
decodeVarIntStep Word64
n Word64
s Word8
b = Word64
n Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
s Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
127)
testMsb :: Word8 -> Bool
testMsb :: Word8 -> Bool
testMsb Word8
b = (Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
128) Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
0
putVarInt :: Word64 -> Builder
putVarInt :: Word64 -> Builder
putVarInt Word64
n
| Word64
n Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
128 = Word8 -> Builder
Builder.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
n)
| Bool
otherwise = Word8 -> Builder
Builder.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Word8) -> Word64 -> Word8
forall a b. (a -> b) -> a -> b
$ Word64
n Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word64
128)
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word64 -> Builder
putVarInt (Word64
n Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
7)
getFixed32 :: Parser Word32
getFixed32 :: Parser Word32
getFixed32 = Parser Word32
getWord32le
getFixed64 :: Parser Word64
getFixed64 :: Parser Word64
getFixed64 = do
Word32
x <- Parser Word32
getFixed32
Word32
y <- Parser Word32
getFixed32
Word64 -> Parser Word64
forall a. a -> Parser a
forall (m :: * -> *) a. Monad m => a -> m a
return (Word64 -> Parser Word64) -> Word64 -> Parser Word64
forall a b. (a -> b) -> a -> b
$ Word32 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
y Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
32 Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word32 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
x
putFixed32 :: Word32 -> Builder
putFixed32 :: Word32 -> Builder
putFixed32 !Word32
x = Word32 -> Builder
word32LE Word32
x
putFixed64 :: Word64 -> Builder
putFixed64 :: Word64 -> Builder
putFixed64 !Word64
x = Word64 -> Builder
word64LE Word64
x
#if MIN_VERSION_base(4,11,0)
wordToDouble :: Word64 -> Double
wordToDouble :: Word64 -> Double
wordToDouble = Word64 -> Double
Float.castWord64ToDouble
wordToFloat :: Word32 -> Float
wordToFloat :: Word32 -> Float
wordToFloat = Word32 -> Float
Float.castWord32ToFloat
doubleToWord :: Double -> Word64
doubleToWord :: Double -> Word64
doubleToWord = Double -> Word64
Float.castDoubleToWord64
floatToWord :: Float -> Word32
floatToWord :: Float -> Word32
floatToWord = Float -> Word32
Float.castFloatToWord32
#else
{-# INLINE cast #-}
cast :: (Storable a, Storable b) => a -> b
cast x = unsafePerformIO $ alloca $ \p -> do
poke p x
peek $ castPtr p
wordToDouble :: Word64 -> Double
wordToDouble = cast
wordToFloat :: Word32 -> Float
wordToFloat = cast
doubleToWord :: Double -> Word64
doubleToWord = cast
floatToWord :: Float -> Word32
floatToWord = cast
#endif
signedInt32ToWord :: Int32 -> Word32
signedInt32ToWord :: Int32 -> Word32
signedInt32ToWord Int32
n = Int32 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int32 -> Word32) -> Int32 -> Word32
forall a b. (a -> b) -> a -> b
$ Int32 -> Int -> Int32
forall a. Bits a => a -> Int -> a
shiftL Int32
n Int
1 Int32 -> Int32 -> Int32
forall a. Bits a => a -> a -> a
`xor` Int32 -> Int -> Int32
forall a. Bits a => a -> Int -> a
shiftR Int32
n Int
31
wordToSignedInt32 :: Word32 -> Int32
wordToSignedInt32 :: Word32 -> Int32
wordToSignedInt32 Word32
n
= Word32 -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
shiftR Word32
n Int
1) Int32 -> Int32 -> Int32
forall a. Bits a => a -> a -> a
`xor` Int32 -> Int32
forall a. Num a => a -> a
negate (Word32 -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Int32) -> Word32 -> Int32
forall a b. (a -> b) -> a -> b
$ Word32
n Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
1)
signedInt64ToWord :: Int64 -> Word64
signedInt64ToWord :: Int64 -> Word64
signedInt64ToWord Int64
n = Int64 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64 -> Word64) -> Int64 -> Word64
forall a b. (a -> b) -> a -> b
$ Int64 -> Int -> Int64
forall a. Bits a => a -> Int -> a
shiftL Int64
n Int
1 Int64 -> Int64 -> Int64
forall a. Bits a => a -> a -> a
`xor` Int64 -> Int -> Int64
forall a. Bits a => a -> Int -> a
shiftR Int64
n Int
63
wordToSignedInt64 :: Word64 -> Int64
wordToSignedInt64 :: Word64 -> Int64
wordToSignedInt64 Word64
n
= Word64 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
shiftR Word64
n Int
1) Int64 -> Int64 -> Int64
forall a. Bits a => a -> a -> a
`xor` Int64 -> Int64
forall a. Num a => a -> a
negate (Word64 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int64) -> Word64 -> Int64
forall a b. (a -> b) -> a -> b
$ Word64
n Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
1)
runEither :: Either String a -> Parser a
runEither :: forall a. Either String a -> Parser a
runEither = (String -> Parser a)
-> (a -> Parser a) -> Either String a -> Parser a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> Parser a
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail a -> Parser a
forall a. a -> Parser a
forall (m :: * -> *) a. Monad m => a -> m a
return
foldMapBuilder :: V.Vector v a => (a -> Builder) -> v a -> Builder
foldMapBuilder :: forall (v :: * -> *) a.
Vector v a =>
(a -> Builder) -> v a -> Builder
foldMapBuilder a -> Builder
f = \v a
v0 -> (forall r. BuildStep r -> BuildStep r) -> Builder
Internal.builder (v a
-> (BufferRange -> IO (BuildSignal r))
-> BufferRange
-> IO (BuildSignal r)
forall {v :: * -> *} {a}.
Vector v a =>
v a
-> (BufferRange -> IO (BuildSignal a))
-> BufferRange
-> IO (BuildSignal a)
loop v a
v0)
where
loop :: v a
-> (BufferRange -> IO (BuildSignal a))
-> BufferRange
-> IO (BuildSignal a)
loop v a
v BufferRange -> IO (BuildSignal a)
cont BufferRange
bs
| v a -> Bool
forall (v :: * -> *) a. Vector v a => v a -> Bool
V.null v a
v = BufferRange -> IO (BuildSignal a)
cont BufferRange
bs
| Bool
otherwise = let
!x :: a
x = v a -> a
forall (v :: * -> *) a. Vector v a => v a -> a
V.unsafeHead v a
v
!xs :: v a
xs = v a -> v a
forall (v :: * -> *) a. Vector v a => v a -> v a
V.unsafeTail v a
v
in Builder
-> (BufferRange -> IO (BuildSignal a))
-> BufferRange
-> IO (BuildSignal a)
forall a. Builder -> BuildStep a -> BuildStep a
Internal.runBuilderWith
(a -> Builder
f a
x)
(v a
-> (BufferRange -> IO (BuildSignal a))
-> BufferRange
-> IO (BuildSignal a)
loop v a
xs BufferRange -> IO (BuildSignal a)
cont) BufferRange
bs
{-# INLINE foldMapBuilder #-}