bytesmith 0.3.11.1 → 0.3.13.0
raw patch · 10 files changed
+111/−55 lines, 10 filesdep ~basePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: base
API changes (from Hackage documentation)
+ Data.Bytes.Parser: bindFromByteArrayIntIntToLifted :: Parser s e (# ByteArray#, Int#, Int# #) -> ((# ByteArray#, Int#, Int# #) -> Parser s e a) -> Parser s e a
+ Data.Bytes.Parser: bindFromCharToByteArrayIntInt :: Parser s e Char# -> (Char# -> Parser s e (# ByteArray#, Int#, Int# #)) -> Parser s e (# ByteArray#, Int#, Int# #)
+ Data.Bytes.Parser: bindFromLiftedToByteArrayIntInt :: Parser s e a -> (a -> Parser s e (# ByteArray#, Int#, Int# #)) -> Parser s e (# ByteArray#, Int#, Int# #)
+ Data.Bytes.Parser: bindFromWordToByteArrayIntInt :: Parser s e Word# -> (Word# -> Parser s e (# ByteArray#, Int#, Int# #)) -> Parser s e (# ByteArray#, Int#, Int# #)
+ Data.Bytes.Parser: failByteArrayIntInt :: forall e s (a :: TYPE ('TupleRep '[UnliftedRep, 'IntRep, 'IntRep])). e -> Parser e s a
+ Data.Bytes.Parser: listUntilEoi :: Parser e s a -> Parser e s [a]
+ Data.Bytes.Parser: pureByteArrayIntInt :: (# ByteArray#, Int#, Int# #) -> Parser s e (# ByteArray#, Int#, Int# #)
+ Data.Bytes.Parser.Latin: hexFixedWord16# :: e -> Parser e s Word#
- Data.Bytes.Parser: data Parser :: forall (r :: RuntimeRep). Type -> Type -> TYPE r -> Type
+ Data.Bytes.Parser: data Parser a b (c :: TYPE r)
- Data.Bytes.Parser: parseByteArray :: (forall s. Parser e s a) -> ByteArray -> Result e a
+ Data.Bytes.Parser: parseByteArray :: (forall s. () => Parser e s a) -> ByteArray -> Result e a
- Data.Bytes.Parser: parseBytes :: forall e a. (forall s. Parser e s a) -> Bytes -> Result e a
+ Data.Bytes.Parser: parseBytes :: (forall s. () => Parser e s a) -> Bytes -> Result e a
- Data.Bytes.Parser: parseBytesEither :: forall e a. (forall s. Parser e s a) -> Bytes -> Either e a
+ Data.Bytes.Parser: parseBytesEither :: (forall s. () => Parser e s a) -> Bytes -> Either e a
- Data.Bytes.Parser: parseBytesMaybe :: forall e a. (forall s. Parser e s a) -> Bytes -> Maybe a
+ Data.Bytes.Parser: parseBytesMaybe :: (forall s. () => Parser e s a) -> Bytes -> Maybe a
- Data.Bytes.Parser: takeN :: e -> Nat n -> Parser e s (BytesN n)
+ Data.Bytes.Parser: takeN :: forall e (n :: Nat) s. e -> Nat n -> Parser e s (BytesN n)
- Data.Bytes.Parser.Latin: trySatisfyThen :: forall (r :: RuntimeRep) (e :: Type) (s :: Type) (a :: TYPE r). Parser e s a -> (Char -> Maybe (Parser e s a)) -> Parser e s a
+ Data.Bytes.Parser.Latin: trySatisfyThen :: Parser e s a -> (Char -> Maybe (Parser e s a)) -> Parser e s a
- Data.Bytes.Parser.Unsafe: [Parser] :: forall (r :: RuntimeRep) (e :: Type) (s :: Type) (a :: TYPE r). ((# ByteArray#, Int#, Int# #) -> ST# s (Result# e a)) -> Parser e s a
+ Data.Bytes.Parser.Unsafe: [Parser] :: forall (r :: RuntimeRep) a b (c :: TYPE r). ((# ByteArray#, Int#, Int# #) -> ST# b (Result# a c)) -> Parser a b c
- Data.Bytes.Parser.Unsafe: newtype Parser :: forall (r :: RuntimeRep). Type -> Type -> TYPE r -> Type
+ Data.Bytes.Parser.Unsafe: newtype Parser a b (c :: TYPE r)
Files
- CHANGELOG.md +6/−0
- bytesmith.cabal +2/−2
- src/Data/Bytes/Parser.hs +85/−11
- src/Data/Bytes/Parser/BigEndian.hs +0/−4
- src/Data/Bytes/Parser/Internal.hs +9/−0
- src/Data/Bytes/Parser/Latin.hs +9/−24
- src/Data/Bytes/Parser/LittleEndian.hs +0/−3
- src/Data/Bytes/Parser/Rebindable.hs +0/−5
- src/Data/Bytes/Parser/Utf8.hs +0/−2
- test/Main.hs +0/−4
CHANGELOG.md view
@@ -1,5 +1,11 @@ # Revision history for bytesmith +## 0.3.13.0 -- 2025-07-11++* Add `hexFixedWord16#`+* Drop support for base < 4.18, clean up CPP+* Add more levity-monomorphized variants of bind, pure, and fail+ ## 0.3.11.1 -- 2024-02-28 * Update package metadata.
bytesmith.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: bytesmith-version: 0.3.11.1+version: 0.3.13.0 synopsis: Nonresumable byte parser description: Parse bytes as fast as possible. This is a nonresumable parser@@ -41,7 +41,7 @@ Data.Bytes.Parser.Types build-depends:- , base >=4.12 && <5+ , base >=4.18 && <5 , byteslice >=0.2.6 && <0.3 , bytestring >=0.10.8 && <0.13 , contiguous >=0.6 && <0.7
src/Data/Bytes/Parser.hs view
@@ -79,6 +79,7 @@ -- * Repetition , replicate+ , listUntilEoi -- * Subparsing , delimit@@ -104,23 +105,30 @@ -- of monadic @>>=@ can be helpful. If @C#@, @I#@, etc. never -- get used in your original source code, GHC will not introduce them. , bindFromCharToLifted+ , bindFromCharToByteArrayIntInt+ , bindFromWordToByteArrayIntInt , bindFromLiftedToIntPair , bindFromLiftedToInt , bindFromIntToIntPair , bindFromCharToIntPair+ , bindFromLiftedToByteArrayIntInt+ , bindFromByteArrayIntIntToLifted , bindFromMaybeCharToIntPair , bindFromMaybeCharToLifted -- * Specialized Pure , pureIntPair+ , pureByteArrayIntInt -- * Specialized Fail , failIntPair+ , failByteArrayIntInt ) where import Prelude hiding (any, fail, length, replicate, take, takeWhile) import Data.Bytes.Parser.Internal (Parser (..), Result#, ST#, boxBytes, fail, unboxBytes, uneffectful, uneffectful#, uneffectfulInt#)+import Data.Bytes.Parser.Internal (failByteArrayIntInt) import Data.Bytes.Parser.Types (Result (Failure, Success), Slice (Slice)) import Data.Bytes.Parser.Unsafe (cursor, expose, unconsume) import Data.Bytes.Types (Bytes (..), BytesN (BytesN))@@ -128,6 +136,7 @@ import Data.Primitive.Contiguous (Contiguous, Element) import Foreign.C.String (CString) import GHC.Exts (Char#, Int (I#), Int#, Word#, runRW#, (+#), (-#), (>=#))+import GHC.Exts (ByteArray#) import GHC.ST (ST (..)) import GHC.Word (Word32 (W32#), Word8) @@ -135,6 +144,7 @@ import qualified Arithmetic.Types as Arithmetic import qualified Data.Bytes as B import qualified Data.Bytes.Parser.Internal as Internal+import qualified Data.List as List import qualified Data.Primitive as PM import qualified Data.Primitive.Contiguous as C import qualified GHC.Exts as Exts@@ -249,17 +259,13 @@ cstring e (Exts.Ptr ptr0) = Parser ( \(# arr, off0, len0 #) s -> let go !ptr !off !len = case-#if MIN_VERSION_base(4,16,0) Exts.word8ToWord#-#endif (Exts.indexWord8OffAddr# ptr 0#) of 0## -> (# s, (# | (# (), off, len #) #) #) c -> case len of 0# -> (# s, (# e | #) #) _ -> case Exts.eqWord# c (-#if MIN_VERSION_base(4,16,0) Exts.word8ToWord#-#endif (Exts.indexWord8Array# arr off)) of 1# -> go (Exts.plusAddr# ptr 1# ) (off +# 1# ) (len -# 1# ) _ -> (# s, (# e | #) #)@@ -519,15 +525,15 @@ -- | Skip while the predicate is matched. This is always inlined. skipWhile :: (Word8 -> Bool) -> Parser e s () {-# INLINE skipWhile #-}-skipWhile f = go+skipWhile f = goSkipWhile where- go =+ goSkipWhile = isEndOfInput >>= \case True -> pure () False -> do w <- anyUnsafe if f w- then go+ then goSkipWhile else unconsume 1 {- | The parser @satisfy p@ succeeds for any byte for which the@@ -584,9 +590,7 @@ (# s1, r #) -> case r of (# e | #) -> (# s1, (# e | #) #) (# | (# W32# a, b, c #) #) -> (# s1, (# | (#-#if MIN_VERSION_base(4,16,0) Exts.word32ToWord#-#endif a, b, c #) #) #) ) {- FOURMOLU_ENABLE -}@@ -612,9 +616,7 @@ (# s1, r #) -> case r of (# e | #) -> (# s1, (# e | #) #) (# | (# a, b, c #) #) -> (# s1, (# | (# W32# (-#if MIN_VERSION_base(4,16,0) Exts.wordToWord32#-#endif a), b, c #) #) #) ) {- FOURMOLU_ENABLE -}@@ -696,6 +698,28 @@ runParser (g y) (# arr, b, c #) s1 ) +bindFromWordToByteArrayIntInt :: Parser s e Word# -> (Word# -> Parser s e (# ByteArray#, Int#, Int# #)) -> Parser s e (# ByteArray#, Int#, Int# #)+{-# INLINE bindFromWordToByteArrayIntInt #-}+bindFromWordToByteArrayIntInt (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+ )++bindFromCharToByteArrayIntInt :: Parser s e Char# -> (Char# -> Parser s e (# ByteArray#, Int#, Int# #)) -> Parser s e (# ByteArray#, Int#, Int# #)+{-# INLINE bindFromCharToByteArrayIntInt #-}+bindFromCharToByteArrayIntInt (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+ )+ bindFromCharToIntPair :: Parser s e Char# -> (Char# -> Parser s e (# Int#, Int# #)) -> Parser s e (# Int#, Int# #) {-# INLINE bindFromCharToIntPair #-} bindFromCharToIntPair (Parser f) g =@@ -718,6 +742,34 @@ runParser (g y) (# arr, b, c #) s1 ) +bindFromByteArrayIntIntToLifted ::+ Parser s e (# ByteArray#, Int#, Int# #)+ -> ((# ByteArray#, Int#, Int# #) -> Parser s e a)+ -> Parser s e a+{-# INLINE bindFromByteArrayIntIntToLifted #-}+bindFromByteArrayIntIntToLifted (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+ )++bindFromLiftedToByteArrayIntInt ::+ Parser s e a+ -> (a -> Parser s e (# ByteArray#, Int#, Int# #))+ -> Parser s e (# ByteArray#, Int#, Int# #)+{-# INLINE bindFromLiftedToByteArrayIntInt #-}+bindFromLiftedToByteArrayIntInt (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+ )+ bindFromLiftedToIntPair :: Parser s e a -> (a -> Parser s e (# Int#, Int# #)) -> Parser s e (# Int#, Int# #) {-# INLINE bindFromLiftedToIntPair #-} bindFromLiftedToIntPair (Parser f) g =@@ -776,6 +828,14 @@ Parser (\(# _, b, c #) s -> (# s, (# | (# a, b, c #) #) #)) +pureByteArrayIntInt ::+ (# ByteArray#, Int#, Int# #) ->+ Parser s e (# ByteArray#, Int#, Int# #)+{-# INLINE pureByteArrayIntInt #-}+pureByteArrayIntInt a =+ Parser+ (\(# _, b, c #) s -> (# s, (# | (# a, b, c #) #) #))+ failIntPair :: e -> Parser e s (# Int#, Int# #) {-# INLINE failIntPair #-} failIntPair e =@@ -847,6 +907,20 @@ _ -> (# s1, (# eleftovers | #) #) _ -> (# s0, (# esz | #) #) )++{- | Apply the parser repeatedly until there is no more input left+to consume. Collects the results into a list.+-}+listUntilEoi ::+ Parser e s a -- ^ Parser to repeatedly apply until input is exhausted+ -> Parser e s [a]+listUntilEoi p = go []+ where+ go !acc = isEndOfInput >>= \case+ True -> pure $! List.reverse acc+ False -> do+ a <- p+ go (a : acc) {- | Replicate a parser @n@ times, writing the results into an array of length @n@. For @Array@ and @SmallArray@, this
src/Data/Bytes/Parser/BigEndian.hs view
@@ -38,10 +38,6 @@ import Prelude hiding (any, fail, length, takeWhile) -#if MIN_VERSION_base(4,18,0)-#else-import Control.Applicative (liftA2)-#endif import Data.Bits (unsafeShiftL, (.|.)) import Data.Bytes.Parser.Internal (Parser, Result (..), swapArray128, swapArray16, swapArray256, swapArray32, swapArray64, uneffectful) import Data.Bytes.Types (Bytes (..))
src/Data/Bytes/Parser/Internal.hs view
@@ -25,6 +25,7 @@ , unboxBytes , unboxResult , fail+ , failByteArrayIntInt , indexLatinCharArray , upcastUnitSuccess -- Swapping@@ -44,6 +45,7 @@ import Data.Primitive (ByteArray (ByteArray)) import Data.Word (Word8) import GHC.Exts (ByteArray#, Char (C#), Int (I#), Int#, RuntimeRep, State#, TYPE)+import GHC.Exts (RuntimeRep(IntRep, BoxedRep, TupleRep), Levity(Unlifted)) import qualified Control.Applicative import qualified Control.Monad@@ -128,6 +130,13 @@ Parser e s a {-# INLINE fail #-} fail e = uneffectful $ \_ -> Failure e++failByteArrayIntInt :: forall e s (a :: TYPE ('TupleRep '[ 'BoxedRep 'Unlifted, 'IntRep, 'IntRep ])).+ -- | Error message+ e ->+ Parser e s a+{-# INLINE failByteArrayIntInt #-}+failByteArrayIntInt e = Parser (\_ s0 -> (# s0, (# e | #) #)) instance Applicative (Parser e s) where pure = pureParser
src/Data/Bytes/Parser/Latin.hs view
@@ -99,6 +99,7 @@ -- *** Fixed Length , hexFixedWord8 , hexFixedWord16+ , hexFixedWord16# , hexFixedWord32 , hexFixedWord64 , hexFixedWord128@@ -701,11 +702,7 @@ {-# inline upcastWord64Result #-} upcastWord64Result (# e | #) = (# e | #) upcastWord64Result (# | (# a, b, c #) #) = (# | (# W64# (-#if MIN_VERSION_base(4,17,0) Exts.wordToWord64# a-#else- a-#endif ), b, c #) #) {- FOURMOLU_ENABLE -} @@ -774,9 +771,7 @@ {-# inline upcastWord16Result #-} upcastWord16Result (# e | #) = (# e | #) upcastWord16Result (# | (# a, b, c #) #) = (# | (# W16# (-#if MIN_VERSION_base(4,16,0) Exts.wordToWord16#-#endif a), b, c #) #) -- Precondition: the word is small enough@@ -784,9 +779,7 @@ {-# inline upcastWord32Result #-} upcastWord32Result (# e | #) = (# e | #) upcastWord32Result (# | (# a, b, c #) #) = (# | (# W32# (-#if MIN_VERSION_base(4,16,0) Exts.wordToWord32#-#endif a), b, c #) #) -- Precondition: the word is small enough@@ -794,9 +787,7 @@ {-# inline upcastWord8Result #-} upcastWord8Result (# e | #) = (# e | #) upcastWord8Result (# | (# a, b, c #) #) = (# | (# W8# (-#if MIN_VERSION_base(4,16,0) Exts.wordToWord8#-#endif a), b, c #) #) {- FOURMOLU_ENABLE -} @@ -1188,9 +1179,7 @@ (# s1, r #) -> case r of (# err | #) -> (# s1, (# err | #) #) (# | (# a, b, c #) #) -> (# s1, (# | (# W32# (-#if MIN_VERSION_base(4,16,0) Exts.wordToWord32#-#endif a), b, c #) #) #) ) {- FOURMOLU_ENABLE -}@@ -1239,12 +1228,7 @@ (# s1, r #) -> case r of (# err | #) -> (# s1, (# err | #) #) (# | (# a, b, c #) #) -> (# s1, (# | (# W64# (-#if MIN_VERSION_base(4,17,0) Exts.wordToWord64# a-#else-- a-#endif ), b, c #) #) #) ) {- FOURMOLU_ENABLE -}@@ -1298,12 +1282,15 @@ (# s1, r #) -> case r of (# err | #) -> (# s1, (# err | #) #) (# | (# a, b, c #) #) -> (# s1, (# | (# W16# (-#if MIN_VERSION_base(4,16,0) Exts.wordToWord16#-#endif a), b, c #) #) #) ) +-- | Variant of hexFixedWord16 that returns an unboxed result. The result is+-- a machine-sized word instead of a 16-bit word, but this function guarantees+-- that only the low 16 bits may be non-zero. This is helpful because the+-- result needs to be constructed as a machine-sized word. GHC's primitives+-- for working with 16-bit words lower to most ISAs poorly. hexFixedWord16# :: e -> Parser e s Word# {-# noinline hexFixedWord16# #-} hexFixedWord16# e = uneffectfulWord# $ \chunk -> if length chunk >= 4@@ -1314,9 +1301,9 @@ !w3@(W# n3) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 3) in if | w0 .|. w1 .|. w2 .|. w3 /= maxBound -> (# |- (# (n0 `Exts.timesWord#` 4096##) `Exts.plusWord#`- (n1 `Exts.timesWord#` 256##) `Exts.plusWord#`- (n2 `Exts.timesWord#` 16##) `Exts.plusWord#`+ (# (n0 `Exts.shiftL#` 12#) `Exts.plusWord#`+ (n1 `Exts.shiftL#` 8#) `Exts.plusWord#`+ (n2 `Exts.shiftL#` 4#) `Exts.plusWord#` n3 , unI (offset chunk) +# 4# , unI (length chunk) -# 4# #) #)@@ -1334,9 +1321,7 @@ (# s1, r #) -> case r of (# err | #) -> (# s1, (# err | #) #) (# | (# a, b, c #) #) -> (# s1, (# | (# W8# (-#if MIN_VERSION_base(4,16,0) Exts.wordToWord8#-#endif a), b, c #) #) #) ) {- FOURMOLU_ENABLE -}
src/Data/Bytes/Parser/LittleEndian.hs view
@@ -43,10 +43,7 @@ import Prelude hiding (any, fail, length, takeWhile) -#if MIN_VERSION_base(4,18,0)-#else import Control.Applicative (liftA2)-#endif import Data.Bits (unsafeShiftL, (.|.)) import Data.Bytes.Parser.Internal (Parser, Result (..), swapArray128, swapArray16, swapArray256, swapArray32, swapArray64, uneffectful) import Data.Bytes.Types (Bytes (..))
src/Data/Bytes/Parser/Rebindable.hs view
@@ -25,12 +25,7 @@ import Data.Bytes.Parser.Internal (Parser (..)) import GHC.Exts (RuntimeRep (..), TYPE) import Prelude ()--#if MIN_VERSION_base(4,16,0) import GHC.Exts (LiftedRep)-#else-type LiftedRep = 'LiftedRep-#endif class Bind (ra :: RuntimeRep) (rb :: RuntimeRep) where (>>=) ::
src/Data/Bytes/Parser/Utf8.hs view
@@ -46,9 +46,7 @@ let !w0 = Exts.indexWord8Array# arr off in if | oneByteChar (W8# w0) -> (# s0, (# | (# chr# (Exts.word2Int# (-#if MIN_VERSION_base(4,16,0) Exts.word8ToWord#-#endif w0)), off +# 1#, len -# 1# #) #) #) | twoByteChar (W8# w0) -> if | I# len > 1
test/Main.hs view
@@ -7,10 +7,6 @@ {-# LANGUAGE TypeApplications #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -#if MIN_VERSION_base(4,18,0)-#else-import Control.Applicative (liftA2)-#endif import Control.Monad (replicateM) import Control.Monad.ST (runST) import Data.Bytes.Parser (Slice (Slice))