{-# language BangPatterns #-}
{-# language BinaryLiterals #-}
{-# language DataKinds #-}
{-# language DeriveFunctor #-}
{-# language DerivingStrategies #-}
{-# language GADTSyntax #-}
{-# language KindSignatures #-}
{-# language LambdaCase #-}
{-# language MagicHash #-}
{-# language MultiWayIf #-}
{-# language PolyKinds #-}
{-# language RankNTypes #-}
{-# language ScopedTypeVariables #-}
{-# language StandaloneDeriving #-}
{-# language TypeApplications #-}
{-# language UnboxedSums #-}
{-# language UnboxedTuples #-}

-- | Little-endian fixed-width numbers.
module Data.Bytes.Parser.LittleEndian
  ( -- * One
    -- ** Unsigned
    word8
  , word16
  , word32
  , word64
  , word128
  , word256
    -- ** Signed
  , int8
  , int16
  , int32
  , int64
    -- * Many
    -- ** Unsigned
  , word16Array
  , word32Array
  , word64Array
  , word128Array
  , word256Array
    -- ** Unsigned
  , int64Array
  ) where

import Prelude hiding (length,any,fail,takeWhile)

import Control.Applicative (liftA2)
import Data.Bits ((.|.),unsafeShiftL)
import Data.Primitive (ByteArray(..),PrimArray(..))
import Data.Bytes.Types (Bytes(..))
import Data.Bytes.Parser.Internal (Parser,uneffectful)
import Data.Bytes.Parser.Internal (Result(..))
import Data.Bytes.Parser.Internal (swapArray16,swapArray32)
import Data.Bytes.Parser.Internal (swapArray64,swapArray128,swapArray256)
import Data.Word (Word8,Word16,Word32,Word64)
import Data.Int (Int8,Int16,Int32,Int64)
import Data.WideWord (Word128(Word128),Word256(Word256))
import GHC.ByteOrder (ByteOrder(LittleEndian,BigEndian),targetByteOrder)

import qualified Data.Bytes as Bytes
import qualified Data.Bytes.Parser as P
import qualified Data.Primitive as PM

-- | Unsigned 8-bit word.
word8 :: e -> Parser e s Word8
word8 :: forall e s. e -> Parser e s Word8
word8 = forall e s. e -> Parser e s Word8
P.any

-- | Array of little-endian unsigned 16-bit words. If the host is
-- little-endian, the implementation is optimized to simply @memcpy@
-- bytes into the result array. The result array always has elements
-- in native-endian byte order.
word16Array ::
     e -- ^ Error message if not enough bytes are present
  -> Int -- ^ Number of little-endian 16-bit words to expect
  -> Parser e s (PrimArray Word16) -- ^ Native-endian elements
word16Array :: forall e s. e -> Int -> Parser e s (PrimArray Word16)
word16Array e
e !Int
n = case ByteOrder
targetByteOrder of
  ByteOrder
LittleEndian -> forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ByteArray -> PrimArray Word16
asWord16s forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes -> ByteArray
Bytes.toByteArrayClone) (forall e s. e -> Int -> Parser e s Bytes
P.take e
e (Int
n forall a. Num a => a -> a -> a
* Int
2))
  ByteOrder
BigEndian -> do
    Bytes
bs <- forall e s. e -> Int -> Parser e s Bytes
P.take e
e (Int
n forall a. Num a => a -> a -> a
* Int
2)
    let r :: ByteArray
r = Bytes -> ByteArray
swapArray16 Bytes
bs
    forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteArray -> PrimArray Word16
asWord16s ByteArray
r)

-- | Parse an array of little-endian unsigned 32-bit words.
word32Array ::
     e -- ^ Error message if not enough bytes are present
  -> Int -- ^ Number of little-endian 32-bit words to consume
  -> Parser e s (PrimArray Word32) -- ^ Native-endian elements
word32Array :: forall e s. e -> Int -> Parser e s (PrimArray Word32)
word32Array e
e !Int
n = case ByteOrder
targetByteOrder of
  ByteOrder
LittleEndian -> forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ByteArray -> PrimArray Word32
asWord32s forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes -> ByteArray
Bytes.toByteArrayClone) (forall e s. e -> Int -> Parser e s Bytes
P.take e
e (Int
n forall a. Num a => a -> a -> a
* Int
4))
  ByteOrder
BigEndian -> do
    Bytes
bs <- forall e s. e -> Int -> Parser e s Bytes
P.take e
e (Int
n forall a. Num a => a -> a -> a
* Int
4)
    let r :: ByteArray
r = Bytes -> ByteArray
swapArray32 Bytes
bs
    forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteArray -> PrimArray Word32
asWord32s ByteArray
r)

-- | Parse an array of little-endian unsigned 64-bit words.
word64Array ::
     e -- ^ Error message if not enough bytes are present
  -> Int -- ^ Number of little-endian 64-bit words to consume
  -> Parser e s (PrimArray Word64) -- ^ Native-endian elements
word64Array :: forall e s. e -> Int -> Parser e s (PrimArray Word64)
word64Array e
e !Int
n = case ByteOrder
targetByteOrder of
  ByteOrder
LittleEndian -> forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ByteArray -> PrimArray Word64
asWord64s forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes -> ByteArray
Bytes.toByteArrayClone) (forall e s. e -> Int -> Parser e s Bytes
P.take e
e (Int
n forall a. Num a => a -> a -> a
* Int
8))
  ByteOrder
BigEndian -> do
    Bytes
bs <- forall e s. e -> Int -> Parser e s Bytes
P.take e
e (Int
n forall a. Num a => a -> a -> a
* Int
8)
    let r :: ByteArray
r = Bytes -> ByteArray
swapArray64 Bytes
bs
    forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteArray -> PrimArray Word64
asWord64s ByteArray
r)

-- | Parse an array of little-endian unsigned 128-bit words.
word128Array ::
     e -- ^ Error message if not enough bytes are present
  -> Int -- ^ Number of little-endian 128-bit words to consume
  -> Parser e s (PrimArray Word128) -- ^ Native-endian elements
word128Array :: forall e s. e -> Int -> Parser e s (PrimArray Word128)
word128Array e
e !Int
n = case ByteOrder
targetByteOrder of
  ByteOrder
LittleEndian -> forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ByteArray -> PrimArray Word128
asWord128s forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes -> ByteArray
Bytes.toByteArrayClone) (forall e s. e -> Int -> Parser e s Bytes
P.take e
e (Int
n forall a. Num a => a -> a -> a
* Int
16))
  ByteOrder
BigEndian -> do
    Bytes
bs <- forall e s. e -> Int -> Parser e s Bytes
P.take e
e (Int
n forall a. Num a => a -> a -> a
* Int
16)
    let r :: ByteArray
r = Bytes -> ByteArray
swapArray128 Bytes
bs
    forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteArray -> PrimArray Word128
asWord128s ByteArray
r)

-- | Parse an array of little-endian unsigned 256-bit words.
word256Array ::
     e -- ^ Error message if not enough bytes are present
  -> Int -- ^ Number of little-endian 256-bit words to consume
  -> Parser e s (PrimArray Word256) -- ^ Native-endian elements
word256Array :: forall e s. e -> Int -> Parser e s (PrimArray Word256)
word256Array e
e !Int
n = case ByteOrder
targetByteOrder of
  ByteOrder
LittleEndian -> forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ByteArray -> PrimArray Word256
asWord256s forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes -> ByteArray
Bytes.toByteArrayClone) (forall e s. e -> Int -> Parser e s Bytes
P.take e
e (Int
n forall a. Num a => a -> a -> a
* Int
32))
  ByteOrder
BigEndian -> do
    Bytes
bs <- forall e s. e -> Int -> Parser e s Bytes
P.take e
e (Int
n forall a. Num a => a -> a -> a
* Int
32)
    let r :: ByteArray
r = Bytes -> ByteArray
swapArray256 Bytes
bs
    forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteArray -> PrimArray Word256
asWord256s ByteArray
r)

-- | Parse an array of little-endian signed 64-bit words.
int64Array ::
     e -- ^ Error message if not enough bytes are present
  -> Int -- ^ Number of little-endian 64-bit words to expect
  -> Parser e s (PrimArray Int64) -- ^ Native-endian elements
int64Array :: forall e s. e -> Int -> Parser e s (PrimArray Int64)
int64Array e
e !Int
n = do
  PrimArray ByteArray#
x <- forall e s. e -> Int -> Parser e s (PrimArray Word64)
word64Array e
e Int
n
  forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall a. ByteArray# -> PrimArray a
PrimArray ByteArray#
x)

asWord16s :: ByteArray -> PrimArray Word16
asWord16s :: ByteArray -> PrimArray Word16
asWord16s (ByteArray ByteArray#
x) = forall a. ByteArray# -> PrimArray a
PrimArray ByteArray#
x

asWord32s :: ByteArray -> PrimArray Word32
asWord32s :: ByteArray -> PrimArray Word32
asWord32s (ByteArray ByteArray#
x) = forall a. ByteArray# -> PrimArray a
PrimArray ByteArray#
x

asWord64s :: ByteArray -> PrimArray Word64
asWord64s :: ByteArray -> PrimArray Word64
asWord64s (ByteArray ByteArray#
x) = forall a. ByteArray# -> PrimArray a
PrimArray ByteArray#
x

asWord128s :: ByteArray -> PrimArray Word128
asWord128s :: ByteArray -> PrimArray Word128
asWord128s (ByteArray ByteArray#
x) = forall a. ByteArray# -> PrimArray a
PrimArray ByteArray#
x

asWord256s :: ByteArray -> PrimArray Word256
asWord256s :: ByteArray -> PrimArray Word256
asWord256s (ByteArray ByteArray#
x) = forall a. ByteArray# -> PrimArray a
PrimArray ByteArray#
x

-- | Unsigned 16-bit word.
word16 :: e -> Parser e s Word16
word16 :: forall e s. e -> Parser e s Word16
word16 e
e = forall e a s. (Bytes -> Result e a) -> Parser e s a
uneffectful forall a b. (a -> b) -> a -> b
$ \Bytes
chunk -> if Bytes -> Int
length Bytes
chunk forall a. Ord a => a -> a -> Bool
>= Int
2
  then
    let wa :: Word8
wa = forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray (Bytes -> ByteArray
array Bytes
chunk) (Bytes -> Int
offset Bytes
chunk) :: Word8
        wb :: Word8
wb = forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray (Bytes -> ByteArray
array Bytes
chunk) (Bytes -> Int
offset Bytes
chunk forall a. Num a => a -> a -> a
+ Int
1) :: Word8
     in forall e a. a -> Int -> Int -> Result e a
Success
          (forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word @Word16 (forall a. Bits a => a -> Int -> a
unsafeShiftL (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
wb) Int
8 forall a. Bits a => a -> a -> a
.|. forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
wa))
          (Bytes -> Int
offset Bytes
chunk forall a. Num a => a -> a -> a
+ Int
2) (Bytes -> Int
length Bytes
chunk forall a. Num a => a -> a -> a
- Int
2)
  else forall e a. e -> Result e a
Failure e
e

-- | Unsigned 32-bit word.
word32 :: e -> Parser e s Word32
word32 :: forall e s. e -> Parser e s Word32
word32 e
e = forall e a s. (Bytes -> Result e a) -> Parser e s a
uneffectful forall a b. (a -> b) -> a -> b
$ \Bytes
chunk -> if Bytes -> Int
length Bytes
chunk forall a. Ord a => a -> a -> Bool
>= Int
4
  then
    let wa :: Word8
wa = forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray (Bytes -> ByteArray
array Bytes
chunk) (Bytes -> Int
offset Bytes
chunk) :: Word8
        wb :: Word8
wb = forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray (Bytes -> ByteArray
array Bytes
chunk) (Bytes -> Int
offset Bytes
chunk forall a. Num a => a -> a -> a
+ Int
1) :: Word8
        wc :: Word8
wc = forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray (Bytes -> ByteArray
array Bytes
chunk) (Bytes -> Int
offset Bytes
chunk forall a. Num a => a -> a -> a
+ Int
2) :: Word8
        wd :: Word8
wd = forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray (Bytes -> ByteArray
array Bytes
chunk) (Bytes -> Int
offset Bytes
chunk forall a. Num a => a -> a -> a
+ Int
3) :: Word8
     in forall e a. a -> Int -> Int -> Result e a
Success
          (forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word @Word32
            ( forall a. Bits a => a -> Int -> a
unsafeShiftL (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
wd) Int
24 forall a. Bits a => a -> a -> a
.|.
              forall a. Bits a => a -> Int -> a
unsafeShiftL (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
wc) Int
16 forall a. Bits a => a -> a -> a
.|.
              forall a. Bits a => a -> Int -> a
unsafeShiftL (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
wb) Int
8 forall a. Bits a => a -> a -> a
.|.
              forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
wa
            )
          )
          (Bytes -> Int
offset Bytes
chunk forall a. Num a => a -> a -> a
+ Int
4) (Bytes -> Int
length Bytes
chunk forall a. Num a => a -> a -> a
- Int
4)
  else forall e a. e -> Result e a
Failure e
e

-- | Unsigned 64-bit word.
word64 :: e -> Parser e s Word64
word64 :: forall e s. e -> Parser e s Word64
word64 e
e = forall e a s. (Bytes -> Result e a) -> Parser e s a
uneffectful forall a b. (a -> b) -> a -> b
$ \Bytes
chunk -> if Bytes -> Int
length Bytes
chunk forall a. Ord a => a -> a -> Bool
>= Int
8
  then
    let wa :: Word8
wa = forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray (Bytes -> ByteArray
array Bytes
chunk) (Bytes -> Int
offset Bytes
chunk) :: Word8
        wb :: Word8
wb = forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray (Bytes -> ByteArray
array Bytes
chunk) (Bytes -> Int
offset Bytes
chunk forall a. Num a => a -> a -> a
+ Int
1) :: Word8
        wc :: Word8
wc = forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray (Bytes -> ByteArray
array Bytes
chunk) (Bytes -> Int
offset Bytes
chunk forall a. Num a => a -> a -> a
+ Int
2) :: Word8
        wd :: Word8
wd = forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray (Bytes -> ByteArray
array Bytes
chunk) (Bytes -> Int
offset Bytes
chunk forall a. Num a => a -> a -> a
+ Int
3) :: Word8
        we :: Word8
we = forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray (Bytes -> ByteArray
array Bytes
chunk) (Bytes -> Int
offset Bytes
chunk forall a. Num a => a -> a -> a
+ Int
4) :: Word8
        wf :: Word8
wf = forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray (Bytes -> ByteArray
array Bytes
chunk) (Bytes -> Int
offset Bytes
chunk forall a. Num a => a -> a -> a
+ Int
5) :: Word8
        wg :: Word8
wg = forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray (Bytes -> ByteArray
array Bytes
chunk) (Bytes -> Int
offset Bytes
chunk forall a. Num a => a -> a -> a
+ Int
6) :: Word8
        wh :: Word8
wh = forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray (Bytes -> ByteArray
array Bytes
chunk) (Bytes -> Int
offset Bytes
chunk forall a. Num a => a -> a -> a
+ Int
7) :: Word8
     in forall e a. a -> Int -> Int -> Result e a
Success
          ( forall a. Bits a => a -> Int -> a
unsafeShiftL (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
wh) Int
56 forall a. Bits a => a -> a -> a
.|.
            forall a. Bits a => a -> Int -> a
unsafeShiftL (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
wg) Int
48 forall a. Bits a => a -> a -> a
.|.
            forall a. Bits a => a -> Int -> a
unsafeShiftL (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
wf) Int
40 forall a. Bits a => a -> a -> a
.|.
            forall a. Bits a => a -> Int -> a
unsafeShiftL (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
we) Int
32 forall a. Bits a => a -> a -> a
.|.
            forall a. Bits a => a -> Int -> a
unsafeShiftL (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
wd) Int
24 forall a. Bits a => a -> a -> a
.|.
            forall a. Bits a => a -> Int -> a
unsafeShiftL (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
wc) Int
16 forall a. Bits a => a -> a -> a
.|.
            forall a. Bits a => a -> Int -> a
unsafeShiftL (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
wb) Int
8 forall a. Bits a => a -> a -> a
.|.
            forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
wa
          )
          (Bytes -> Int
offset Bytes
chunk forall a. Num a => a -> a -> a
+ Int
8) (Bytes -> Int
length Bytes
chunk forall a. Num a => a -> a -> a
- Int
8)
  else forall e a. e -> Result e a
Failure e
e

-- | Unsigned 256-bit word.
word256 :: e -> Parser e s Word256
word256 :: forall e s. e -> Parser e s Word256
word256 e
e = (\Word64
d Word64
c Word64
b Word64
a -> Word64 -> Word64 -> Word64 -> Word64 -> Word256
Word256 Word64
a Word64
b Word64
c Word64
d) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall e s. e -> Parser e s Word64
word64 e
e forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall e s. e -> Parser e s Word64
word64 e
e forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall e s. e -> Parser e s Word64
word64 e
e forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall e s. e -> Parser e s Word64
word64 e
e

-- | Unsigned 128-bit word.
word128 :: e -> Parser e s Word128
word128 :: forall e s. e -> Parser e s Word128
word128 e
e = forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 (forall a b c. (a -> b -> c) -> b -> a -> c
flip Word64 -> Word64 -> Word128
Word128) (forall e s. e -> Parser e s Word64
word64 e
e) (forall e s. e -> Parser e s Word64
word64 e
e)

-- | Signed 8-bit integer.
int8 :: e -> Parser e s Int8
int8 :: forall e s. e -> Parser e s Int8
int8 = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e s. e -> Parser e s Word8
word8

-- | Signed 16-bit integer.
int16 :: e -> Parser e s Int16
int16 :: forall e s. e -> Parser e s Int16
int16 = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e s. e -> Parser e s Word16
word16

-- | Signed 32-bit integer.
int32 :: e -> Parser e s Int32
int32 :: forall e s. e -> Parser e s Int32
int32 = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e s. e -> Parser e s Word32
word32

-- | Signed 64-bit integer.
int64 :: e -> Parser e s Int64
int64 :: forall e s. e -> Parser e s Int64
int64 = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e s. e -> Parser e s Word64
word64