bytesmith 0.3.7.0 → 0.3.8.0
raw patch · 10 files changed
+238/−116 lines, 10 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.Bytes.Parser.Latin: peek :: Parser e s (Maybe Char)
+ Data.Bytes.Parser.Latin: peek' :: e -> Parser e s Char
+ Data.Bytes.Parser.Rebindable: instance Data.Bytes.Parser.Rebindable.Bind 'GHC.Types.WordRep 'GHC.Types.LiftedRep
+ Data.Bytes.Parser.Unsafe: uneffectful :: (Bytes -> Result e a) -> Parser e s a
Files
- CHANGELOG.md +8/−0
- bytesmith.cabal +2/−2
- src/Data/Bytes/Parser.hs +48/−21
- src/Data/Bytes/Parser/Ascii.hs +23/−14
- src/Data/Bytes/Parser/BigEndian.hs +7/−7
- src/Data/Bytes/Parser/Internal.hs +11/−9
- src/Data/Bytes/Parser/Latin.hs +96/−47
- src/Data/Bytes/Parser/LittleEndian.hs +7/−7
- src/Data/Bytes/Parser/Rebindable.hs +27/−0
- src/Data/Bytes/Parser/Unsafe.hs +9/−9
CHANGELOG.md view
@@ -1,5 +1,13 @@ # Revision history for bytesmith +## 0.3.8.0 -- 2021-10-11++* Add `peek` and `peek'` to `Data.Bytes.Parser.Latin`.+* Add inline pragmas to most functions to prevent cost centers.+* Add support for WordRep-to-LiftedRep in Rebindable module.+* Allow building with newer Contiguous.+* Export `uneffectful`.+ ## 0.3.7.0 -- 2020-07-27 * Add `Data.Bytes.Parser.Base128` module for Base-128 encoding.
bytesmith.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: bytesmith-version: 0.3.7.0+version: 0.3.8.0 synopsis: Nonresumable byte parser description: Parse bytes as fast as possible. This is a nonresumable parser@@ -35,7 +35,7 @@ , base >=4.12 && <5 , bytestring >=0.10.8 && <0.11 , byteslice >=0.1.4 && <0.3- , contiguous >= 0.4 && < 0.6+ , contiguous >= 0.4 && < 0.7 , primitive >=0.7 && <0.8 , text-short >=0.1.3 && <0.2 , run-st >=0.1 && <0.2
src/Data/Bytes/Parser.hs view
@@ -100,7 +100,7 @@ import Prelude hiding (length,any,fail,takeWhile,take,replicate) -import Data.Bytes.Parser.Internal (InternalResult(..),Parser(..),ST#,unboxBytes)+import Data.Bytes.Parser.Internal (Parser(..),ST#,unboxBytes) import Data.Bytes.Parser.Internal (boxBytes,Result#,uneffectful,fail) import Data.Bytes.Parser.Internal (uneffectful#,uneffectfulInt#) import Data.Bytes.Parser.Types (Result(Failure,Success),Slice(Slice))@@ -114,6 +114,7 @@ import Data.Primitive.Contiguous (Contiguous,Element) import qualified Data.Bytes as B+import qualified Data.Bytes.Parser.Internal as Internal import qualified Data.Primitive as PM import qualified Data.Primitive.Contiguous as C import qualified GHC.Exts as Exts@@ -121,6 +122,7 @@ -- | Parse a byte sequence. This can succeed even if the -- entire slice was not consumed by the parser. parseBytes :: forall e a. (forall s. Parser e s a) -> Bytes -> Result e a+{-# inline parseBytes #-} parseBytes p !b = runResultST action where action :: forall s. ST# s (Result# e a)@@ -131,6 +133,7 @@ -- Just like 'parseBytesEither', this does not impose any checks on the length -- of the remaining input. parseBytesMaybe :: forall e a. (forall s. Parser e s a) -> Bytes -> Maybe a+{-# inline parseBytesMaybe #-} parseBytesMaybe p !b = runMaybeST action where action :: forall s. ST# s (Result# e a)@@ -141,6 +144,7 @@ -- remaining length. This does not, however, require the remaining -- length to be zero. Use 'endOfInput' to accomplish that. parseBytesEither :: forall e a. (forall s. Parser e s a) -> Bytes -> Either e a+{-# inline parseBytesEither #-} parseBytesEither p !b = runEitherST action where action :: forall s. ST# s (Result# e a)@@ -149,12 +153,14 @@ -- Similar to runResultST runMaybeST :: (forall s. ST# s (Result# e x)) -> Maybe x+{-# inline runMaybeST #-} runMaybeST f = case (runRW# (\s0 -> case f s0 of { (# _, r #) -> r })) of (# _ | #) -> Nothing (# | (# x, _, _ #) #) -> Just x -- Similar to runResultST runEitherST :: (forall s. ST# s (Result# e x)) -> Either e x+{-# inline runEitherST #-} runEitherST f = case (runRW# (\s0 -> case f s0 of { (# _, r #) -> r })) of (# e | #) -> Left e (# | (# x, _, _ #) #) -> Right x@@ -165,18 +171,21 @@ -- it avoids the additional boxing that the Success data -- constructor would normally cause. runResultST :: (forall s. ST# s (Result# e x)) -> Result e x+{-# inline runResultST #-} runResultST f = case (runRW# (\s0 -> case f s0 of { (# _, r #) -> r })) of (# e | #) -> Failure e (# | (# x, off, len #) #) -> Success (Slice (I# off) (I# len) x) -- | Variant of 'parseBytes' that accepts an unsliced 'ByteArray'. parseByteArray :: (forall s. Parser e s a) -> ByteArray -> Result e a+{-# inline parseByteArray #-} parseByteArray p b = parseBytes p (Bytes b 0 (PM.sizeofByteArray b)) -- | Variant of 'parseBytes' that allows the parser to be run -- as part of an existing effectful context. parseBytesEffectfully :: Parser e s a -> Bytes -> ST s (Result e a)+{-# inline parseBytesEffectfully #-} parseBytesEffectfully (Parser f) !b = ST (\s0 -> case f (unboxBytes b) s0 of (# s1, r #) -> (# s1, boxPublicResult r #)@@ -184,12 +193,14 @@ -- | Lift an effectful computation into a parser. effect :: ST s a -> Parser e s a+{-# inline effect #-} effect (ST f) = Parser ( \(# _, off, len #) s0 -> case f s0 of (# s1, a #) -> (# s1, (# | (# a, off, len #) #) #) ) byteArray :: e -> ByteArray -> Parser e s ()+{-# inline byteArray #-} byteArray e !expected = bytes e (B.fromByteArray expected) -- | Consume input matching the byte sequence.@@ -235,8 +246,8 @@ any e = uneffectful $ \chunk -> if length chunk > 0 then let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8- in InternalSuccess w (offset chunk + 1) (length chunk - 1)- else InternalFailure e+ in Internal.Success w (offset chunk + 1) (length chunk - 1)+ else Internal.Failure e -- | Match any byte, to perform lookahead. Returns 'Nothing' if -- end of input has been reached. Does not consume any input.@@ -246,18 +257,20 @@ -- because such parsers loop until a failure occurs. Careless -- use will thus result in an infinite loop. peek :: Parser e s (Maybe Word8)+{-# inline peek #-} peek = uneffectful $ \chunk -> let v = if length chunk > 0 then Just (B.unsafeIndex chunk 0) else Nothing- in InternalSuccess v (offset chunk) (length chunk)+ in Internal.Success v (offset chunk) (length chunk) -- | Match any byte, to perform lookahead. Does not consume any -- input, but will fail if end of input has been reached. peek' :: e -> Parser e s Word8+{-# inline peek' #-} peek' e = uneffectful $ \chunk -> if length chunk > 0- then InternalSuccess (B.unsafeIndex chunk 0) (offset chunk) (length chunk)- else InternalFailure e+ then Internal.Success (B.unsafeIndex chunk 0) (offset chunk) (length chunk)+ else Internal.Failure e -- | A stateful scanner. The predicate consumes and transforms a -- state argument, and each transformed state is passed to@@ -271,6 +284,7 @@ -- combinators such a 'many', because such parsers loop until a -- failure occurs. Careless use will thus result in an infinite loop. scan :: state -> (state -> Word8 -> Maybe state) -> Parser e s state+{-# inline scan #-} scan s0 t = do let go s = do mw <- peek@@ -288,13 +302,14 @@ {-# inline anyUnsafe #-} anyUnsafe = uneffectful $ \chunk -> let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8- in InternalSuccess w (offset chunk + 1) (length chunk - 1)+ in Internal.Success w (offset chunk + 1) (length chunk - 1) --- | Take while the predicate is matched. This is always inlined.+-- | Take while the predicate is matched. This is always inlined. This+-- always succeeds. takeWhile :: (Word8 -> Bool) -> Parser e s Bytes {-# inline takeWhile #-} takeWhile f = uneffectful $ \chunk -> case B.takeWhile f chunk of- bs -> InternalSuccess bs (offset chunk + length bs) (length chunk - length bs)+ bs -> Internal.Success bs (offset chunk + length bs) (length chunk - length bs) -- | Take bytes until the specified byte is encountered. Consumes -- the matched byte as well. Fails if the byte is not present.@@ -315,6 +330,7 @@ -- | Skip all characters until the character from the is encountered -- and then consume the matching byte as well. skipTrailedBy :: e -> Word8 -> Parser e s ()+{-# inline skipTrailedBy #-} skipTrailedBy e !w = uneffectful# (\c -> skipUntilConsumeByteLoop e w c) skipUntilConsumeByteLoop ::@@ -337,6 +353,7 @@ -> Word8 -- ^ First trailer, @False@ indicates that this was encountered -> Word8 -- ^ Second trailer, @True@ indicates that this was encountered -> Parser e s Bool+{-# inline skipTrailedBy2 #-} skipTrailedBy2 e !wa !wb = boxBool (skipTrailedBy2# e wa wb) skipTrailedBy2# ::@@ -344,6 +361,7 @@ -> Word8 -- ^ First trailer, 0 indicates that this was encountered -> Word8 -- ^ Second trailer, 1 indicates that this was encountered -> Parser e s Int#+{-# inline skipTrailedBy2# #-} skipTrailedBy2# e !wa !wb = uneffectfulInt# (\c -> skipUntilConsumeByteEitherLoop e wa wb c) @@ -353,6 +371,7 @@ -> Word8 -- ^ Second trailer, 1 indicates that this was encountered -> Word8 -- ^ Third trailer, 2 indicates that this was encountered -> Parser e s Int#+{-# inline skipTrailedBy3# #-} skipTrailedBy3# e !wa !wb !wc = uneffectfulInt# (\c -> skipUntilConsumeByte3Loop e wa wb wc c) @@ -390,20 +409,20 @@ {-# inline take #-} take e n = uneffectful $ \chunk -> if n <= B.length chunk then case B.unsafeTake n chunk of- bs -> InternalSuccess bs (offset chunk + n) (length chunk - n)- else InternalFailure e+ bs -> Internal.Success bs (offset chunk + n) (length chunk - n)+ else Internal.Failure e -- | Consume all remaining bytes in the input. remaining :: Parser e s Bytes {-# inline remaining #-} remaining = uneffectful $ \chunk ->- InternalSuccess chunk (offset chunk + length chunk) 0+ Internal.Success chunk (offset chunk + length chunk) 0 -- | Return all remaining bytes in the input without consuming them. peekRemaining :: Parser e s Bytes {-# inline peekRemaining #-} peekRemaining = uneffectful $ \b@(Bytes _ off len) ->- InternalSuccess b off len+ Internal.Success b off len -- | Skip while the predicate is matched. This is always inlined. skipWhile :: (Word8 -> Bool) -> Parser e s ()@@ -428,35 +447,38 @@ -- if the predicate @p@ returns 'True' on the transformed value. -- The parser returns the transformed byte that was parsed. satisfyWith :: e -> (Word8 -> a) -> (a -> Bool) -> Parser e s a+{-# inline satisfyWith #-} satisfyWith e f p = uneffectful $ \chunk -> if length chunk > 1 then case B.unsafeIndex chunk 1 of w -> let v = f w in if p v- then InternalSuccess v (offset chunk + 1) (length chunk - 1)- else InternalFailure e- else InternalFailure e+ then Internal.Success v (offset chunk + 1) (length chunk - 1)+ else Internal.Failure e+ else Internal.Failure e -- | Fails if there is still more input remaining. endOfInput :: e -> Parser e s ()--- GHC should decide to inline this after optimization.+{-# inline endOfInput #-} endOfInput e = uneffectful $ \chunk -> if length chunk == 0- then InternalSuccess () (offset chunk) 0- else InternalFailure e+ then Internal.Success () (offset chunk) 0+ else Internal.Failure e -- | Returns true if there are no more bytes in the input. Returns -- false otherwise. Always succeeds. isEndOfInput :: Parser e s Bool--- GHC should decide to inline this after optimization.+{-# inline isEndOfInput #-} isEndOfInput = uneffectful $ \chunk ->- InternalSuccess (length chunk == 0) (offset chunk) (length chunk)+ Internal.Success (length chunk == 0) (offset chunk) (length chunk) boxPublicResult :: Result# e a -> Result e a+{-# inline boxPublicResult #-} boxPublicResult (# | (# a, b, c #) #) = Success (Slice (I# b) (I# c) a) boxPublicResult (# e | #) = Failure e -- | Convert a 'Word32' parser to a 'Word#' parser. unboxWord32 :: Parser e s Word32 -> Parser e s Word#+{-# inline unboxWord32 #-} unboxWord32 (Parser f) = Parser (\x s0 -> case f x s0 of (# s1, r #) -> case r of@@ -466,6 +488,7 @@ -- | Convert a @(Int,Int)@ parser to a @(# Int#, Int# #)@ parser. unboxIntPair :: Parser e s (Int,Int) -> Parser e s (# Int#, Int# #)+{-# inline unboxIntPair #-} unboxIntPair (Parser f) = Parser (\x s0 -> case f x s0 of (# s1, r #) -> case r of@@ -476,6 +499,7 @@ -- | Convert a 'Word#' parser to a 'Word32' parser. Precondition: -- the argument parser only returns words less than 4294967296. boxWord32 :: Parser e s Word# -> Parser e s Word32+{-# inline boxWord32 #-} boxWord32 (Parser f) = Parser (\x s0 -> case f x s0 of (# s1, r #) -> case r of@@ -505,6 +529,7 @@ -- | Convert a @(# Int#, Int# #)@ parser to a @(Int,Int)@ parser. boxIntPair :: Parser e s (# Int#, Int# #) -> Parser e s (Int,Int)+{-# inline boxIntPair #-} boxIntPair (Parser f) = Parser (\x s0 -> case f x s0 of (# s1, r #) -> case r of@@ -664,6 +689,7 @@ -> Int -- ^ Exact number of bytes delimited parser is expected to consume -> Parser e s a -- ^ Parser to execute in delimited context -> Parser e s a+{-# inline delimit #-} delimit esz eleftovers (I# n) (Parser f) = Parser ( \(# arr, off, len #) s0 -> case len >=# n of 1# -> case f (# arr, off, n #) s0 of@@ -696,4 +722,5 @@ go 0 unI :: Int -> Int#+{-# inline unI #-} unI (I# w) = w
src/Data/Bytes/Parser/Ascii.hs view
@@ -57,7 +57,7 @@ import Data.Bits (clearBit) import Data.Bytes.Types (Bytes(..)) import Data.Bytes.Parser.Internal (Parser(..),uneffectful,Result#,uneffectful#)-import Data.Bytes.Parser.Internal (InternalResult(..),indexLatinCharArray,upcastUnitSuccess)+import Data.Bytes.Parser.Internal (Result(..),indexLatinCharArray,upcastUnitSuccess) import Data.Char (ord) import Data.Word (Word8) import Data.Text.Short (ShortText)@@ -79,11 +79,12 @@ -- Precondition: The argument must be a letter (@[a-zA-Z]@). Behavior is -- undefined if it is not. charInsensitive :: e -> Char -> Parser e s ()+{-# inline charInsensitive #-} charInsensitive e !c = uneffectful $ \chunk -> if length chunk > 0 then if clearBit (PM.indexByteArray (array chunk) (offset chunk) :: Word8) 5 == w- then InternalSuccess () (offset chunk + 1) (length chunk - 1)- else InternalFailure e- else InternalFailure e+ then Success () (offset chunk + 1) (length chunk - 1)+ else Failure e+ else Failure e where w = clearBit (fromIntegral @Int @Word8 (ord c)) 5 @@ -91,6 +92,7 @@ -- the trailer as well. This fails if the trailer is not -- found or if any non-ASCII characters are encountered. skipTrailedBy :: e -> Char -> Parser e s ()+{-# inline skipTrailedBy #-} skipTrailedBy e !c = do let go = do !d <- any e@@ -142,13 +144,14 @@ -- | Consumes and returns the next character in the input. any :: e -> Parser e s Char+{-# inline any #-} any e = uneffectful $ \chunk -> if length chunk > 0 then let c = indexLatinCharArray (array chunk) (offset chunk) in if c < '\128'- then InternalSuccess c (offset chunk + 1) (length chunk - 1)- else InternalFailure e- else InternalFailure e+ then Success c (offset chunk + 1) (length chunk - 1)+ else Failure e+ else Failure e -- | Variant of 'any' with unboxed result. any# :: e -> Parser e s Char#@@ -164,22 +167,24 @@ ) unI :: Int -> Int#+{-# inline unI #-} unI (I# w) = w -- | Examine the next byte without consuming it, interpret it as an -- ASCII-encoded character. This fails if the byte is above @0x7F@ or -- if the end of input has been reached. peek :: e -> Parser e s Char+{-# inline peek #-} peek e = uneffectful $ \chunk -> if length chunk > 0 then let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8 in if w < 128- then InternalSuccess+ then Success (C# (chr# (unI (fromIntegral w)))) (offset chunk) (length chunk)- else InternalFailure e- else InternalFailure e+ else Failure e+ else Failure e -- | Consume the next byte, interpreting it as an ASCII-encoded character. -- Fails if the byte is above @0x7F@. Returns @Nothing@ if the@@ -190,12 +195,12 @@ then let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8 in if w < 128- then InternalSuccess+ then Success (Just (C# (chr# (unI (fromIntegral w))))) (offset chunk + 1) (length chunk - 1)- else InternalFailure e- else InternalSuccess Nothing (offset chunk) (length chunk)+ else Failure e+ else Success Nothing (offset chunk) (length chunk) -- | Consume characters matching the predicate. The stops when it -- encounters a non-matching character or when it encounters a byte@@ -218,18 +223,21 @@ -- | Skip uppercase and lowercase letters until a non-alpha -- character is encountered. skipAlpha :: Parser e s ()+{-# inline skipAlpha #-} skipAlpha = uneffectful# $ \c -> upcastUnitSuccess (skipAlphaAsciiLoop c) -- | Skip uppercase and lowercase letters until a non-alpha -- character is encountered. skipAlpha1 :: e -> Parser e s ()+{-# inline skipAlpha1 #-} skipAlpha1 e = uneffectful# $ \c -> skipAlphaAsciiLoop1Start e c skipAlphaAsciiLoop :: Bytes -- Chunk -> (# Int#, Int# #)+{-# inline skipAlphaAsciiLoop #-} skipAlphaAsciiLoop !c = if length c > 0 then let w = indexLatinCharArray (array c) (offset c)@@ -242,6 +250,7 @@ e -> Bytes -- chunk -> Result# e ()+{-# inline skipAlphaAsciiLoop1Start #-} skipAlphaAsciiLoop1Start e !c = if length c > 0 then let w = indexLatinCharArray (array c) (offset c)@@ -251,5 +260,5 @@ else (# e | #) byteArrayToShortByteString :: PM.ByteArray -> BSS.ShortByteString+{-# inline byteArrayToShortByteString #-} byteArrayToShortByteString (PM.ByteArray x) = BSS.SBS x-
src/Data/Bytes/Parser/BigEndian.hs view
@@ -45,7 +45,7 @@ import Data.Bits ((.|.),unsafeShiftL) import Data.Bytes.Types (Bytes(..)) import Data.Bytes.Parser.Internal (Parser,uneffectful)-import Data.Bytes.Parser.Internal (InternalResult(..))+import Data.Bytes.Parser.Internal (Result(..)) import Data.Bytes.Parser.Internal (swapArray16,swapArray32,swapArray64,swapArray256) import Data.Bytes.Parser.Internal (swapArray128) import Data.Word (Word8,Word16,Word32,Word64)@@ -146,10 +146,10 @@ then let wa = PM.indexByteArray (array chunk) (offset chunk) :: Word8 wb = PM.indexByteArray (array chunk) (offset chunk + 1) :: Word8- in InternalSuccess+ in Success (fromIntegral @Word @Word16 (unsafeShiftL (fromIntegral wa) 8 .|. fromIntegral wb)) (offset chunk + 2) (length chunk - 2)- else InternalFailure e+ else Failure e -- | Unsigned 32-bit word. word32 :: e -> Parser e s Word32@@ -159,7 +159,7 @@ wb = PM.indexByteArray (array chunk) (offset chunk + 1) :: Word8 wc = PM.indexByteArray (array chunk) (offset chunk + 2) :: Word8 wd = PM.indexByteArray (array chunk) (offset chunk + 3) :: Word8- in InternalSuccess+ in Success (fromIntegral @Word @Word32 ( unsafeShiftL (fromIntegral wa) 24 .|. unsafeShiftL (fromIntegral wb) 16 .|.@@ -168,7 +168,7 @@ ) ) (offset chunk + 4) (length chunk - 4)- else InternalFailure e+ else Failure e -- | Unsigned 64-bit word. word64 :: e -> Parser e s Word64@@ -182,7 +182,7 @@ wf = PM.indexByteArray (array chunk) (offset chunk + 5) :: Word8 wg = PM.indexByteArray (array chunk) (offset chunk + 6) :: Word8 wh = PM.indexByteArray (array chunk) (offset chunk + 7) :: Word8- in InternalSuccess+ in Success ( unsafeShiftL (fromIntegral wa) 56 .|. unsafeShiftL (fromIntegral wb) 48 .|. unsafeShiftL (fromIntegral wc) 40 .|.@@ -193,7 +193,7 @@ fromIntegral wh ) (offset chunk + 8) (length chunk - 8)- else InternalFailure e+ else Failure e -- | Unsigned 128-bit word. word128 :: e -> Parser e s Word128
src/Data/Bytes/Parser/Internal.hs view
@@ -19,7 +19,7 @@ module Data.Bytes.Parser.Internal ( Parser(..)- , InternalResult(..)+ , Result(..) , InternalStep(..) , Bytes# , ST#@@ -63,16 +63,16 @@ { runParser :: (# ByteArray#, Int#, Int# #) -> ST# s (Result# e a) } -> Parser e s a -- The result of running a parser. Used internally.-data InternalResult e a- = InternalFailure e+data Result e a+ = Failure e -- An error message indicating what went wrong.- | InternalSuccess !a !Int !Int+ | Success !a !Int !Int -- The parsed value, the offset after the last consumed byte, and the -- number of bytes remaining in parsed slice. data InternalStep a = InternalStep !a !Int !Int -uneffectful :: (Bytes -> InternalResult e a) -> Parser e s a+uneffectful :: (Bytes -> Result e a) -> Parser e s a {-# inline uneffectful #-} uneffectful f = Parser ( \b s0 -> (# s0, unboxResult (f (boxBytes b)) #) )@@ -98,9 +98,10 @@ (# e | (# a, Int#, Int# #) #) -- ints are offset and length -unboxResult :: InternalResult e a -> Result# e a-unboxResult (InternalSuccess a (I# b) (I# c)) = (# | (# a, b, c #) #)-unboxResult (InternalFailure e) = (# e | #)+unboxResult :: Result e a -> Result# e a+{-# inline unboxResult #-}+unboxResult (Success a (I# b) (I# c)) = (# | (# a, b, c #) #)+unboxResult (Failure e) = (# e | #) -- | Combines the error messages using '<>' when both -- parsers fail.@@ -122,7 +123,8 @@ fail :: e -- ^ Error message -> Parser e s a-fail e = uneffectful $ \_ -> InternalFailure e+{-# inline fail #-}+fail e = uneffectful $ \_ -> Failure e instance Applicative (Parser e s) where pure = pureParser
src/Data/Bytes/Parser/Latin.hs view
@@ -43,6 +43,9 @@ , opt# -- * Many Characters , takeTrailedBy+ -- * Lookahead+ , peek+ , peek' -- * Skip , skipDigits , skipDigits1@@ -94,7 +97,7 @@ import Data.Bytes.Types (Bytes(..)) import Data.Bytes.Parser.Internal (InternalStep(..),unfailing) import Data.Bytes.Parser.Internal (Parser(..),ST#,uneffectful,Result#,uneffectful#)-import Data.Bytes.Parser.Internal (InternalResult(..),indexLatinCharArray,upcastUnitSuccess)+import Data.Bytes.Parser.Internal (Result(..),indexLatinCharArray,upcastUnitSuccess) import Data.Bytes.Parser.Internal (boxBytes) import Data.Bytes.Parser (bindFromLiftedToInt,isEndOfInput,endOfInput) import Data.Bytes.Parser.Unsafe (expose,cursor,unconsume)@@ -116,10 +119,10 @@ -- of the input has been reached. This never fails. trySatisfy :: (Char -> Bool) -> Parser e s Bool trySatisfy f = uneffectful $ \chunk -> case length chunk of- 0 -> InternalSuccess False (offset chunk) (length chunk)+ 0 -> Success False (offset chunk) (length chunk) _ -> case f (indexLatinCharArray (array chunk) (offset chunk)) of- True -> InternalSuccess True (offset chunk + 1) (length chunk - 1)- False -> InternalSuccess False (offset chunk) (length chunk)+ True -> Success True (offset chunk + 1) (length chunk - 1)+ False -> Success False (offset chunk) (length chunk) -- | Runs the function on the next character in the input. If the -- function returns @Just@, this consumes the character and then@@ -144,58 +147,59 @@ -- | Consume the next character, failing if it does not -- match the expected value or if there is no more input. char :: e -> Char -> Parser e s ()--- GHC should decide to inline this after optimization.+{-# inline char #-} char e !c = uneffectful $ \chunk -> if length chunk > 0 then if indexLatinCharArray (array chunk) (offset chunk) == c- then InternalSuccess () (offset chunk + 1) (length chunk - 1)- else InternalFailure e- else InternalFailure e+ then Success () (offset chunk + 1) (length chunk - 1)+ else Failure e+ else Failure e -- | Consume the next two characters, failing if they do -- not match the expected values. -- -- > char2 e a b === char e a *> char e b char2 :: e -> Char -> Char -> Parser e s ()--- GHC should decide to inline this after optimization.+{-# inline char2 #-} char2 e !c0 !c1 = uneffectful $ \chunk -> if | length chunk > 1 , indexLatinCharArray (array chunk) (offset chunk) == c0 , indexLatinCharArray (array chunk) (offset chunk + 1) == c1- -> InternalSuccess () (offset chunk + 2) (length chunk - 2)- | otherwise -> InternalFailure e+ -> Success () (offset chunk + 2) (length chunk - 2)+ | otherwise -> Failure e -- | Consume three characters, failing if they do -- not match the expected values. -- -- > char3 e a b c === char e a *> char e b *> char e c char3 :: e -> Char -> Char -> Char -> Parser e s ()--- GHC should decide to inline this after optimization.+{-# inline char3 #-} char3 e !c0 !c1 !c2 = uneffectful $ \chunk -> if | length chunk > 2 , indexLatinCharArray (array chunk) (offset chunk) == c0 , indexLatinCharArray (array chunk) (offset chunk + 1) == c1 , indexLatinCharArray (array chunk) (offset chunk + 2) == c2- -> InternalSuccess () (offset chunk + 3) (length chunk - 3)- | otherwise -> InternalFailure e+ -> Success () (offset chunk + 3) (length chunk - 3)+ | otherwise -> Failure e -- | Consume four characters, failing if they do -- not match the expected values. -- -- > char4 e a b c d === char e a *> char e b *> char e c *> char e d char4 :: e -> Char -> Char -> Char -> Char -> Parser e s ()--- GHC should decide to inline this after optimization.+{-# inline char4 #-} char4 e !c0 !c1 !c2 !c3 = uneffectful $ \chunk -> if | length chunk > 3 , indexLatinCharArray (array chunk) (offset chunk) == c0 , indexLatinCharArray (array chunk) (offset chunk + 1) == c1 , indexLatinCharArray (array chunk) (offset chunk + 2) == c2 , indexLatinCharArray (array chunk) (offset chunk + 3) == c3- -> InternalSuccess () (offset chunk + 4) (length chunk - 4)- | otherwise -> InternalFailure e+ -> Success () (offset chunk + 4) (length chunk - 4)+ | otherwise -> Failure e -- | Consume five characters, failing if they do -- not match the expected values. char5 :: e -> Char -> Char -> Char -> Char -> Char -> Parser e s ()+{-# inline char5 #-} char5 e !c0 !c1 !c2 !c3 !c4 = uneffectful $ \chunk -> if | length chunk > 4 , indexLatinCharArray (array chunk) (offset chunk) == c0@@ -203,12 +207,13 @@ , indexLatinCharArray (array chunk) (offset chunk + 2) == c2 , indexLatinCharArray (array chunk) (offset chunk + 3) == c3 , indexLatinCharArray (array chunk) (offset chunk + 4) == c4- -> InternalSuccess () (offset chunk + 5) (length chunk - 5)- | otherwise -> InternalFailure e+ -> Success () (offset chunk + 5) (length chunk - 5)+ | otherwise -> Failure e -- | Consume six characters, failing if they do -- not match the expected values. char6 :: e -> Char -> Char -> Char -> Char -> Char -> Char -> Parser e s ()+{-# inline char6 #-} char6 e !c0 !c1 !c2 !c3 !c4 !c5 = uneffectful $ \chunk -> if | length chunk > 5 , indexLatinCharArray (array chunk) (offset chunk) == c0@@ -217,12 +222,13 @@ , indexLatinCharArray (array chunk) (offset chunk + 3) == c3 , indexLatinCharArray (array chunk) (offset chunk + 4) == c4 , indexLatinCharArray (array chunk) (offset chunk + 5) == c5- -> InternalSuccess () (offset chunk + 6) (length chunk - 6)- | otherwise -> InternalFailure e+ -> Success () (offset chunk + 6) (length chunk - 6)+ | otherwise -> Failure e -- | Consume seven characters, failing if they do -- not match the expected values. char7 :: e -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Parser e s ()+{-# inline char7 #-} char7 e !c0 !c1 !c2 !c3 !c4 !c5 !c6 = uneffectful $ \chunk -> if | length chunk > 6 , indexLatinCharArray (array chunk) (offset chunk) == c0@@ -232,12 +238,13 @@ , indexLatinCharArray (array chunk) (offset chunk + 4) == c4 , indexLatinCharArray (array chunk) (offset chunk + 5) == c5 , indexLatinCharArray (array chunk) (offset chunk + 6) == c6- -> InternalSuccess () (offset chunk + 7) (length chunk - 7)- | otherwise -> InternalFailure e+ -> Success () (offset chunk + 7) (length chunk - 7)+ | otherwise -> Failure e -- | Consume eight characters, failing if they do -- not match the expected values. char8 :: e -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Parser e s ()+{-# inline char8 #-} char8 e !c0 !c1 !c2 !c3 !c4 !c5 !c6 !c7 = uneffectful $ \chunk -> if | length chunk > 7 , indexLatinCharArray (array chunk) (offset chunk) == c0@@ -248,13 +255,14 @@ , indexLatinCharArray (array chunk) (offset chunk + 5) == c5 , indexLatinCharArray (array chunk) (offset chunk + 6) == c6 , indexLatinCharArray (array chunk) (offset chunk + 7) == c7- -> InternalSuccess () (offset chunk + 8) (length chunk - 8)- | otherwise -> InternalFailure e+ -> Success () (offset chunk + 8) (length chunk - 8)+ | otherwise -> Failure e -- | Consume nine characters, failing if they do -- not match the expected values. char9 :: e -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Parser e s ()+{-# inline char9 #-} char9 e !c0 !c1 !c2 !c3 !c4 !c5 !c6 !c7 !c8 = uneffectful $ \chunk -> if | length chunk > 8 , indexLatinCharArray (array chunk) (offset chunk) == c0@@ -266,13 +274,14 @@ , indexLatinCharArray (array chunk) (offset chunk + 6) == c6 , indexLatinCharArray (array chunk) (offset chunk + 7) == c7 , indexLatinCharArray (array chunk) (offset chunk + 8) == c8- -> InternalSuccess () (offset chunk + 9) (length chunk - 9)- | otherwise -> InternalFailure e+ -> Success () (offset chunk + 9) (length chunk - 9)+ | otherwise -> Failure e -- | Consume ten characters, failing if they do -- not match the expected values. char10 :: e -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Parser e s ()+{-# inline char10 #-} char10 e !c0 !c1 !c2 !c3 !c4 !c5 !c6 !c7 !c8 !c9 = uneffectful $ \chunk -> if | length chunk > 9 , indexLatinCharArray (array chunk) (offset chunk) == c0@@ -285,13 +294,14 @@ , indexLatinCharArray (array chunk) (offset chunk + 7) == c7 , indexLatinCharArray (array chunk) (offset chunk + 8) == c8 , indexLatinCharArray (array chunk) (offset chunk + 9) == c9- -> InternalSuccess () (offset chunk + 10) (length chunk - 10)- | otherwise -> InternalFailure e+ -> Success () (offset chunk + 10) (length chunk - 10)+ | otherwise -> Failure e -- | Consume eleven characters, failing if they do -- not match the expected values. char11 :: e -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Parser e s ()+{-# inline char11 #-} char11 e !c0 !c1 !c2 !c3 !c4 !c5 !c6 !c7 !c8 !c9 !c10 = uneffectful $ \chunk -> if | length chunk > 10 , indexLatinCharArray (array chunk) (offset chunk) == c0@@ -305,13 +315,14 @@ , indexLatinCharArray (array chunk) (offset chunk + 8) == c8 , indexLatinCharArray (array chunk) (offset chunk + 9) == c9 , indexLatinCharArray (array chunk) (offset chunk + 10) == c10- -> InternalSuccess () (offset chunk + 11) (length chunk - 11)- | otherwise -> InternalFailure e+ -> Success () (offset chunk + 11) (length chunk - 11)+ | otherwise -> Failure e -- | Consume twelve characters, failing if they do -- not match the expected values. char12 :: e -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Parser e s ()+{-# inline char12 #-} char12 e !c0 !c1 !c2 !c3 !c4 !c5 !c6 !c7 !c8 !c9 !c10 !c11 = uneffectful $ \chunk -> if | length chunk > 11 , indexLatinCharArray (array chunk) (offset chunk) == c0@@ -326,24 +337,26 @@ , indexLatinCharArray (array chunk) (offset chunk + 9) == c9 , indexLatinCharArray (array chunk) (offset chunk + 10) == c10 , indexLatinCharArray (array chunk) (offset chunk + 11) == c11- -> InternalSuccess () (offset chunk + 12) (length chunk - 12)- | otherwise -> InternalFailure e+ -> Success () (offset chunk + 12) (length chunk - 12)+ | otherwise -> Failure e -- | Consumes and returns the next character in the input. any :: e -> Parser e s Char+{-# inline any #-} any e = uneffectful $ \chunk -> if length chunk > 0 then let c = indexLatinCharArray (array chunk) (offset chunk)- in InternalSuccess c (offset chunk + 1) (length chunk - 1)- else InternalFailure e+ in Success c (offset chunk + 1) (length chunk - 1)+ else Failure e -- | Consume a character from the input or return @Nothing@ if -- end of the stream has been reached. Since ISO 8859-1 maps every -- bytes to a character, this parser never fails. opt :: Parser e s (Maybe Char)+{-# inline opt #-} opt = uneffectful $ \chunk -> case length chunk of- 0 -> InternalSuccess Nothing (offset chunk) (length chunk)- _ -> InternalSuccess+ 0 -> Success Nothing (offset chunk) (length chunk)+ _ -> Success (Just (indexLatinCharArray (array chunk) (offset chunk))) (offset chunk + 1) (length chunk - 1) @@ -382,6 +395,7 @@ -- | Variant of 'skipDigits' that requires at least one digit -- to be present. skipDigits1 :: e -> Parser e s ()+{-# inline skipDigits1 #-} skipDigits1 e = uneffectful# $ \c -> skipDigitsAscii1LoopStart e c @@ -397,12 +411,14 @@ -- | Skip the character any number of times. This succeeds -- even if the character was not present. skipChar :: Char -> Parser e s ()+{-# inline skipChar #-} skipChar !w = uneffectful# $ \c -> upcastUnitSuccess (skipLoop w c) -- | Skip the character any number of times. It must occur -- at least once or else this will fail. skipChar1 :: e -> Char -> Parser e s ()+{-# inline skipChar1 #-} skipChar1 e !w = uneffectful# $ \c -> skipLoop1Start e w c @@ -539,11 +555,13 @@ !len@(I# len# ) = length chunk0 upcastWordResult :: Result# e Word# -> Result# e Word+{-# inline upcastWordResult #-} upcastWordResult (# e | #) = (# e | #) upcastWordResult (# | (# a, b, c #) #) = (# | (# W# a, b, c #) #) -- This only works on 64-bit platforms. upcastWord64Result :: Result# e Word# -> Result# e Word64+{-# inline upcastWord64Result #-} upcastWord64Result (# e | #) = (# e | #) upcastWord64Result (# | (# a, b, c #) #) = (# | (# W64# a, b, c #) #) @@ -599,16 +617,19 @@ -- Precondition: the word is small enough upcastWord16Result :: Result# e Word# -> Result# e Word16+{-# inline upcastWord16Result #-} upcastWord16Result (# e | #) = (# e | #) upcastWord16Result (# | (# a, b, c #) #) = (# | (# W16# a, b, c #) #) -- Precondition: the word is small enough upcastWord32Result :: Result# e Word# -> Result# e Word32+{-# inline upcastWord32Result #-} upcastWord32Result (# e | #) = (# e | #) upcastWord32Result (# | (# a, b, c #) #) = (# | (# W32# a, b, c #) #) -- Precondition: the word is small enough upcastWord8Result :: Result# e Word# -> Result# e Word8+{-# inline upcastWord8Result #-} upcastWord8Result (# e | #) = (# e | #) upcastWord8Result (# | (# a, b, c #) #) = (# | (# W8# a, b, c #) #) @@ -1076,25 +1097,25 @@ -- @[a-f0-9]@. hexNibbleLower :: e -> Parser e s Word hexNibbleLower e = uneffectful $ \chunk -> case length chunk of- 0 -> InternalFailure e+ 0 -> Failure e _ -> let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8 in- if | w >= 48 && w < 58 -> InternalSuccess (fromIntegral w - 48) (offset chunk + 1) (length chunk - 1)- | w >= 97 && w < 103 -> InternalSuccess (fromIntegral w - 87) (offset chunk + 1) (length chunk - 1)- | otherwise -> InternalFailure e+ if | w >= 48 && w < 58 -> Success (fromIntegral w - 48) (offset chunk + 1) (length chunk - 1)+ | w >= 97 && w < 103 -> Success (fromIntegral w - 87) (offset chunk + 1) (length chunk - 1)+ | otherwise -> Failure e -- | Consume a single character that is the case-insensitive hexadecimal -- encoding of a 4-bit word. Fails if the character is not in the class -- @[a-fA-F0-9]@. hexNibble :: e -> Parser e s Word hexNibble e = uneffectful $ \chunk -> case length chunk of- 0 -> InternalFailure e+ 0 -> Failure e _ -> let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8 in- if | w >= 48 && w < 58 -> InternalSuccess (fromIntegral w - 48) (offset chunk + 1) (length chunk - 1)- | w >= 65 && w < 71 -> InternalSuccess (fromIntegral w - 55) (offset chunk + 1) (length chunk - 1)- | w >= 97 && w < 103 -> InternalSuccess (fromIntegral w - 87) (offset chunk + 1) (length chunk - 1)- | otherwise -> InternalFailure e+ if | w >= 48 && w < 58 -> Success (fromIntegral w - 48) (offset chunk + 1) (length chunk - 1)+ | w >= 65 && w < 71 -> Success (fromIntegral w - 55) (offset chunk + 1) (length chunk - 1)+ | w >= 97 && w < 103 -> Success (fromIntegral w - 87) (offset chunk + 1) (length chunk - 1)+ | otherwise -> Failure e -- | Consume a single character that is the lowercase hexadecimal -- encoding of a 4-bit word. Returns @Nothing@ without consuming@@ -1126,6 +1147,7 @@ -- Returns the maximum machine word if the argument is not -- the ASCII encoding of a hexadecimal digit. oneHex :: Word8 -> Word+{-# inline oneHex #-} oneHex w | w >= 48 && w < 58 = (fromIntegral w - 48) | w >= 65 && w < 71 = (fromIntegral w - 55)@@ -1141,6 +1163,7 @@ | otherwise = Nothing uneffectfulWord# :: (Bytes -> Result# e Word#) -> Parser e s Word#+{-# inline uneffectfulWord# #-} uneffectfulWord# f = Parser ( \b s0 -> (# s0, (f (boxBytes b)) #) ) @@ -1149,6 +1172,7 @@ -- Postcondition: when overflow is false, the resulting -- word is less than or equal to the upper bound positivePushBase10 :: Word -> Word -> Word -> (Bool,Word)+{-# inline positivePushBase10 #-} positivePushBase10 (W# a) (W# b) (W# upper) = let !(# ca, r0 #) = Exts.timesWord2# a 10## !r1 = Exts.plusWord# r0 b@@ -1158,6 +1182,7 @@ in (case c of { 0## -> False; _ -> True }, W# r1) unsignedPushBase10 :: Word -> Word -> (Bool,Word)+{-# inline unsignedPushBase10 #-} unsignedPushBase10 (W# a) (W# b) = let !(# ca, r0 #) = Exts.timesWord2# a 10## !r1 = Exts.plusWord# r0 b@@ -1184,8 +1209,32 @@ {-# inline anyUnsafe #-} anyUnsafe = uneffectful $ \chunk -> let w = indexCharArray (array chunk) (offset chunk) :: Char- in InternalSuccess w (offset chunk + 1) (length chunk - 1)+ in Success w (offset chunk + 1) (length chunk - 1) -- Reads one byte and interprets it as Latin1-encoded character. indexCharArray :: PM.ByteArray -> Int -> Char+{-# inline indexCharArray #-} indexCharArray (PM.ByteArray x) (I# i) = C# (indexCharArray# x i)++-- | Match any character, to perform lookahead. Returns 'Nothing' if+-- end of input has been reached. Does not consume any input.+--+-- /Note/: Because this parser does not fail, do not use it+-- with combinators such as 'many', because such as 'many',+-- because such parsers loop until a failure occurs. Careless+-- use will thus result in an infinite loop.+peek :: Parser e s (Maybe Char)+{-# inline peek #-}+peek = uneffectful $ \(Bytes arr off len) ->+ let v = if len > 0+ then Just (indexCharArray arr off)+ else Nothing+ in Success v off len++-- | Match any byte, to perform lookahead. Does not consume any+-- input, but will fail if end of input has been reached.+peek' :: e -> Parser e s Char+{-# inline peek' #-}+peek' e = uneffectful $ \(Bytes arr off len) -> if len > 0+ then Success (indexCharArray arr off) off len+ else Failure e
src/Data/Bytes/Parser/LittleEndian.hs view
@@ -49,7 +49,7 @@ import Data.Primitive (ByteArray(..),PrimArray(..)) import Data.Bytes.Types (Bytes(..)) import Data.Bytes.Parser.Internal (Parser,uneffectful)-import Data.Bytes.Parser.Internal (InternalResult(..))+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)@@ -158,10 +158,10 @@ then let wa = PM.indexByteArray (array chunk) (offset chunk) :: Word8 wb = PM.indexByteArray (array chunk) (offset chunk + 1) :: Word8- in InternalSuccess+ in Success (fromIntegral @Word @Word16 (unsafeShiftL (fromIntegral wb) 8 .|. fromIntegral wa)) (offset chunk + 2) (length chunk - 2)- else InternalFailure e+ else Failure e -- | Unsigned 32-bit word. word32 :: e -> Parser e s Word32@@ -171,7 +171,7 @@ wb = PM.indexByteArray (array chunk) (offset chunk + 1) :: Word8 wc = PM.indexByteArray (array chunk) (offset chunk + 2) :: Word8 wd = PM.indexByteArray (array chunk) (offset chunk + 3) :: Word8- in InternalSuccess+ in Success (fromIntegral @Word @Word32 ( unsafeShiftL (fromIntegral wd) 24 .|. unsafeShiftL (fromIntegral wc) 16 .|.@@ -180,7 +180,7 @@ ) ) (offset chunk + 4) (length chunk - 4)- else InternalFailure e+ else Failure e -- | Unsigned 64-bit word. word64 :: e -> Parser e s Word64@@ -194,7 +194,7 @@ wf = PM.indexByteArray (array chunk) (offset chunk + 5) :: Word8 wg = PM.indexByteArray (array chunk) (offset chunk + 6) :: Word8 wh = PM.indexByteArray (array chunk) (offset chunk + 7) :: Word8- in InternalSuccess+ in Success ( unsafeShiftL (fromIntegral wh) 56 .|. unsafeShiftL (fromIntegral wg) 48 .|. unsafeShiftL (fromIntegral wf) 40 .|.@@ -205,7 +205,7 @@ fromIntegral wa ) (offset chunk + 8) (length chunk - 8)- else InternalFailure e+ else Failure e -- | Unsigned 256-bit word. word256 :: e -> Parser e s Word256
src/Data/Bytes/Parser/Rebindable.hs view
@@ -75,6 +75,17 @@ runParser (g y) (# arr, b, c #) s1 ) +bindWordParser :: forall (a :: TYPE 'WordRep) e s b.+ Parser e s a -> (a -> Parser e s b) -> Parser e s b+{-# inline bindWordParser #-}+bindWordParser (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+ )+ sequenceIntParser :: forall (a :: TYPE 'IntRep) e s b. Parser e s a -> Parser e s b -> Parser e s b {-# inline sequenceIntParser #-}@@ -85,6 +96,16 @@ (# | (# _, b, c #) #) -> g (# arr, b, c #) s1 ) +sequenceWordParser :: forall (a :: TYPE 'WordRep) e s b.+ Parser e s a -> Parser e s b -> Parser e s b+{-# inline sequenceWordParser #-}+sequenceWordParser (Parser f) (Parser g) = Parser+ (\x@(# arr, _, _ #) s0 -> case f x s0 of+ (# s1, r0 #) -> case r0 of+ (# e | #) -> (# s1, (# e | #) #)+ (# | (# _, b, c #) #) -> g (# arr, b, c #) s1+ )+ pureIntPairParser :: forall (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep])) e s. a -> Parser e s a {-# inline pureIntPairParser #-}@@ -171,6 +192,12 @@ {-# inline (>>) #-} (>>=) = bindParser (>>) = sequenceParser++instance Bind 'WordRep 'LiftedRep where+ {-# inline (>>=) #-}+ {-# inline (>>) #-}+ (>>=) = bindWordParser+ (>>) = sequenceWordParser instance Bind 'IntRep 'LiftedRep where {-# inline (>>=) #-}
src/Data/Bytes/Parser/Unsafe.hs view
@@ -29,23 +29,24 @@ , expose , unconsume , jump+ , uneffectful ) where import Prelude hiding (length) -import Data.Primitive (ByteArray)-import Data.Bytes.Types (Bytes(..)) import Data.Bytes.Parser.Internal (Parser(..),uneffectful,uneffectfulInt#)-import Data.Bytes.Parser.Internal (InternalResult(..))-+import Data.Bytes.Parser.Internal (Result(..))+import Data.Bytes.Types (Bytes(..))+import Data.Primitive (ByteArray) import GHC.Exts (Int#,Int(I#)) + -- | Get the current offset into the chunk. Using this makes -- it possible to observe the internal difference between 'Bytes' -- that refer to equivalent slices. Be careful. cursor :: Parser e s Int cursor = uneffectful $ \Bytes{offset,length} ->- InternalSuccess offset offset length+ Success offset offset length -- | Variant of 'cursor' with unboxed result. cursor# :: Parser e s Int#@@ -57,18 +58,17 @@ -- use this is you know what you're doing. expose :: Parser e s ByteArray expose = uneffectful $ \Bytes{length,offset,array} ->- InternalSuccess array offset length+ Success array offset length -- | Move the cursor back by @n@ bytes. Precondition: you -- must have previously consumed at least @n@ bytes. unconsume :: Int -> Parser e s () unconsume n = uneffectful $ \Bytes{length,offset} ->- InternalSuccess () (offset - n) (length + n)+ Success () (offset - n) (length + n) -- | Set the position to the given index. Precondition: the index -- must be valid. It should be the result of an earlier call to -- 'cursor'. jump :: Int -> Parser e s () jump ix = uneffectful $ \(Bytes{length,offset}) ->- InternalSuccess () ix (length + (offset - ix))-+ Success () ix (length + (offset - ix))