-- | Machine integer parsers.

module FlatParse.Basic.Integers
  (
  -- * Native byte order
    anyWord8, anyWord16, anyWord32, anyWord64
  , anyInt8,  anyInt16,  anyInt32,  anyInt64
  , anyWord, anyInt

  -- * Explicit endianness
  -- $explicit-endianness
  , anyWord16le, anyWord16be
  , anyWord32le, anyWord32be
  , anyWord64le, anyWord64be
  , anyInt16le,  anyInt16be
  , anyInt32le,  anyInt32be
  , anyInt64le,  anyInt64be

  -- * Value assertions
  , word8

  -- * CPS parsers
  , withAnyWord8, withAnyWord16, withAnyWord32, withAnyWord64
  , withAnyInt8,  withAnyInt16,  withAnyInt32,  withAnyInt64
  , withAnyWord, withAnyInt

  -- * Unsafe
  -- $unsafe
  , anyWord8Unsafe

  -- ** Value assertions
  , word8Unsafe, word16Unsafe, word32Unsafe, word64Unsafe

  -- * Helper definitions
  , withAnySized#, withAnySizedUnsafe#
  , sizedUnsafe#
  ) where

import FlatParse.Basic.Parser
import FlatParse.Basic.Base ( withEnsure# )

import FlatParse.Common.Assorted ( word16ToInt16, word32ToInt32, word64ToInt64 )

import FlatParse.Common.GHCExts
import GHC.Word
import GHC.Int

import Control.Applicative ( Alternative(empty) )

--------------------------------------------------------------------------------

-- | Helper for defining CPS parsers for types of a constant byte size (i.e.
--   machine integers).
--
-- Call this with an @indexXYZOffAddr@ primop (e.g.
-- 'GHC.Exts.indexWord8OffAddr') and the size in bytes of the type you're
-- parsing.
withAnySized#
    :: Int# -> (Addr# -> Int# -> a) -> (a -> ParserT st e r) -> ParserT st e r
withAnySized# :: forall a (st :: ZeroBitType) e r.
Int#
-> (Addr# -> Int# -> a) -> (a -> ParserT st e r) -> ParserT st e r
withAnySized# Int#
size# Addr# -> Int# -> a
indexOffAddr a -> ParserT st e r
p =
    Int# -> ParserT st e r -> ParserT st e r
forall (st :: ZeroBitType) e r.
Int# -> ParserT st e r -> ParserT st e r
withEnsure# Int#
size# (Int#
-> (Addr# -> Int# -> a) -> (a -> ParserT st e r) -> ParserT st e r
forall a (st :: ZeroBitType) e r.
Int#
-> (Addr# -> Int# -> a) -> (a -> ParserT st e r) -> ParserT st e r
withAnySizedUnsafe# Int#
size# Addr# -> Int# -> a
indexOffAddr a -> ParserT st e r
p)
{-# inline withAnySized# #-}

-- | Unsafe helper for defining CPS parsers for types of a constant byte size
--   (i.e. machine integers).
--
-- Is really just syntactic sugar for applying the given parser and shifting the
-- buffer along.
--
-- The caller must guarantee that the input has enough bytes.
withAnySizedUnsafe#
    :: Int# -> (Addr# -> Int# -> a) -> (a -> ParserT st e r) -> ParserT st e r
withAnySizedUnsafe# :: forall a (st :: ZeroBitType) e r.
Int#
-> (Addr# -> Int# -> a) -> (a -> ParserT st e r) -> ParserT st e r
withAnySizedUnsafe# Int#
size# Addr# -> Int# -> a
indexOffAddr a -> ParserT st e r
p = (ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e r)
-> ParserT st e r
forall (st :: ZeroBitType) e a.
(ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e a)
-> ParserT st e a
ParserT \ForeignPtrContents
fp Addr#
eob Addr#
buf st
st ->
  let !a :: a
a   = Addr# -> Int# -> a
indexOffAddr Addr#
buf Int#
0#
      buf' :: Addr#
buf' = Addr# -> Int# -> Addr#
plusAddr# Addr#
buf Int#
size#
  in  ParserT st e r
-> ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e r
forall (st :: ZeroBitType) e a.
ParserT st e a
-> ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e a
runParserT# (a -> ParserT st e r
p a
a) ForeignPtrContents
fp Addr#
eob Addr#
buf' st
st
{-# inline withAnySizedUnsafe# #-}

-- | Parse any 'Word8' (CPS).
withAnyWord8 :: (Word8 -> ParserT st e r) -> ParserT st e r
withAnyWord8 :: forall (st :: ZeroBitType) e r.
(Word8 -> ParserT st e r) -> ParserT st e r
withAnyWord8 Word8 -> ParserT st e r
p = (ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e r)
-> ParserT st e r
forall (st :: ZeroBitType) e a.
(ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e a)
-> ParserT st e a
ParserT \ForeignPtrContents
fp Addr#
eob Addr#
buf st
st -> case Addr# -> Addr# -> Int#
eqAddr# Addr#
eob Addr#
buf of
  Int#
1# -> st -> Res# st e r
forall (st :: ZeroBitType) e a. st -> Res# st e a
Fail# st
st
  Int#
_  -> let w# :: Word8#
w# = Addr# -> Int# -> Word8#
indexWord8OffAddr# Addr#
buf Int#
0#
        in  ParserT st e r
-> ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e r
forall (st :: ZeroBitType) e a.
ParserT st e a
-> ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e a
runParserT# (Word8 -> ParserT st e r
p (Word8# -> Word8
W8# Word8#
w#)) ForeignPtrContents
fp Addr#
eob (Addr# -> Int# -> Addr#
plusAddr# Addr#
buf Int#
1#) st
st
{-# inline withAnyWord8 #-}

-- | Parse any 'Word16' (native byte order) (CPS).
withAnyWord16 :: (Word16 -> ParserT st e r) -> ParserT st e r
withAnyWord16 :: forall (st :: ZeroBitType) e r.
(Word16 -> ParserT st e r) -> ParserT st e r
withAnyWord16 = Int#
-> (Addr# -> Int# -> Word16)
-> (Word16 -> ParserT st e r)
-> ParserT st e r
forall a (st :: ZeroBitType) e r.
Int#
-> (Addr# -> Int# -> a) -> (a -> ParserT st e r) -> ParserT st e r
withAnySized# Int#
2# (\Addr#
a Int#
i -> Word16# -> Word16
W16# (Addr# -> Int# -> Word16#
indexWord16OffAddr# Addr#
a Int#
i))
{-# inline withAnyWord16 #-}

-- | Parse any 'Word32' (native byte order) (CPS).
withAnyWord32 :: (Word32 -> ParserT st e r) -> ParserT st e r
withAnyWord32 :: forall (st :: ZeroBitType) e r.
(Word32 -> ParserT st e r) -> ParserT st e r
withAnyWord32 = Int#
-> (Addr# -> Int# -> Word32)
-> (Word32 -> ParserT st e r)
-> ParserT st e r
forall a (st :: ZeroBitType) e r.
Int#
-> (Addr# -> Int# -> a) -> (a -> ParserT st e r) -> ParserT st e r
withAnySized# Int#
4# (\Addr#
a Int#
i -> Word32# -> Word32
W32# (Addr# -> Int# -> Word32#
indexWord32OffAddr# Addr#
a Int#
i))
{-# inline withAnyWord32 #-}

-- | Parse any 'Word64' (native byte order) (CPS).
withAnyWord64 :: (Word64 -> ParserT st e r) -> ParserT st e r
withAnyWord64 :: forall (st :: ZeroBitType) e r.
(Word64 -> ParserT st e r) -> ParserT st e r
withAnyWord64 = Int#
-> (Addr# -> Int# -> Word64)
-> (Word64 -> ParserT st e r)
-> ParserT st e r
forall a (st :: ZeroBitType) e r.
Int#
-> (Addr# -> Int# -> a) -> (a -> ParserT st e r) -> ParserT st e r
withAnySized# Int#
8# (\Addr#
a Int#
i -> Word64# -> Word64
W64# (Addr# -> Int# -> Word64#
indexWord64OffAddr# Addr#
a Int#
i))
{-# inline withAnyWord64 #-}

-- | Parse any 'Int8' (CPS).
withAnyInt8 :: (Int8 -> ParserT st e r) -> ParserT st e r
withAnyInt8 :: forall (st :: ZeroBitType) e r.
(Int8 -> ParserT st e r) -> ParserT st e r
withAnyInt8 Int8 -> ParserT st e r
p = (ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e r)
-> ParserT st e r
forall (st :: ZeroBitType) e a.
(ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e a)
-> ParserT st e a
ParserT \ForeignPtrContents
fp Addr#
eob Addr#
buf st
st -> case Addr# -> Addr# -> Int#
eqAddr# Addr#
eob Addr#
buf of
  Int#
1# -> st -> Res# st e r
forall (st :: ZeroBitType) e a. st -> Res# st e a
Fail# st
st
  Int#
_  -> let i# :: Int8#
i# = Addr# -> Int# -> Int8#
indexInt8OffAddr# Addr#
buf Int#
0#
        in  ParserT st e r
-> ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e r
forall (st :: ZeroBitType) e a.
ParserT st e a
-> ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e a
runParserT# (Int8 -> ParserT st e r
p (Int8# -> Int8
I8# Int8#
i#)) ForeignPtrContents
fp Addr#
eob (Addr# -> Int# -> Addr#
plusAddr# Addr#
buf Int#
1#) st
st
{-# inline withAnyInt8 #-}

-- | Parse any 'Int16' (native byte order) (CPS).
withAnyInt16 :: (Int16 -> ParserT st e r) -> ParserT st e r
withAnyInt16 :: forall (st :: ZeroBitType) e r.
(Int16 -> ParserT st e r) -> ParserT st e r
withAnyInt16 = Int#
-> (Addr# -> Int# -> Int16)
-> (Int16 -> ParserT st e r)
-> ParserT st e r
forall a (st :: ZeroBitType) e r.
Int#
-> (Addr# -> Int# -> a) -> (a -> ParserT st e r) -> ParserT st e r
withAnySized# Int#
2# (\Addr#
a Int#
i -> Int16# -> Int16
I16# (Addr# -> Int# -> Int16#
indexInt16OffAddr# Addr#
a Int#
i))
{-# inline withAnyInt16 #-}

-- | Parse any 'Int32' (native byte order) (CPS).
withAnyInt32 :: (Int32 -> ParserT st e r) -> ParserT st e r
withAnyInt32 :: forall (st :: ZeroBitType) e r.
(Int32 -> ParserT st e r) -> ParserT st e r
withAnyInt32 = Int#
-> (Addr# -> Int# -> Int32)
-> (Int32 -> ParserT st e r)
-> ParserT st e r
forall a (st :: ZeroBitType) e r.
Int#
-> (Addr# -> Int# -> a) -> (a -> ParserT st e r) -> ParserT st e r
withAnySized# Int#
4# (\Addr#
a Int#
i -> Int32# -> Int32
I32# (Addr# -> Int# -> Int32#
indexInt32OffAddr# Addr#
a Int#
i))
{-# inline withAnyInt32 #-}

-- | Parse any 'Int64' (native byte order) (CPS).
withAnyInt64 :: (Int64 -> ParserT st e r) -> ParserT st e r
withAnyInt64 :: forall (st :: ZeroBitType) e r.
(Int64 -> ParserT st e r) -> ParserT st e r
withAnyInt64 = Int#
-> (Addr# -> Int# -> Int64)
-> (Int64 -> ParserT st e r)
-> ParserT st e r
forall a (st :: ZeroBitType) e r.
Int#
-> (Addr# -> Int# -> a) -> (a -> ParserT st e r) -> ParserT st e r
withAnySized# Int#
8# (\Addr#
a Int#
i -> Int64# -> Int64
I64# (Addr# -> Int# -> Int64#
indexInt64OffAddr# Addr#
a Int#
i))
{-# inline withAnyInt64 #-}

-- TODO assumes 64-bit platform
-- | Parse any 'Word' (native size) (CPS).
withAnyWord :: (Word -> ParserT st e r) -> ParserT st e r
withAnyWord :: forall (st :: ZeroBitType) e r.
(Word -> ParserT st e r) -> ParserT st e r
withAnyWord Word -> ParserT st e r
p = (ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e r)
-> ParserT st e r
forall (st :: ZeroBitType) e a.
(ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e a)
-> ParserT st e a
ParserT \ForeignPtrContents
fp Addr#
eob Addr#
buf st
st -> case Int#
8# Int# -> Int# -> Int#
<=# Addr# -> Addr# -> Int#
minusAddr# Addr#
eob Addr#
buf of
  Int#
0# -> st -> Res# st e r
forall (st :: ZeroBitType) e a. st -> Res# st e a
Fail# st
st
  Int#
_  -> let w# :: Word#
w# = Addr# -> Int# -> Word#
indexWordOffAddr# Addr#
buf Int#
0#
        in  ParserT st e r
-> ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e r
forall (st :: ZeroBitType) e a.
ParserT st e a
-> ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e a
runParserT# (Word -> ParserT st e r
p (Word# -> Word
W# Word#
w#)) ForeignPtrContents
fp Addr#
eob (Addr# -> Int# -> Addr#
plusAddr# Addr#
buf Int#
8#) st
st
{-# inline withAnyWord #-}

-- -- TODO assumes 64-bit platform
-- | Parse any 'Int' (native size) (CPS).
withAnyInt :: (Int -> ParserT st e r) -> ParserT st e r
withAnyInt :: forall (st :: ZeroBitType) e r.
(Int -> ParserT st e r) -> ParserT st e r
withAnyInt Int -> ParserT st e r
p = (ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e r)
-> ParserT st e r
forall (st :: ZeroBitType) e a.
(ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e a)
-> ParserT st e a
ParserT \ForeignPtrContents
fp Addr#
eob Addr#
buf st
st -> case Int#
8# Int# -> Int# -> Int#
<=# Addr# -> Addr# -> Int#
minusAddr# Addr#
eob Addr#
buf of
  Int#
0# -> st -> Res# st e r
forall (st :: ZeroBitType) e a. st -> Res# st e a
Fail# st
st
  Int#
_  -> let i# :: Int#
i# = Addr# -> Int# -> Int#
indexIntOffAddr# Addr#
buf Int#
0#
        in  ParserT st e r
-> ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e r
forall (st :: ZeroBitType) e a.
ParserT st e a
-> ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e a
runParserT# (Int -> ParserT st e r
p (Int# -> Int
I# Int#
i#)) ForeignPtrContents
fp Addr#
eob (Addr# -> Int# -> Addr#
plusAddr# Addr#
buf Int#
8#) st
st
{-# inline withAnyInt #-}

--------------------------------------------------------------------------------

-- | Parse any 'Word8'.
anyWord8 :: ParserT st e Word8
anyWord8 :: forall (st :: ZeroBitType) e. ParserT st e Word8
anyWord8 = (Word8 -> ParserT st e Word8) -> ParserT st e Word8
forall (st :: ZeroBitType) e r.
(Word8 -> ParserT st e r) -> ParserT st e r
withAnyWord8 Word8 -> ParserT st e Word8
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
{-# inline anyWord8 #-}

-- | Parse any 'Word16' (native byte order).
anyWord16 :: ParserT st e Word16
anyWord16 :: forall (st :: ZeroBitType) e. ParserT st e Word16
anyWord16 = (Word16 -> ParserT st e Word16) -> ParserT st e Word16
forall (st :: ZeroBitType) e r.
(Word16 -> ParserT st e r) -> ParserT st e r
withAnyWord16 Word16 -> ParserT st e Word16
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
{-# inline anyWord16 #-}

-- | Parse any 'Word32' (native byte order).
anyWord32 :: ParserT st e Word32
anyWord32 :: forall (st :: ZeroBitType) e. ParserT st e Word32
anyWord32 = (Word32 -> ParserT st e Word32) -> ParserT st e Word32
forall (st :: ZeroBitType) e r.
(Word32 -> ParserT st e r) -> ParserT st e r
withAnyWord32 Word32 -> ParserT st e Word32
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
{-# inline anyWord32 #-}

-- | Parse any 'Word64' (native byte order).
anyWord64 :: ParserT st e Word64
anyWord64 :: forall (st :: ZeroBitType) e. ParserT st e Word64
anyWord64 = (Word64 -> ParserT st e Word64) -> ParserT st e Word64
forall (st :: ZeroBitType) e r.
(Word64 -> ParserT st e r) -> ParserT st e r
withAnyWord64 Word64 -> ParserT st e Word64
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
{-# inline anyWord64 #-}

-- | Parse any 'Int8'.
anyInt8 :: ParserT st e Int8
anyInt8 :: forall (st :: ZeroBitType) e. ParserT st e Int8
anyInt8 = (Int8 -> ParserT st e Int8) -> ParserT st e Int8
forall (st :: ZeroBitType) e r.
(Int8 -> ParserT st e r) -> ParserT st e r
withAnyInt8 Int8 -> ParserT st e Int8
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
{-# inline anyInt8 #-}

-- | Parse any 'Int16' (native byte order).
anyInt16 :: ParserT st e Int16
anyInt16 :: forall (st :: ZeroBitType) e. ParserT st e Int16
anyInt16 = (Int16 -> ParserT st e Int16) -> ParserT st e Int16
forall (st :: ZeroBitType) e r.
(Int16 -> ParserT st e r) -> ParserT st e r
withAnyInt16 Int16 -> ParserT st e Int16
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
{-# inline anyInt16 #-}

-- | Parse any 'Int32' (native byte order).
anyInt32 :: ParserT st e Int32
anyInt32 :: forall (st :: ZeroBitType) e. ParserT st e Int32
anyInt32 = (Int32 -> ParserT st e Int32) -> ParserT st e Int32
forall (st :: ZeroBitType) e r.
(Int32 -> ParserT st e r) -> ParserT st e r
withAnyInt32 Int32 -> ParserT st e Int32
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
{-# inline anyInt32 #-}

-- | Parse any 'Int64' (native byte order).
anyInt64 :: ParserT st e Int64
anyInt64 :: forall (st :: ZeroBitType) e. ParserT st e Int64
anyInt64 = (Int64 -> ParserT st e Int64) -> ParserT st e Int64
forall (st :: ZeroBitType) e r.
(Int64 -> ParserT st e r) -> ParserT st e r
withAnyInt64 Int64 -> ParserT st e Int64
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
{-# inline anyInt64 #-}

-- TODO 'withAnyWord' assumes 64-bit platform
-- | Parse any 'Word' (native size).
anyWord :: ParserT st e Word
anyWord :: forall (st :: ZeroBitType) e. ParserT st e Word
anyWord = (Word -> ParserT st e Word) -> ParserT st e Word
forall (st :: ZeroBitType) e r.
(Word -> ParserT st e r) -> ParserT st e r
withAnyWord Word -> ParserT st e Word
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
{-# inline anyWord #-}

-- TODO 'withAnyInt' assumes 64-bit platform
-- | Parse any 'Int' (native size).
anyInt :: ParserT st e Int
anyInt :: forall (st :: ZeroBitType) e. ParserT st e Int
anyInt = (Int -> ParserT st e Int) -> ParserT st e Int
forall (st :: ZeroBitType) e r.
(Int -> ParserT st e r) -> ParserT st e r
withAnyInt Int -> ParserT st e Int
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
{-# inline anyInt #-}

--------------------------------------------------------------------------------

{- $explicit-endianness
Native endianness parsers are used where possible. For non-native endianness
parsers, we parse then use the corresponding @byteSwapX@ function. On x86, this
is inlined as a single @BSWAP@ instruction.
-}

-- | Parse any 'Word16' (little-endian).
anyWord16le :: ParserT st e Word16
#ifdef WORDS_BIGENDIAN
anyWord16le = withAnyWord16 (pure . byteSwap16)
#else
anyWord16le :: forall (st :: ZeroBitType) e. ParserT st e Word16
anyWord16le = ParserT st e Word16
forall (st :: ZeroBitType) e. ParserT st e Word16
anyWord16
#endif
{-# inline anyWord16le #-}

-- | Parse any 'Word16' (big-endian).
anyWord16be :: ParserT st e Word16
#ifdef WORDS_BIGENDIAN
anyWord16be = anyWord16
#else
anyWord16be :: forall (st :: ZeroBitType) e. ParserT st e Word16
anyWord16be = (Word16 -> ParserT st e Word16) -> ParserT st e Word16
forall (st :: ZeroBitType) e r.
(Word16 -> ParserT st e r) -> ParserT st e r
withAnyWord16 (Word16 -> ParserT st e Word16
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word16 -> ParserT st e Word16)
-> (Word16 -> Word16) -> Word16 -> ParserT st e Word16
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word16 -> Word16
byteSwap16)
#endif
{-# inline anyWord16be #-}

-- | Parse any 'Word32' (little-endian).
anyWord32le :: ParserT st e Word32
#ifdef WORDS_BIGENDIAN
anyWord32le = withAnyWord32 (pure . byteSwap32)
#else
anyWord32le :: forall (st :: ZeroBitType) e. ParserT st e Word32
anyWord32le = ParserT st e Word32
forall (st :: ZeroBitType) e. ParserT st e Word32
anyWord32
#endif
{-# inline anyWord32le #-}

-- | Parse any 'Word32' (big-endian).
anyWord32be :: ParserT st e Word32
#ifdef WORDS_BIGENDIAN
anyWord32be = anyWord32
#else
anyWord32be :: forall (st :: ZeroBitType) e. ParserT st e Word32
anyWord32be = (Word32 -> ParserT st e Word32) -> ParserT st e Word32
forall (st :: ZeroBitType) e r.
(Word32 -> ParserT st e r) -> ParserT st e r
withAnyWord32 (Word32 -> ParserT st e Word32
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word32 -> ParserT st e Word32)
-> (Word32 -> Word32) -> Word32 -> ParserT st e Word32
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> Word32
byteSwap32)
#endif
{-# inline anyWord32be #-}

-- | Parse any 'Word64' (little-endian).
anyWord64le :: ParserT st e Word64
#ifdef WORDS_BIGENDIAN
anyWord64le = withAnyWord64 (pure . byteSwap64)
#else
anyWord64le :: forall (st :: ZeroBitType) e. ParserT st e Word64
anyWord64le = ParserT st e Word64
forall (st :: ZeroBitType) e. ParserT st e Word64
anyWord64
#endif
{-# inline anyWord64le #-}

-- | Parse any 'Word64' (big-endian).
anyWord64be :: ParserT st e Word64
#ifdef WORDS_BIGENDIAN
anyWord64be = anyWord64
#else
anyWord64be :: forall (st :: ZeroBitType) e. ParserT st e Word64
anyWord64be = (Word64 -> ParserT st e Word64) -> ParserT st e Word64
forall (st :: ZeroBitType) e r.
(Word64 -> ParserT st e r) -> ParserT st e r
withAnyWord64 (Word64 -> ParserT st e Word64
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word64 -> ParserT st e Word64)
-> (Word64 -> Word64) -> Word64 -> ParserT st e Word64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Word64
byteSwap64)
#endif
{-# inline anyWord64be #-}

-- | Parse any 'Int16' (little-endian).
anyInt16le :: ParserT st e Int16
#ifdef WORDS_BIGENDIAN
anyInt16le = withAnyWord16 (pure . word16ToInt16 . byteSwap16)
#else
anyInt16le :: forall (st :: ZeroBitType) e. ParserT st e Int16
anyInt16le = ParserT st e Int16
forall (st :: ZeroBitType) e. ParserT st e Int16
anyInt16
#endif
{-# inline anyInt16le #-}

-- | Parse any 'Int16' (big-endian).
anyInt16be :: ParserT st e Int16
#ifdef WORDS_BIGENDIAN
anyInt16be = anyInt16
#else
anyInt16be :: forall (st :: ZeroBitType) e. ParserT st e Int16
anyInt16be = (Word16 -> ParserT st e Int16) -> ParserT st e Int16
forall (st :: ZeroBitType) e r.
(Word16 -> ParserT st e r) -> ParserT st e r
withAnyWord16 (Int16 -> ParserT st e Int16
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int16 -> ParserT st e Int16)
-> (Word16 -> Int16) -> Word16 -> ParserT st e Int16
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word16 -> Int16
word16ToInt16 (Word16 -> Int16) -> (Word16 -> Word16) -> Word16 -> Int16
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word16 -> Word16
byteSwap16)
#endif
{-# inline anyInt16be #-}

-- | Parse any 'Int32' (little-endian).
anyInt32le :: ParserT st e Int32
#ifdef WORDS_BIGENDIAN
anyInt32le = withAnyWord32 (pure . word32ToInt32 . byteSwap32)
#else
anyInt32le :: forall (st :: ZeroBitType) e. ParserT st e Int32
anyInt32le = ParserT st e Int32
forall (st :: ZeroBitType) e. ParserT st e Int32
anyInt32
#endif
{-# inline anyInt32le #-}

-- | Parse any 'Int32' (big-endian).
anyInt32be :: ParserT st e Int32
#ifdef WORDS_BIGENDIAN
anyInt32be = anyInt32
#else
anyInt32be :: forall (st :: ZeroBitType) e. ParserT st e Int32
anyInt32be = (Word32 -> ParserT st e Int32) -> ParserT st e Int32
forall (st :: ZeroBitType) e r.
(Word32 -> ParserT st e r) -> ParserT st e r
withAnyWord32 (Int32 -> ParserT st e Int32
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int32 -> ParserT st e Int32)
-> (Word32 -> Int32) -> Word32 -> ParserT st e Int32
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> Int32
word32ToInt32 (Word32 -> Int32) -> (Word32 -> Word32) -> Word32 -> Int32
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> Word32
byteSwap32)
#endif
{-# inline anyInt32be #-}

-- | Parse any 'Int64' (little-endian).
anyInt64le :: ParserT st e Int64
#ifdef WORDS_BIGENDIAN
anyInt64le = withAnyWord64 (pure . word64ToInt64 . byteSwap64)
#else
anyInt64le :: forall (st :: ZeroBitType) e. ParserT st e Int64
anyInt64le = ParserT st e Int64
forall (st :: ZeroBitType) e. ParserT st e Int64
anyInt64
#endif
{-# inline anyInt64le #-}

-- | Parse any 'Int64' (big-endian).
anyInt64be :: ParserT st e Int64
#ifdef WORDS_BIGENDIAN
anyInt64be = anyInt64
#else
anyInt64be :: forall (st :: ZeroBitType) e. ParserT st e Int64
anyInt64be = (Word64 -> ParserT st e Int64) -> ParserT st e Int64
forall (st :: ZeroBitType) e r.
(Word64 -> ParserT st e r) -> ParserT st e r
withAnyWord64 (Int64 -> ParserT st e Int64
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int64 -> ParserT st e Int64)
-> (Word64 -> Int64) -> Word64 -> ParserT st e Int64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Int64
word64ToInt64 (Word64 -> Int64) -> (Word64 -> Word64) -> Word64 -> Int64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Word64
byteSwap64)
#endif
{-# inline anyInt64be #-}

--------------------------------------------------------------------------------

-- | Read the next 1 byte and assert its value as a 'Word8'.
word8 :: Word8 -> ParserT st e ()
word8 :: forall (st :: ZeroBitType) e. Word8 -> ParserT st e ()
word8 Word8
wExpected = (ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e ())
-> ParserT st e ()
forall (st :: ZeroBitType) e a.
(ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e a)
-> ParserT st e a
ParserT \ForeignPtrContents
fp Addr#
eob Addr#
buf st
st -> case Addr# -> Addr# -> Int#
eqAddr# Addr#
eob Addr#
buf of
  Int#
1# -> st -> Res# st e ()
forall (st :: ZeroBitType) e a. st -> Res# st e a
Fail# st
st
  Int#
_  -> let w# :: Word8#
w# = Addr# -> Int# -> Word8#
indexWord8OffAddr# Addr#
buf Int#
0#
        in  if   Word8# -> Word8
W8# Word8#
w# Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
wExpected
            then st -> () -> Addr# -> Res# st e ()
forall (st :: ZeroBitType) a e. st -> a -> Addr# -> Res# st e a
OK# st
st () (Addr# -> Int# -> Addr#
plusAddr# Addr#
buf Int#
1#)
            else st -> Res# st e ()
forall (st :: ZeroBitType) e a. st -> Res# st e a
Fail# st
st
{-# inline word8 #-}

--------------------------------------------------------------------------------

{- $unsafe
These unsafe parsers and helpers may be useful for efficient parsing in special
situations e.g. you already know that the input has enough bytes. You should
only use them if you can assert their necessary guarantees (see the individual
function documentation).
-}

-- | Unsafe helper for defining parsers for types of a constant byte size (i.e.
--   machine integers) which assert the parsed value's... value.
--
-- Call this with an @indexXYZOffAddr@ primop (e.g.
-- 'GHC.Exts.indexWord8OffAddr'), the size in bytes of the type you're parsing,
-- and the expected value to test the parsed value against.
--
-- The caller must guarantee that the input has enough bytes.
sizedUnsafe# :: Eq a => Int# -> (Addr# -> Int# -> a) -> a -> ParserT st e ()
sizedUnsafe# :: forall a (st :: ZeroBitType) e.
Eq a =>
Int# -> (Addr# -> Int# -> a) -> a -> ParserT st e ()
sizedUnsafe# Int#
size# Addr# -> Int# -> a
indexOffAddr a
aExpected =
    Int#
-> (Addr# -> Int# -> a)
-> (a -> ParserT st e ())
-> ParserT st e ()
forall a (st :: ZeroBitType) e r.
Int#
-> (Addr# -> Int# -> a) -> (a -> ParserT st e r) -> ParserT st e r
withAnySizedUnsafe# Int#
size# Addr# -> Int# -> a
indexOffAddr a -> ParserT st e ()
forall {f :: * -> *}. Alternative f => a -> f ()
go
  where
    go :: a -> f ()
go a
aParsed =
        if   a
aParsed a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
aExpected
        then () -> f ()
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
        else f ()
forall a. f a
forall (f :: * -> *) a. Alternative f => f a
empty
{-# inline sizedUnsafe# #-}

-- | Unsafely read the next 1 byte and assert its value as a 'Word8'.
--
-- The caller must guarantee that the input has enough bytes.
word8Unsafe :: Word8 -> ParserT st e ()
word8Unsafe :: forall (st :: ZeroBitType) e. Word8 -> ParserT st e ()
word8Unsafe = Int# -> (Addr# -> Int# -> Word8) -> Word8 -> ParserT st e ()
forall a (st :: ZeroBitType) e.
Eq a =>
Int# -> (Addr# -> Int# -> a) -> a -> ParserT st e ()
sizedUnsafe# Int#
1# (\Addr#
a Int#
i -> Word8# -> Word8
W8# (Addr# -> Int# -> Word8#
indexWord8OffAddr# Addr#
a Int#
i))
{-# inline word8Unsafe #-}

-- | Unsafely read the next 2 bytes and assert their value as a 'Word16'
--   (native byte order).
--
-- The caller must guarantee that the input has enough bytes.
word16Unsafe :: Word16 -> ParserT st e ()
word16Unsafe :: forall (st :: ZeroBitType) e. Word16 -> ParserT st e ()
word16Unsafe = Int# -> (Addr# -> Int# -> Word16) -> Word16 -> ParserT st e ()
forall a (st :: ZeroBitType) e.
Eq a =>
Int# -> (Addr# -> Int# -> a) -> a -> ParserT st e ()
sizedUnsafe# Int#
2# (\Addr#
a Int#
i -> Word16# -> Word16
W16# (Addr# -> Int# -> Word16#
indexWord16OffAddr# Addr#
a Int#
i))
{-# inline word16Unsafe #-}

-- | Unsafely read the next 4 bytes and assert their value as a 'Word32'.
--   (native byte order).
--
-- The caller must guarantee that the input has enough bytes.
word32Unsafe :: Word32 -> ParserT st e ()
word32Unsafe :: forall (st :: ZeroBitType) e. Word32 -> ParserT st e ()
word32Unsafe = Int# -> (Addr# -> Int# -> Word32) -> Word32 -> ParserT st e ()
forall a (st :: ZeroBitType) e.
Eq a =>
Int# -> (Addr# -> Int# -> a) -> a -> ParserT st e ()
sizedUnsafe# Int#
4# (\Addr#
a Int#
i -> Word32# -> Word32
W32# (Addr# -> Int# -> Word32#
indexWord32OffAddr# Addr#
a Int#
i))
{-# inline word32Unsafe #-}

-- | Unsafely read the next 8 bytes and assert their value as a 'Word64'.
--   (native byte order).
--
-- The caller must guarantee that the input has enough bytes.
word64Unsafe :: Word64 -> ParserT st e ()
word64Unsafe :: forall (st :: ZeroBitType) e. Word64 -> ParserT st e ()
word64Unsafe = Int# -> (Addr# -> Int# -> Word64) -> Word64 -> ParserT st e ()
forall a (st :: ZeroBitType) e.
Eq a =>
Int# -> (Addr# -> Int# -> a) -> a -> ParserT st e ()
sizedUnsafe# Int#
8# (\Addr#
a Int#
i -> Word64# -> Word64
W64# (Addr# -> Int# -> Word64#
indexWord64OffAddr# Addr#
a Int#
i))
{-# inline word64Unsafe #-}

--------------------------------------------------------------------------------

-- | Unsafely parse any 'Word8', without asserting the input is non-empty.
--
-- The caller must guarantee that the input has enough bytes.
anyWord8Unsafe :: ParserT st e Word8
anyWord8Unsafe :: forall (st :: ZeroBitType) e. ParserT st e Word8
anyWord8Unsafe = Int#
-> (Addr# -> Int# -> Word8)
-> (Word8 -> ParserT st e Word8)
-> ParserT st e Word8
forall a (st :: ZeroBitType) e r.
Int#
-> (Addr# -> Int# -> a) -> (a -> ParserT st e r) -> ParserT st e r
withAnySizedUnsafe# Int#
1# (\Addr#
a Int#
i -> Word8# -> Word8
W8# (Addr# -> Int# -> Word8#
indexWord8OffAddr# Addr#
a Int#
i)) Word8 -> ParserT st e Word8
forall a. a -> ParserT st e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
{-# inline anyWord8Unsafe #-}