bytearray-parsing-0.1: library/ByteArray/Parsing/Parse.hs
module ByteArray.Parsing.Parse
where
import ByteArray.Parsing.Prelude hiding (take, takeWhile)
import qualified Data.ByteString.Internal as A
import qualified GHC.ForeignPtr as B
import qualified Data.Primitive.ByteArray as C
import qualified Data.Primitive.Addr as D
import qualified ByteArray.Parsing.Prim as E
newtype Parse a =
Parse (forall x. C.ByteArray -> Int -> (Int -> x) -> (Text -> x) -> (Int -> a -> x) -> x)
instance Functor Parse where
{-# INLINE fmap #-}
fmap mapping (Parse parse) =
Parse $ \ array index needMoreResult errorResult successResult ->
{-# SCC "fmap" #-}
parse array index needMoreResult errorResult $ \ newIndex parsed ->
successResult newIndex (mapping parsed)
instance Applicative Parse where
{-# INLINE pure #-}
pure x =
Parse $ \ _ index _ _ successResult -> successResult index x
{-# INLINE (<*>) #-}
(<*>) (Parse parseLeft) (Parse parseRight) =
Parse $ \ array index needMoreResult errorResult successResult ->
{-# SCC "<*>" #-}
parseLeft array index needMoreResult errorResult $ \ leftConsumed leftParsed ->
parseRight array leftConsumed needMoreResult errorResult $ \ rightConsumed rightParsed ->
successResult rightConsumed (leftParsed rightParsed)
instance Alternative Parse where
{-# INLINE empty #-}
empty =
Parse $ \ _ _ needMoreResult _ _ -> needMoreResult 0
{-# INLINE (<|>) #-}
(<|>) (Parse parseLeft) (Parse parseRight) =
Parse $ \ array index needMoreResult errorResult successResult ->
{-# SCC "<|>" #-}
parseLeft array index
(\ _ -> parseRight array index needMoreResult errorResult successResult)
errorResult
successResult
instance Monad Parse where
{-# INLINE return #-}
return =
pure
{-# INLINE (>>=) #-}
(>>=) (Parse parseLeft) rightK =
Parse $ \ array index needMoreResult errorResult successResult ->
{-# SCC ">>=" #-}
parseLeft array index needMoreResult errorResult $ \ leftConsumed leftParsed ->
case rightK leftParsed of
Parse parseRight ->
parseRight array leftConsumed needMoreResult errorResult successResult
instance MonadPlus Parse where
mzero = empty
mplus = (<|>)
{-# INLINE fail #-}
fail :: Text -> Parse a
fail message =
Parse $ \ _ _ _ errorResult _ ->
errorResult message
{-# INLINE word8 #-}
word8 :: Parse Word8
word8 =
Parse $ \ array index needMoreResult errorResult successResult ->
{-# SCC "word8" #-}
if C.sizeofByteArray array >= index
then successResult (succ index) (C.indexByteArray array index)
else needMoreResult 1
{-# INLINE beNum #-}
beNum :: (Bits a, Num a) => Int -> Parse a
beNum size =
Parse $ \ array index needMoreResult errorResult successResult ->
{-# SCC "beNum" #-}
let
arrayLength = C.sizeofByteArray array
nextIndex = index + size
in if arrayLength >= size
then let
fold !index !state =
if index < nextIndex
then fold (succ index) (shiftL state 8 .|. fromIntegral (C.indexByteArray array index :: Word8))
else state
in successResult (nextIndex) (fold index 0)
else needMoreResult (nextIndex - arrayLength)
{-# INLINE beWord16 #-}
beWord16 :: Parse Word16
beWord16 =
{-# SCC "beWord16" #-}
beNum 2
{-# INLINE beWord32 #-}
beWord32 :: Parse Word32
beWord32 =
{-# SCC "beWord32" #-}
beNum 4
{-# INLINE beWord64 #-}
beWord64 :: Parse Word64
beWord64 =
{-# SCC "beWord64" #-}
beNum 8
{-# INLINE shortByteString #-}
shortByteString :: Int -> Parse ShortByteString
shortByteString size =
Parse $ \ array index needMoreResult errorResult successResult ->
{-# SCC "shortByteString" #-}
let
arrayLength = C.sizeofByteArray array
nextIndex = index + size
in if arrayLength >= nextIndex
then successResult nextIndex (E.byteArraySliceToShortByteString index size array)
else needMoreResult (nextIndex - arrayLength)
{-# INLINE byteString #-}
byteString :: Int -> Parse ByteString
byteString size =
Parse $ \ array index needMoreResult errorResult successResult ->
{-# SCC "byteString" #-}
let
arrayLength = C.sizeofByteArray array
nextIndex = index + size
in if arrayLength >= nextIndex
then successResult nextIndex (E.byteArraySliceToByteString index size array)
else needMoreResult (nextIndex - arrayLength)
{-# INLINE remainingByteString #-}
remainingByteString :: Parse ByteString
remainingByteString =
Parse $ \ array index needMoreResult errorResult successResult ->
{-# SCC "remainingByteString" #-}
let
arrayLength =
C.sizeofByteArray array
size =
arrayLength - index
in successResult arrayLength (E.byteArraySliceToByteString index (arrayLength - index) array)
{-# INLINE nullTerminatedByteString #-}
nullTerminatedByteString :: Parse ByteString
nullTerminatedByteString =
Parse $ \ array index needMoreResult errorResult successResult ->
{-# SCC "nullTerminatedBytes" #-}
let
findNullIndex !index =
if (C.indexByteArray array index :: Word8) == 0
then index
else findNullIndex (succ index)
nullIndex =
findNullIndex index
nextIndex =
succ nullIndex
size =
nullIndex - index
in successResult nextIndex (E.byteArraySliceToByteString index size array)
{-# INLINE byteStringWhile #-}
byteStringWhile :: (Word8 -> Bool) -> Parse ByteString
byteStringWhile predicate =
Parse $ \ array index needMoreResult errorResult successResult ->
{-# SCC "byteStringWhile" #-}
let
iterate !index =
if predicate (C.indexByteArray array index)
then iterate (succ index)
else index
nextIndex =
iterate index
size =
nextIndex - index
in successResult nextIndex (E.byteArraySliceToByteString index size array)
{-# INLINE skipWhile #-}
skipWhile :: (Word8 -> Bool) -> Parse ()
skipWhile predicate =
Parse $ \ array index needMoreResult errorResult successResult ->
{-# SCC "skipWhile" #-}
let
iterate !index =
if predicate (C.indexByteArray array index)
then iterate (succ index)
else index
nextIndex =
iterate index
size =
nextIndex - index
in successResult nextIndex ()
{-# INLINE foldWhile #-}
foldWhile :: (Word8 -> Bool) -> (state -> Word8 -> state) -> state -> Parse state
foldWhile predicate step start =
Parse $ \ array index needMoreResult errorResult successResult ->
{-# SCC "foldWhile" #-}
let
iterate !index !state =
let
byte =
C.indexByteArray array index
in if predicate byte
then iterate (succ index) (step state byte)
else successResult index state
in iterate index start
-- |
-- Unsigned integral number encoded in ASCII.
{-# INLINE unsignedASCIIIntegral #-}
unsignedASCIIIntegral :: Integral a => Parse a
unsignedASCIIIntegral =
{-# SCC "unsignedASCIIIntegral" #-}
foldWhile byteIsDigit step 0
where
byteIsDigit byte =
byte - 48 <= 9
step !state !byte =
state * 10 + fromIntegral byte - 48