{-# language BangPatterns #-}
{-# language BinaryLiterals #-}
{-# language DataKinds #-}
{-# language DeriveFunctor #-}
{-# language DerivingStrategies #-}
{-# language GADTSyntax #-}
{-# language KindSignatures #-}
{-# language LambdaCase #-}
{-# language MagicHash #-}
{-# language MultiWayIf #-}
{-# language NamedFieldPuns #-}
{-# language PolyKinds #-}
{-# language RankNTypes #-}
{-# language ScopedTypeVariables #-}
{-# language StandaloneDeriving #-}
{-# language TypeApplications #-}
{-# language UnboxedSums #-}
{-# language UnboxedTuples #-}
module Data.Bytes.Parser.Internal
( Parser(..)
, InternalResult(..)
, InternalStep(..)
, Bytes#
, ST#
, Result#
, unfailing
, uneffectful
, uneffectful#
, uneffectfulInt#
, boxBytes
, unboxBytes
, unboxResult
, fail
, indexLatinCharArray
, upcastUnitSuccess
, swapArray16
, swapArray32
, swapArray64
, swapArray128
, swapArray256
) where
import Prelude hiding (length,any,fail,takeWhile)
import Control.Applicative (Alternative)
import Control.Monad.ST.Run (runByteArrayST)
import Data.Primitive (ByteArray(ByteArray))
import Data.Bytes.Types (Bytes(..))
import Data.Kind (Type)
import Data.Word (Word8)
import GHC.Exts (TYPE,RuntimeRep,Int(I#),Int#,State#,ByteArray#,Char(C#))
import qualified Control.Applicative
import qualified Control.Monad
import qualified Data.Primitive as PM
import qualified GHC.Exts as Exts
newtype Parser :: forall (r :: RuntimeRep). Type -> Type -> TYPE r -> Type where
Parser :: forall (r :: RuntimeRep) (e :: Type) (s :: Type) (a :: TYPE r).
{ runParser :: (# ByteArray#, Int#, Int# #) -> ST# s (Result# e a) } -> Parser e s a
data InternalResult e a
= InternalFailure e
| InternalSuccess !a !Int !Int
data InternalStep a = InternalStep !a !Int !Int
uneffectful :: (Bytes -> InternalResult e a) -> Parser e s a
{-# inline uneffectful #-}
uneffectful f = Parser
( \b s0 -> (# s0, unboxResult (f (boxBytes b)) #) )
unfailing :: (Bytes -> InternalStep a) -> Parser e s a
{-# inline unfailing #-}
unfailing f = Parser
( \b s0 -> (# s0, case f (boxBytes b) of { InternalStep a (I# off) (I# len) -> (# | (# a, off, len #) #) } #) )
boxBytes :: Bytes# -> Bytes
{-# inline boxBytes #-}
boxBytes (# a, b, c #) = Bytes (ByteArray a) (I# b) (I# c)
unboxBytes :: Bytes -> Bytes#
{-# inline unboxBytes #-}
unboxBytes (Bytes (ByteArray a) (I# b) (I# c)) = (# a,b,c #)
type Bytes# = (# ByteArray#, Int#, Int# #)
type ST# s (a :: TYPE r) = State# s -> (# State# s, a #)
type Result# e (a :: TYPE r) =
(# e
| (# a, Int#, Int# #) #)
unboxResult :: InternalResult e a -> Result# e a
unboxResult (InternalSuccess a (I# b) (I# c)) = (# | (# a, b, c #) #)
unboxResult (InternalFailure e) = (# e | #)
instance Monoid e => Alternative (Parser e s) where
{-# inline empty #-}
{-# inline (<|>) #-}
empty = fail mempty
Parser f <|> Parser g = Parser
(\x s0 -> case f x s0 of
(# s1, r0 #) -> case r0 of
(# eRight | #) -> case g x s1 of
(# s2, r1 #) -> case r1 of
(# eLeft | #) -> (# s2, (# eRight <> eLeft | #) #)
(# | r #) -> (# s2, (# | r #) #)
(# | r #) -> (# s1, (# | r #) #)
)
fail ::
e
-> Parser e s a
fail e = uneffectful $ \_ -> InternalFailure e
instance Applicative (Parser e s) where
pure = pureParser
(<*>) = Control.Monad.ap
instance Monad (Parser e s) where
{-# inline return #-}
{-# inline (>>=) #-}
return = pureParser
(>>=) = bindParser
instance Functor (Parser e s) where
{-# inline fmap #-}
fmap f (Parser g) = Parser
(\x s0 -> case g x s0 of
(# s1, r #) -> case r of
(# e | #) -> (# s1, (# e | #) #)
(# | (# a, b, c #) #) -> (# s1, (# | (# f a, b, c #) #) #)
)
indexLatinCharArray :: ByteArray -> Int -> Char
{-# inline indexLatinCharArray #-}
indexLatinCharArray (ByteArray arr) (I# off) =
C# (Exts.indexCharArray# arr off)
uneffectful# :: (Bytes -> Result# e a) -> Parser e s a
{-# inline uneffectful# #-}
uneffectful# f = Parser
( \b s0 -> (# s0, (f (boxBytes b)) #) )
uneffectfulInt# :: (Bytes -> Result# e Int# ) -> Parser e s Int#
{-# inline uneffectfulInt# #-}
uneffectfulInt# f = Parser
( \b s0 -> (# s0, (f (boxBytes b)) #) )
upcastUnitSuccess :: (# Int#, Int# #) -> Result# e ()
{-# inline upcastUnitSuccess #-}
upcastUnitSuccess (# b, c #) = (# | (# (), b, c #) #)
swapArray16 :: Bytes -> ByteArray
swapArray16 (Bytes{array,offset,length}) = runByteArrayST $ do
dst <- PM.newByteArray length
let go !ixSrc !ixDst !len = if len > 0
then do
let v0 = PM.indexByteArray array ixSrc :: Word8
v1 = PM.indexByteArray array (ixSrc + 1) :: Word8
PM.writeByteArray dst ixDst v1
PM.writeByteArray dst (ixDst + 1) v0
go (ixSrc + 2) (ixDst + 2) (len - 2)
else pure ()
go offset 0 length
PM.unsafeFreezeByteArray dst
swapArray32 :: Bytes -> ByteArray
swapArray32 (Bytes{array,offset,length}) = runByteArrayST $ do
dst <- PM.newByteArray length
let go !ixSrc !ixDst !len = if len > 0
then do
let v0 = PM.indexByteArray array ixSrc :: Word8
v1 = PM.indexByteArray array (ixSrc + 1) :: Word8
v2 = PM.indexByteArray array (ixSrc + 2) :: Word8
v3 = PM.indexByteArray array (ixSrc + 3) :: Word8
PM.writeByteArray dst ixDst v3
PM.writeByteArray dst (ixDst + 1) v2
PM.writeByteArray dst (ixDst + 2) v1
PM.writeByteArray dst (ixDst + 3) v0
go (ixSrc + 4) (ixDst + 4) (len - 4)
else pure ()
go offset 0 length
PM.unsafeFreezeByteArray dst
swapArray64 :: Bytes -> ByteArray
swapArray64 (Bytes{array,offset,length}) = runByteArrayST $ do
dst <- PM.newByteArray length
let go !ixSrc !ixDst !len = if len > 0
then do
let v0 = PM.indexByteArray array ixSrc :: Word8
v1 = PM.indexByteArray array (ixSrc + 1) :: Word8
v2 = PM.indexByteArray array (ixSrc + 2) :: Word8
v3 = PM.indexByteArray array (ixSrc + 3) :: Word8
v4 = PM.indexByteArray array (ixSrc + 4) :: Word8
v5 = PM.indexByteArray array (ixSrc + 5) :: Word8
v6 = PM.indexByteArray array (ixSrc + 6) :: Word8
v7 = PM.indexByteArray array (ixSrc + 7) :: Word8
PM.writeByteArray dst ixDst v7
PM.writeByteArray dst (ixDst + 1) v6
PM.writeByteArray dst (ixDst + 2) v5
PM.writeByteArray dst (ixDst + 3) v4
PM.writeByteArray dst (ixDst + 4) v3
PM.writeByteArray dst (ixDst + 5) v2
PM.writeByteArray dst (ixDst + 6) v1
PM.writeByteArray dst (ixDst + 7) v0
go (ixSrc + 8) (ixDst + 8) (len - 8)
else pure ()
go offset 0 length
PM.unsafeFreezeByteArray dst
swapArray128 :: Bytes -> ByteArray
swapArray128 (Bytes{array,offset,length}) = runByteArrayST $ do
dst <- PM.newByteArray length
let go !ixSrc !ixDst !len = if len > 0
then do
let v0 = PM.indexByteArray array ixSrc :: Word8
v1 = PM.indexByteArray array (ixSrc + 1) :: Word8
v2 = PM.indexByteArray array (ixSrc + 2) :: Word8
v3 = PM.indexByteArray array (ixSrc + 3) :: Word8
v4 = PM.indexByteArray array (ixSrc + 4) :: Word8
v5 = PM.indexByteArray array (ixSrc + 5) :: Word8
v6 = PM.indexByteArray array (ixSrc + 6) :: Word8
v7 = PM.indexByteArray array (ixSrc + 7) :: Word8
v8 = PM.indexByteArray array (ixSrc + 8) :: Word8
v9 = PM.indexByteArray array (ixSrc + 9) :: Word8
v10 = PM.indexByteArray array (ixSrc + 10) :: Word8
v11 = PM.indexByteArray array (ixSrc + 11) :: Word8
v12 = PM.indexByteArray array (ixSrc + 12) :: Word8
v13 = PM.indexByteArray array (ixSrc + 13) :: Word8
v14 = PM.indexByteArray array (ixSrc + 14) :: Word8
v15 = PM.indexByteArray array (ixSrc + 15) :: Word8
PM.writeByteArray dst ixDst v15
PM.writeByteArray dst (ixDst + 1) v14
PM.writeByteArray dst (ixDst + 2) v13
PM.writeByteArray dst (ixDst + 3) v12
PM.writeByteArray dst (ixDst + 4) v11
PM.writeByteArray dst (ixDst + 5) v10
PM.writeByteArray dst (ixDst + 6) v9
PM.writeByteArray dst (ixDst + 7) v8
PM.writeByteArray dst (ixDst + 8) v7
PM.writeByteArray dst (ixDst + 9) v6
PM.writeByteArray dst (ixDst + 10) v5
PM.writeByteArray dst (ixDst + 11) v4
PM.writeByteArray dst (ixDst + 12) v3
PM.writeByteArray dst (ixDst + 13) v2
PM.writeByteArray dst (ixDst + 14) v1
PM.writeByteArray dst (ixDst + 15) v0
go (ixSrc + 16) (ixDst + 16) (len - 16)
else pure ()
go offset 0 length
PM.unsafeFreezeByteArray dst
swapArray256 :: Bytes -> ByteArray
swapArray256 (Bytes{array,offset,length}) = runByteArrayST $ do
dst <- PM.newByteArray length
let go !ixSrc !ixDst !len = if len > 0
then do
let loop !i
| i < 32 = do
let v = PM.indexByteArray array (ixSrc + i) :: Word8
PM.writeByteArray dst (ixDst + (31 - i)) v
loop (i + 1)
| otherwise = pure ()
loop 0
go (ixSrc + 32) (ixDst + 32) (len - 32)
else pure ()
go offset 0 length
PM.unsafeFreezeByteArray dst
pureParser :: a -> Parser e s a
{-# inline pureParser #-}
pureParser a = Parser
(\(# _, b, c #) s -> (# s, (# | (# a, b, c #) #) #))
bindParser :: Parser e s a -> (a -> Parser e s b) -> Parser e s b
{-# inline bindParser #-}
bindParser (Parser f) g = Parser
(\x@(# arr, _, _ #) s0 -> case f x s0 of
(# s1, r0 #) -> case r0 of
(# e | #) -> (# s1, (# e | #) #)
(# | (# y, b, c #) #) ->
runParser (g y) (# arr, b, c #) s1
)