flatparse 0.3.2.0 → 0.3.3.0
raw patch · 6 files changed
+697/−159 lines, 6 filesdep +QuickCheckPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: QuickCheck
API changes (from Hackage documentation)
- FlatParse.Internal: indexWord16OffAddr :: Addr# -> Int# -> Word#
- FlatParse.Internal: indexWord32OffAddr :: Addr# -> Int# -> Word#
- FlatParse.Internal: indexWord64OffAddr :: Addr# -> Int# -> Word#
- FlatParse.Internal: indexWord8OffAddr :: Addr# -> Int# -> Word#
+ FlatParse.Basic: anyInt :: Parser e Int
+ FlatParse.Basic: anyInt16 :: Parser e Int16
+ FlatParse.Basic: anyInt16be :: Parser e Int16
+ FlatParse.Basic: anyInt16le :: Parser e Int16
+ FlatParse.Basic: anyInt32 :: Parser e Int32
+ FlatParse.Basic: anyInt32be :: Parser e Int32
+ FlatParse.Basic: anyInt32le :: Parser e Int32
+ FlatParse.Basic: anyInt64 :: Parser e Int64
+ FlatParse.Basic: anyInt64be :: Parser e Int64
+ FlatParse.Basic: anyInt64le :: Parser e Int64
+ FlatParse.Basic: anyInt8 :: Parser e Int8
+ FlatParse.Basic: anyWord16be :: Parser e Word16
+ FlatParse.Basic: anyWord16le :: Parser e Word16
+ FlatParse.Basic: anyWord32be :: Parser e Word32
+ FlatParse.Basic: anyWord32le :: Parser e Word32
+ FlatParse.Basic: anyWord64 :: Parser e Word64
+ FlatParse.Basic: anyWord64_ :: Parser e ()
+ FlatParse.Basic: anyWord64be :: Parser e Word64
+ FlatParse.Basic: anyWord64le :: Parser e Word64
+ FlatParse.Basic: withAnyInt16# :: (Int16'# -> Parser e a) -> Parser e a
+ FlatParse.Basic: withAnyInt32# :: (Int32'# -> Parser e a) -> Parser e a
+ FlatParse.Basic: withAnyInt64# :: (Int# -> Parser e a) -> Parser e a
+ FlatParse.Basic: withAnyInt8# :: (Int8'# -> Parser e a) -> Parser e a
+ FlatParse.Basic: withAnyWord16# :: (Word16'# -> Parser e a) -> Parser e a
+ FlatParse.Basic: withAnyWord32# :: (Word32'# -> Parser e a) -> Parser e a
+ FlatParse.Basic: withAnyWord64# :: (Word# -> Parser e a) -> Parser e a
+ FlatParse.Basic: withAnyWord8# :: (Word8'# -> Parser e a) -> Parser e a
+ FlatParse.Internal.UnboxedNumerics: byteSwap16'# :: Word16'# -> Word16'#
+ FlatParse.Internal.UnboxedNumerics: byteSwap32'# :: Word32'# -> Word32'#
+ FlatParse.Internal.UnboxedNumerics: eqWord16'# :: Word16'# -> Word16'# -> Int#
+ FlatParse.Internal.UnboxedNumerics: eqWord32'# :: Word32'# -> Word32'# -> Int#
+ FlatParse.Internal.UnboxedNumerics: eqWord8'# :: Word8'# -> Word8'# -> Int#
+ FlatParse.Internal.UnboxedNumerics: indexWord8OffAddr''# :: Addr# -> Int# -> Word8#
+ FlatParse.Internal.UnboxedNumerics: type Int16'# = Int#
+ FlatParse.Internal.UnboxedNumerics: type Int32'# = Int#
+ FlatParse.Internal.UnboxedNumerics: type Int8'# = Int#
+ FlatParse.Internal.UnboxedNumerics: type Word16'# = Word#
+ FlatParse.Internal.UnboxedNumerics: type Word32'# = Word#
+ FlatParse.Internal.UnboxedNumerics: type Word8'# = Word#
+ FlatParse.Internal.UnboxedNumerics: word16ToInt16# :: Word16'# -> Int#
+ FlatParse.Internal.UnboxedNumerics: word32ToInt32# :: Word32'# -> Int#
+ FlatParse.Internal.UnboxedNumerics: word8ToWord''# :: Word8# -> Word#
+ FlatParse.Internal.UnboxedNumerics: wordToWord8''# :: Word# -> Word8#
+ FlatParse.Stateful: anyInt :: Parser e Int
+ FlatParse.Stateful: anyInt16 :: Parser e Int16
+ FlatParse.Stateful: anyInt16be :: Parser e Int16
+ FlatParse.Stateful: anyInt16le :: Parser e Int16
+ FlatParse.Stateful: anyInt32 :: Parser e Int32
+ FlatParse.Stateful: anyInt32be :: Parser e Int32
+ FlatParse.Stateful: anyInt32le :: Parser e Int32
+ FlatParse.Stateful: anyInt64 :: Parser e Int64
+ FlatParse.Stateful: anyInt64be :: Parser e Int64
+ FlatParse.Stateful: anyInt64le :: Parser e Int64
+ FlatParse.Stateful: anyInt8 :: Parser e Int8
+ FlatParse.Stateful: anyWord16be :: Parser e Word16
+ FlatParse.Stateful: anyWord16le :: Parser e Word16
+ FlatParse.Stateful: anyWord32be :: Parser e Word32
+ FlatParse.Stateful: anyWord32le :: Parser e Word32
+ FlatParse.Stateful: anyWord64 :: Parser e Word64
+ FlatParse.Stateful: anyWord64_ :: Parser e ()
+ FlatParse.Stateful: anyWord64be :: Parser e Word64
+ FlatParse.Stateful: anyWord64le :: Parser e Word64
+ FlatParse.Stateful: withAnyInt16# :: (Int16'# -> Parser e a) -> Parser e a
+ FlatParse.Stateful: withAnyInt32# :: (Int32'# -> Parser e a) -> Parser e a
+ FlatParse.Stateful: withAnyInt64# :: (Int# -> Parser e a) -> Parser e a
+ FlatParse.Stateful: withAnyInt8# :: (Int8'# -> Parser e a) -> Parser e a
+ FlatParse.Stateful: withAnyWord16# :: (Word16'# -> Parser e a) -> Parser e a
+ FlatParse.Stateful: withAnyWord32# :: (Word32'# -> Parser e a) -> Parser e a
+ FlatParse.Stateful: withAnyWord64# :: (Word# -> Parser e a) -> Parser e a
+ FlatParse.Stateful: withAnyWord8# :: (Word8'# -> Parser e a) -> Parser e a
- FlatParse.Basic: anyWord16 :: Parser e Word
+ FlatParse.Basic: anyWord16 :: Parser e Word16
- FlatParse.Basic: anyWord32 :: Parser e Word
+ FlatParse.Basic: anyWord32 :: Parser e Word32
- FlatParse.Basic: byte :: Word -> Parser e ()
+ FlatParse.Basic: byte :: Word8 -> Parser e ()
- FlatParse.Basic: scan16# :: Word -> Parser e ()
+ FlatParse.Basic: scan16# :: Word16 -> Parser e ()
- FlatParse.Basic: scan32# :: Word -> Parser e ()
+ FlatParse.Basic: scan32# :: Word32 -> Parser e ()
- FlatParse.Basic: scan8# :: Word -> Parser e ()
+ FlatParse.Basic: scan8# :: Word8 -> Parser e ()
- FlatParse.Basic: scanAny8# :: Parser e Word
+ FlatParse.Basic: scanAny8# :: Parser e Word8
- FlatParse.Stateful: anyWord16 :: Parser e Word
+ FlatParse.Stateful: anyWord16 :: Parser e Word16
- FlatParse.Stateful: anyWord32 :: Parser e Word
+ FlatParse.Stateful: anyWord32 :: Parser e Word32
- FlatParse.Stateful: anyWord8 :: Parser e Word
+ FlatParse.Stateful: anyWord8 :: Parser e Word8
- FlatParse.Stateful: byte :: Word -> Parser e ()
+ FlatParse.Stateful: byte :: Word8 -> Parser e ()
- FlatParse.Stateful: scan16# :: Word -> Parser e ()
+ FlatParse.Stateful: scan16# :: Word16 -> Parser e ()
- FlatParse.Stateful: scan32# :: Word -> Parser e ()
+ FlatParse.Stateful: scan32# :: Word32 -> Parser e ()
- FlatParse.Stateful: scan8# :: Word -> Parser e ()
+ FlatParse.Stateful: scan8# :: Word8 -> Parser e ()
- FlatParse.Stateful: scanAny8# :: Parser e Word
+ FlatParse.Stateful: scanAny8# :: Parser e Word8
Files
- flatparse.cabal +5/−2
- src/FlatParse/Basic.hs +250/−69
- src/FlatParse/Internal.hs +5/−19
- src/FlatParse/Internal/UnboxedNumerics.hs +113/−0
- src/FlatParse/Stateful.hs +251/−69
- test/Test.hs +73/−0
flatparse.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: flatparse-version: 0.3.2.0+version: 0.3.3.0 synopsis: High-performance parsing from strict bytestrings description: @Flatparse@ is a high-performance parsing library, focusing on programming languages and human-readable data formats. See the README for more information:@@ -23,7 +23,8 @@ GHC == 8.6.5 , GHC == 8.8.4 , GHC == 8.10.7- , GHC == 9.0.1+ , GHC == 9.0.2+ , GHC == 9.2.2 extra-source-files: README.md @@ -47,6 +48,7 @@ FlatParse.Examples.BasicLambda.Lexer FlatParse.Examples.BasicLambda.Parser FlatParse.Internal+ FlatParse.Internal.UnboxedNumerics FlatParse.Stateful other-modules: Paths_flatparse@@ -98,6 +100,7 @@ ghc-options: -Wall -Wno-missing-signatures -Wno-name-shadowing -Wno-unused-binds -Wno-unused-matches -O2 -Wno-type-defaults build-depends: HUnit+ , QuickCheck , base >=4.7 && <5 , bytestring , flatparse
src/FlatParse/Basic.hs view
@@ -52,8 +52,15 @@ , anyWord16_ , anyWord32 , anyWord32_+ , anyWord64+ , anyWord64_ , anyWord , anyWord_+ , anyInt8+ , anyInt16+ , anyInt32+ , anyInt64+ , anyInt , anyChar , anyChar_ , anyCharASCII@@ -64,6 +71,20 @@ , FlatParse.Basic.readInt , FlatParse.Basic.readInteger + -- ** Explicit-endianness machine integers+ , anyWord16le+ , anyWord16be+ , anyWord32le+ , anyWord32be+ , anyWord64le+ , anyWord64be+ , anyInt16le+ , anyInt16be+ , anyInt32le+ , anyInt32be+ , anyInt64le+ , anyInt64be+ -- * Combinators , (<|>) , branch@@ -115,6 +136,15 @@ , scanBytes# , setBack# + , withAnyWord8#+ , withAnyWord16#+ , withAnyWord32#+ , withAnyWord64#+ , withAnyInt8#+ , withAnyInt16#+ , withAnyInt32#+ , withAnyInt64#+ ) where import Control.Monad@@ -125,6 +155,7 @@ import Data.Word import GHC.Exts import GHC.Word+import GHC.Int import GHC.ForeignPtr import Language.Haskell.TH import System.IO.Unsafe@@ -135,6 +166,7 @@ import qualified Data.Map.Strict as M import FlatParse.Internal+import FlatParse.Internal.UnboxedNumerics -------------------------------------------------------------------------------- @@ -334,8 +366,8 @@ char c = string [c] -- | Read a `Word8`.-byte :: Word -> Parser e ()-byte (W# w) = ensureBytes# 1 >> scan8# (W# w)+byte :: Word8 -> Parser e ()+byte w = ensureBytes# 1 >> scan8# w {-# inline byte #-} -- | Read a sequence of bytes. This is a template function, you can use it as @$(bytes [3, 4, 5])@,@@ -507,58 +539,6 @@ fusedSatisfy_ f1 f2 f3 f4 = () <$ fusedSatisfy f1 f2 f3 f4 {-# inline fusedSatisfy_ #-} --- | Parse any `Word8`.-anyWord8 :: Parser e Word8-anyWord8 = Parser \fp eob buf -> case eqAddr# eob buf of- 1# -> Fail#- _ -> case indexWord8OffAddr# buf 0# of- w -> OK# (W8# w) (plusAddr# buf 1#)-{-# inline anyWord8 #-}---- | Skip any `Word8`.-anyWord8_ :: Parser e ()-anyWord8_ = () <$ anyWord8-{-# inline anyWord8_ #-}---- | Parse any `Word16`.-anyWord16 :: Parser e Word-anyWord16 = Parser \fp eob buf -> case 2# <=# minusAddr# eob buf of- 0# -> Fail#- _ -> case indexWord16OffAddr buf 0# of- w -> OK# (W# w) (plusAddr# buf 2#)-{-# inline anyWord16 #-}---- | Skip any `Word16`.-anyWord16_ :: Parser e ()-anyWord16_ = () <$ anyWord16-{-# inline anyWord16_ #-}---- | Parse any `Word32`.-anyWord32 :: Parser e Word-anyWord32 = Parser \fp eob buf -> case 4# <=# minusAddr# eob buf of- 0# -> Fail#- _ -> case indexWord32OffAddr buf 0# of- w -> OK# (W# w) (plusAddr# buf 4#)-{-# inline anyWord32 #-}---- | Skip any `Word32`.-anyWord32_ :: Parser e ()-anyWord32_ = () <$ anyWord32-{-# inline anyWord32_ #-}---- | Parse any `Word`.-anyWord :: Parser e Word-anyWord = Parser \fp eob buf -> case 8# <=# minusAddr# eob buf of- 0# -> Fail#- _ -> case indexWordOffAddr# buf 0# of- w -> OK# (W# w) (plusAddr# buf 8#)-{-# inline anyWord #-}---- | Skip any `Word`.-anyWord_ :: Parser e ()-anyWord_ = () <$ anyWord-{-# inline anyWord_ #-}- -- | Parse any UTF-8-encoded `Char`. anyChar :: Parser e Char anyChar = Parser \fp eob buf -> case eqAddr# eob buf of@@ -902,30 +882,30 @@ -- | Unsafely read a concrete byte from the input. It's not checked that the input has -- enough bytes.-scan8# :: Word -> Parser e ()-scan8# (W# c) = Parser \fp eob s ->- case indexWord8OffAddr s 0# of- c' -> case eqWord# c c' of+scan8# :: Word8 -> Parser e ()+scan8# (W8# c) = Parser \fp eob s ->+ case indexWord8OffAddr# s 0# of+ c' -> case eqWord8'# c c' of 1# -> OK# () (plusAddr# s 1#) _ -> Fail# {-# inline scan8# #-} -- | Unsafely read two concrete bytes from the input. It's not checked that the input has -- enough bytes.-scan16# :: Word -> Parser e ()-scan16# (W# c) = Parser \fp eob s ->- case indexWord16OffAddr s 0# of- c' -> case eqWord# c c' of+scan16# :: Word16 -> Parser e ()+scan16# (W16# c) = Parser \fp eob s ->+ case indexWord16OffAddr# s 0# of+ c' -> case eqWord16'# c c' of 1# -> OK# () (plusAddr# s 2#) _ -> Fail# {-# inline scan16# #-} -- | Unsafely read four concrete bytes from the input. It's not checked that the input has -- enough bytes.-scan32# :: Word -> Parser e ()-scan32# (W# c) = Parser \fp eob s ->- case indexWord32OffAddr s 0# of- c' -> case eqWord# c c' of+scan32# :: Word32 -> Parser e ()+scan32# (W32# c) = Parser \fp eob s ->+ case indexWord32OffAddr# s 0# of+ c' -> case eqWord32'# c c' of 1# -> OK# () (plusAddr# s 4#) _ -> Fail# {-# inline scan32# #-}@@ -934,15 +914,15 @@ -- enough bytes. scan64# :: Word -> Parser e () scan64# (W# c) = Parser \fp eob s ->- case indexWord64OffAddr s 0# of+ case indexWord64OffAddr# s 0# of c' -> case eqWord# c c' of 1# -> OK# () (plusAddr# s 8#) _ -> Fail# {-# inline scan64# #-} -- | Unsafely read and return a byte from the input. It's not checked that the input is non-empty.-scanAny8# :: Parser e Word-scanAny8# = Parser \fp eob s -> OK# (W# (indexWord8OffAddr s 0#)) (plusAddr# s 1#)+scanAny8# :: Parser e Word8+scanAny8# = Parser \fp eob s -> OK# (W8# (indexWord8OffAddr# s 0#)) (plusAddr# s 1#) {-# inline scanAny8# #-} scanPartial64# :: Int -> Word -> Parser e ()@@ -1076,3 +1056,204 @@ !m = M.fromList ((Nothing, maybe (VarE 'empty) id fallback) : branches) !trie = compileTrie strings in (m , trie)++--------------------------------------------------------------------------------++withAnyWord8# :: (Word8'# -> Parser e a) -> Parser e a+withAnyWord8# p = Parser \fp eob buf -> case eqAddr# eob buf of+ 1# -> Fail#+ _ -> case indexWord8OffAddr# buf 0# of+ w# -> runParser# (p w#) fp eob (plusAddr# buf 1#)+{-# inline withAnyWord8# #-}++withAnyWord16# :: (Word16'# -> Parser e a) -> Parser e a+withAnyWord16# p = Parser \fp eob buf -> case 2# <=# minusAddr# eob buf of+ 0# -> Fail#+ _ -> case indexWord16OffAddr# buf 0# of+ w# -> runParser# (p w#) fp eob (plusAddr# buf 2#)+{-# inline withAnyWord16# #-}++withAnyWord32# :: (Word32'# -> Parser e a) -> Parser e a+withAnyWord32# p = Parser \fp eob buf -> case 4# <=# minusAddr# eob buf of+ 0# -> Fail#+ _ -> case indexWord32OffAddr# buf 0# of+ w# -> runParser# (p w#) fp eob (plusAddr# buf 4#)+{-# inline withAnyWord32# #-}++withAnyWord64# :: (Word# -> Parser e a) -> Parser e a+withAnyWord64# p = Parser \fp eob buf -> case 8# <=# minusAddr# eob buf of+ 0# -> Fail#+ _ -> case indexWordOffAddr# buf 0# of+ w# -> runParser# (p w#) fp eob (plusAddr# buf 8#)+{-# inline withAnyWord64# #-}++withAnyInt8# :: (Int8'# -> Parser e a) -> Parser e a+withAnyInt8# p = Parser \fp eob buf -> case eqAddr# eob buf of+ 1# -> Fail#+ _ -> case indexInt8OffAddr# buf 0# of+ i# -> runParser# (p i#) fp eob (plusAddr# buf 1#)+{-# inline withAnyInt8# #-}++withAnyInt16# :: (Int16'# -> Parser e a) -> Parser e a+withAnyInt16# p = Parser \fp eob buf -> case 2# <=# minusAddr# eob buf of+ 0# -> Fail#+ _ -> case indexInt16OffAddr# buf 0# of+ i# -> runParser# (p i#) fp eob (plusAddr# buf 2#)+{-# inline withAnyInt16# #-}++withAnyInt32# :: (Int32'# -> Parser e a) -> Parser e a+withAnyInt32# p = Parser \fp eob buf -> case 4# <=# minusAddr# eob buf of+ 0# -> Fail#+ _ -> case indexInt32OffAddr# buf 0# of+ i# -> runParser# (p i#) fp eob (plusAddr# buf 4#)+{-# inline withAnyInt32# #-}++withAnyInt64# :: (Int# -> Parser e a) -> Parser e a+withAnyInt64# p = Parser \fp eob buf -> case 8# <=# minusAddr# eob buf of+ 0# -> Fail#+ _ -> case indexInt64OffAddr# buf 0# of+ i# -> runParser# (p i#) fp eob (plusAddr# buf 8#)+{-# inline withAnyInt64# #-}++--------------------------------------------------------------------------------++-- | Parse any 'Word8' (byte).+anyWord8 :: Parser e Word8+anyWord8 = withAnyWord8# (\w# -> pure (W8# w#))+{-# inline anyWord8 #-}++-- | Skip any 'Word8' (byte).+anyWord8_ :: Parser e ()+anyWord8_ = () <$ anyWord8+{-# inline anyWord8_ #-}++-- | Parse any 'Word16'.+anyWord16 :: Parser e Word16+anyWord16 = withAnyWord16# (\w# -> pure (W16# w#))+{-# inline anyWord16 #-}++-- | Skip any 'Word16'.+anyWord16_ :: Parser e ()+anyWord16_ = () <$ anyWord16+{-# inline anyWord16_ #-}++-- | Parse any 'Word32'.+anyWord32 :: Parser e Word32+anyWord32 = withAnyWord32# (\w# -> pure (W32# w#))+{-# inline anyWord32 #-}++-- | Skip any 'Word32'.+anyWord32_ :: Parser e ()+anyWord32_ = () <$ anyWord32+{-# inline anyWord32_ #-}++-- | Parse any 'Word64'.+anyWord64 :: Parser e Word64+anyWord64 = withAnyWord64# (\w# -> pure (W64# w#))+{-# inline anyWord64 #-}++-- | Skip any 'Word64'.+anyWord64_ :: Parser e ()+anyWord64_ = () <$ anyWord64+{-# inline anyWord64_ #-}++-- | Parse any 'Word'.+anyWord :: Parser e Word+anyWord = withAnyWord64# (\w# -> pure (W# w#))+{-# inline anyWord #-}++-- | Skip any 'Word'.+anyWord_ :: Parser e ()+anyWord_ = () <$ anyWord+{-# inline anyWord_ #-}++--------------------------------------------------------------------------------++-- | Parse any 'Int8'.+anyInt8 :: Parser e Int8+anyInt8 = withAnyInt8# (\i# -> pure (I8# i#))+{-# inline anyInt8 #-}++-- | Parse any 'Int16'.+anyInt16 :: Parser e Int16+anyInt16 = withAnyInt16# (\i# -> pure (I16# i#))+{-# inline anyInt16 #-}++-- | Parse any 'Int32'.+anyInt32 :: Parser e Int32+anyInt32 = withAnyInt32# (\i# -> pure (I32# i#))+{-# inline anyInt32 #-}++-- | Parse any 'Int64'.+anyInt64 :: Parser e Int64+anyInt64 = withAnyInt64# (\i# -> pure (I64# i#))+{-# inline anyInt64 #-}++-- | Parse any 'Int'.+anyInt :: Parser e Int+anyInt = withAnyInt64# (\i# -> pure (I# i#))+{-# inline anyInt #-}++--------------------------------------------------------------------------------++-- | Parse any 'Word16' (little-endian).+anyWord16le :: Parser e Word16+anyWord16le = anyWord16+{-# inline anyWord16le #-}++-- | Parse any 'Word16' (big-endian).+anyWord16be :: Parser e Word16+anyWord16be = withAnyWord16# (\w# -> pure (W16# (byteSwap16'# w#)))+{-# inline anyWord16be #-}++-- | Parse any 'Word32' (little-endian).+anyWord32le :: Parser e Word32+anyWord32le = anyWord32+{-# inline anyWord32le #-}++-- | Parse any 'Word32' (big-endian).+anyWord32be :: Parser e Word32+anyWord32be = withAnyWord32# (\w# -> pure (W32# (byteSwap32'# w#)))+{-# inline anyWord32be #-}++-- | Parse any 'Word64' (little-endian).+anyWord64le :: Parser e Word64+anyWord64le = anyWord64+{-# inline anyWord64le #-}++-- | Parse any 'Word64' (big-endian).+anyWord64be :: Parser e Word64+anyWord64be = withAnyWord64# (\w# -> pure (W64# (byteSwap# w#)))+{-# inline anyWord64be #-}++--------------------------------------------------------------------------------++-- | Parse any 'Int16' (little-endian).+anyInt16le :: Parser e Int16+anyInt16le = anyInt16+{-# inline anyInt16le #-}++-- | Parse any 'Int16' (big-endian).+anyInt16be :: Parser e Int16+anyInt16be = withAnyWord16# (\w# -> pure (I16# (word16ToInt16# (byteSwap16'# w#))))+{-# inline anyInt16be #-}++-- | Parse any 'Int32' (little-endian).+anyInt32le :: Parser e Int32+anyInt32le = anyInt32+{-# inline anyInt32le #-}++-- | Parse any 'Int32' (big-endian).+anyInt32be :: Parser e Int32+anyInt32be = withAnyWord32# (\w# -> pure (I32# (word32ToInt32# (byteSwap32'# w#))))+{-# inline anyInt32be #-}++-- | Parse any 'Int64' (little-endian).+anyInt64le :: Parser e Int64+anyInt64le = anyInt64+{-# inline anyInt64le #-}++-- | Parse any 'Int64' (big-endian).+anyInt64be :: Parser e Int64+anyInt64be = withAnyWord64# (\w# -> pure (I64# (word2Int# (byteSwap# w#))))+{-# inline anyInt64be #-}
src/FlatParse/Internal.hs view
@@ -2,6 +2,8 @@ module FlatParse.Internal where +import FlatParse.Internal.UnboxedNumerics+ import Data.Bits import Data.Char import Data.Foldable (foldl')@@ -31,23 +33,7 @@ #endif {-# inline shortInteger #-} -#if MIN_VERSION_base(4,16,0)-indexWord8OffAddr s x = word8ToWord# (indexWord8OffAddr# s x)-indexWord16OffAddr s x = word16ToWord# (indexWord16OffAddr# s x)-indexWord32OffAddr s x = word32ToWord# (indexWord32OffAddr# s x)-indexWord64OffAddr s x = indexWord64OffAddr# s x-#else-indexWord8OffAddr = indexWord8OffAddr#-indexWord16OffAddr = indexWord16OffAddr#-indexWord32OffAddr = indexWord32OffAddr#-indexWord64OffAddr = indexWord64OffAddr#-#endif-{-# inline indexWord8OffAddr #-}-{-# inline indexWord16OffAddr #-}-{-# inline indexWord32OffAddr #-}-{-# inline indexWord64OffAddr #-} - -- Char predicates -------------------------------------------------------------------------------- @@ -76,9 +62,9 @@ readInt' :: Int# -> Addr# -> Addr# -> (# Int#, Addr# #) readInt' acc s end = case eqAddr# s end of 1# -> (# acc, s #)- _ -> case indexWord8OffAddr s 0# of- w | 1# <- leWord# 48## w, 1# <- leWord# w 57## ->- readInt' (mul10 acc +# (word2Int# w -# 48#)) (plusAddr# s 1#) end+ _ -> case indexWord8OffAddr''# s 0# of+ w | 1# <- leWord8# (wordToWord8''# 0x30##) w, 1# <- leWord8# w (wordToWord8''# 0x39##) ->+ readInt' (mul10 acc +# (word2Int# (word8ToWord''# w) -# 0x30#)) (plusAddr# s 1#) end _ -> (# acc, s #)
+ src/FlatParse/Internal/UnboxedNumerics.hs view
@@ -0,0 +1,113 @@+{- | Compatibility layer for numeric primops.++GHC 9.2 standardized unboxed numeric primops. Prior, it was quite asymmetric.+Many primop functions used the native unboxed numerics 'Word#' and 'Int#' even+if a sized unboxed numeric was in the name, e.g. 'indexWord8OffAddr#' returning+'Word#' pre-9.2. All boxed machine integers only stored 'Word#' internally!++We target GHC 9.2's better handling. In order to maintain compatibility with+older GHCs, we define missing primops and wrap ones that changed type. Usually,+we can write a few wrappers so that 9.2 uses sized unboxed numerics everywhere,+and pre-9.2 uses native unboxed numerics everywhere. Sometimes we really want to+work with sized unboxed numerics on both, in which case we have to do more+involved primop wrapping.++The general pattern is as follows:++ * A ticked primop means it's sized on >=9.2, native on <9.2+ * A double-ticked primop means it's sized on all+ * An unticked primop should mean the same as a ticked primop (no guarantees)++Also see: https://gitlab.haskell.org/ghc/ghc/-/wikis/Unboxed-Numerics+-}++module FlatParse.Internal.UnboxedNumerics where++import GHC.Exts++-- "Switch" wrappers: sized on >=9.2, native on <9.2+byteSwap16'# :: Word16'# -> Word16'#+byteSwap32'# :: Word32'# -> Word32'#+eqWord8'# :: Word8'# -> Word8'# -> Int#+eqWord16'# :: Word16'# -> Word16'# -> Int#+eqWord32'# :: Word32'# -> Word32'# -> Int#+{-# inline byteSwap16'# #-}+{-# inline byteSwap32'# #-}+{-# inline eqWord8'# #-}+{-# inline eqWord16'# #-}+{-# inline eqWord32'# #-}++-- "Sized" wrappers: sized on all+indexWord8OffAddr''# :: Addr# -> Int# -> Word8#+wordToWord8''# :: Word# -> Word8#+word8ToWord''# :: Word8# -> Word#+{-# inline indexWord8OffAddr''# #-}+{-# inline wordToWord8''# #-}+{-# inline word8ToWord''# #-}++#if MIN_VERSION_base(4,16,0)+-- GHC >=9.2++type Word8'# = Word8#+type Word16'# = Word16#+type Word32'# = Word32#+type Int8'# = Int8#+type Int16'# = Int16#+type Int32'# = Int32#++-- "Switch" wrappers: sized on >=9.2, native on <9.2+byteSwap16'# w# = wordToWord16# (byteSwap16# (word16ToWord# w#))+byteSwap32'# w# = wordToWord32# (byteSwap32# (word32ToWord# w#))+eqWord8'# = eqWord8#+eqWord16'# = eqWord16#+eqWord32'# = eqWord32#++-- "Sized" wrappers: sized on all+indexWord8OffAddr''# = indexWord8OffAddr#+wordToWord8''# = wordToWord8#+word8ToWord''# = word8ToWord#++#else+-- GHC <9.2++type Word8'# = Word#+type Word16'# = Word#+type Word32'# = Word#+type Int8'# = Int#+type Int16'# = Int#+type Int32'# = Int#++-- "Switch" wrappers: sized on >=9.2, native on <9.2+byteSwap16'# = byteSwap16#+byteSwap32'# = byteSwap32#+eqWord8'# = eqWord#+eqWord16'# = eqWord#+eqWord32'# = eqWord#++-- No need to tick wrap these, they didn't exist <9.2+word16ToInt16# :: Word16'# -> Int#+word16ToInt16# w = narrow16Int# (word2Int# w)+word32ToInt32# :: Word32'# -> Int#+word32ToInt32# w = narrow32Int# (word2Int# w)+{-# inline word16ToInt16# #-}+{-# inline word32ToInt32# #-}++-- "Sized" wrappers: sized on all+indexWord8OffAddr''# a# i# = narrowWord8# (indexWord8OffAddr# a# i#)+wordToWord8''# = narrowWord8#+word8ToWord''# = extendWord8#++#endif++#if !MIN_VERSION_base(4,13,0)+-- GHC <8.8++type Word8# = Word#+narrowWord8# :: Word# -> Word8#+narrowWord8# = narrow8Word#+extendWord8# :: Word# -> Word8#+extendWord8# w# = w#+leWord8# :: Word8# -> Word8# -> Int#+leWord8# w1# w2# = leWord# w1# w2#++#endif
src/FlatParse/Stateful.hs view
@@ -58,8 +58,15 @@ , anyWord16_ , anyWord32 , anyWord32_+ , anyWord64+ , anyWord64_ , anyWord , anyWord_+ , anyInt8+ , anyInt16+ , anyInt32+ , anyInt64+ , anyInt , anyChar , anyChar_ , anyCharASCII@@ -70,6 +77,20 @@ , FlatParse.Stateful.readInt , FlatParse.Stateful.readInteger + -- ** Explicit-endianness machine integers+ , anyWord16le+ , anyWord16be+ , anyWord32le+ , anyWord32be+ , anyWord64le+ , anyWord64be+ , anyInt16le+ , anyInt16be+ , anyInt32le+ , anyInt32be+ , anyInt64le+ , anyInt64be+ -- * Combinators , (<|>) , branch@@ -121,12 +142,23 @@ , scanBytes# , setBack# + , withAnyWord8#+ , withAnyWord16#+ , withAnyWord32#+ , withAnyWord64#+ , withAnyInt8#+ , withAnyInt16#+ , withAnyInt32#+ , withAnyInt64#+ ) where import Control.Monad import Data.Foldable import Data.Map (Map) import GHC.Exts+import GHC.Word+import GHC.Int import Language.Haskell.TH import System.IO.Unsafe import GHC.ForeignPtr@@ -137,6 +169,7 @@ import qualified Data.Map.Strict as M import FlatParse.Internal+import FlatParse.Internal.UnboxedNumerics import qualified FlatParse.Basic as Basic @@ -367,8 +400,8 @@ char c = string [c] -- | Read a byte.-byte :: Word -> Parser e ()-byte (W# w) = ensureBytes# 1 >> scan8# (W# w)+byte :: Word8 -> Parser e ()+byte w = ensureBytes# 1 >> scan8# w {-# inline byte #-} -- | Read a sequence of bytes. This is a template function, you can use it as @$(bytes [3, 4, 5])@,@@ -536,58 +569,6 @@ fusedSatisfy_ f1 f2 f3 f4 = () <$ fusedSatisfy f1 f2 f3 f4 {-# inline fusedSatisfy_ #-} --- | Parse any byte.-anyWord8 :: Parser e Word-anyWord8 = Parser \fp !r eob buf n -> case eqAddr# eob buf of- 1# -> Fail#- _ -> case indexWord8OffAddr buf 0# of- w -> OK# (W# w) (plusAddr# buf 1#) n-{-# inline anyWord8 #-}---- | Skip any byte.-anyWord8_ :: Parser e ()-anyWord8_ = () <$ anyWord8-{-# inline anyWord8_ #-}---- | Parse any `Word16`.-anyWord16 :: Parser e Word-anyWord16 = Parser \fp !r eob buf n -> case 2# <=# minusAddr# eob buf of- 0# -> Fail#- _ -> case indexWord16OffAddr buf 0# of- w -> OK# (W# w) (plusAddr# buf 2#) n-{-# inline anyWord16 #-}---- | Skip any `Word16`.-anyWord16_ :: Parser e ()-anyWord16_ = () <$ anyWord16-{-# inline anyWord16_ #-}---- | Parse any `Word32`.-anyWord32 :: Parser e Word-anyWord32 = Parser \fp !r eob buf n -> case 4# <=# minusAddr# eob buf of- 0# -> Fail#- _ -> case indexWord32OffAddr buf 0# of- w -> OK# (W# w) (plusAddr# buf 4#) n-{-# inline anyWord32 #-}---- | Skip any `Word32`.-anyWord32_ :: Parser e ()-anyWord32_ = () <$ anyWord32-{-# inline anyWord32_ #-}---- | Parse any `Word`.-anyWord :: Parser e Word-anyWord = Parser \fp !r eob buf n -> case 8# <=# minusAddr# eob buf of- 0# -> Fail#- _ -> case indexWordOffAddr# buf 0# of- w -> OK# (W# w) (plusAddr# buf 8#) n-{-# inline anyWord #-}---- | Skip any `Word`.-anyWord_ :: Parser e ()-anyWord_ = () <$ anyWord-{-# inline anyWord_ #-}- -- | Parse any UTF-8-encoded `Char`. anyChar :: Parser e Char anyChar = Parser \fp !r eob buf n -> case eqAddr# eob buf of@@ -876,30 +857,30 @@ -- | Unsafely read a concrete byte from the input. It's not checked that the input has -- enough bytes.-scan8# :: Word -> Parser e ()-scan8# (W# c) = Parser \fp !r eob s n ->- case indexWord8OffAddr s 0# of- c' -> case eqWord# c c' of+scan8# :: Word8 -> Parser e ()+scan8# (W8# c) = Parser \fp !r eob s n ->+ case indexWord8OffAddr# s 0# of+ c' -> case eqWord8'# c c' of 1# -> OK# () (plusAddr# s 1#) n _ -> Fail# {-# inline scan8# #-} -- | Unsafely read two concrete bytes from the input. It's not checked that the input has -- enough bytes.-scan16# :: Word -> Parser e ()-scan16# (W# c) = Parser \fp !r eob s n ->- case indexWord16OffAddr s 0# of- c' -> case eqWord# c c' of+scan16# :: Word16 -> Parser e ()+scan16# (W16# c) = Parser \fp !r eob s n ->+ case indexWord16OffAddr# s 0# of+ c' -> case eqWord16'# c c' of 1# -> OK# () (plusAddr# s 2#) n _ -> Fail# {-# inline scan16# #-} -- | Unsafely read four concrete bytes from the input. It's not checked that the input has -- enough bytes.-scan32# :: Word -> Parser e ()-scan32# (W# c) = Parser \fp !r eob s n ->- case indexWord32OffAddr s 0# of- c' -> case eqWord# c c' of+scan32# :: Word32 -> Parser e ()+scan32# (W32# c) = Parser \fp !r eob s n ->+ case indexWord32OffAddr# s 0# of+ c' -> case eqWord32'# c c' of 1# -> OK# () (plusAddr# s 4#) n _ -> Fail# {-# inline scan32# #-}@@ -908,15 +889,15 @@ -- enough bytes. scan64# :: Word -> Parser e () scan64# (W# c) = Parser \fp !r eob s n ->- case indexWord64OffAddr s 0# of+ case indexWord64OffAddr# s 0# of c' -> case eqWord# c c' of 1# -> OK# () (plusAddr# s 8#) n _ -> Fail# {-# inline scan64# #-} -- | Unsafely read and return a byte from the input. It's not checked that the input is non-empty.-scanAny8# :: Parser e Word-scanAny8# = Parser \fp !r eob s n -> OK# (W# (indexWord8OffAddr s 0#)) (plusAddr# s 1#) n+scanAny8# :: Parser e Word8+scanAny8# = Parser \fp !r eob s n -> OK# (W8# (indexWord8OffAddr# s 0#)) (plusAddr# s 1#) n {-# inline scanAny8# #-} scanPartial64# :: Int -> Word -> Parser e ()@@ -1050,3 +1031,204 @@ !m = M.fromList ((Nothing, maybe (VarE 'empty) id fallback) : branches) !trie = compileTrie strings in (m , trie)++--------------------------------------------------------------------------------++withAnyWord8# :: (Word8'# -> Parser e a) -> Parser e a+withAnyWord8# p = Parser \fp !r eob buf n -> case eqAddr# eob buf of+ 1# -> Fail#+ _ -> case indexWord8OffAddr# buf 0# of+ w# -> runParser# (p w#) fp r eob (plusAddr# buf 1#) n+{-# inline withAnyWord8# #-}++withAnyWord16# :: (Word16'# -> Parser e a) -> Parser e a+withAnyWord16# p = Parser \fp !r eob buf n -> case 2# <=# minusAddr# eob buf of+ 0# -> Fail#+ _ -> case indexWord16OffAddr# buf 0# of+ w# -> runParser# (p w#) fp r eob (plusAddr# buf 2#) n+{-# inline withAnyWord16# #-}++withAnyWord32# :: (Word32'# -> Parser e a) -> Parser e a+withAnyWord32# p = Parser \fp !r eob buf n -> case 4# <=# minusAddr# eob buf of+ 0# -> Fail#+ _ -> case indexWord32OffAddr# buf 0# of+ w# -> runParser# (p w#) fp r eob (plusAddr# buf 4#) n+{-# inline withAnyWord32# #-}++withAnyWord64# :: (Word# -> Parser e a) -> Parser e a+withAnyWord64# p = Parser \fp !r eob buf n -> case 8# <=# minusAddr# eob buf of+ 0# -> Fail#+ _ -> case indexWordOffAddr# buf 0# of+ w# -> runParser# (p w#) fp r eob (plusAddr# buf 8#) n+{-# inline withAnyWord64# #-}++withAnyInt8# :: (Int8'# -> Parser e a) -> Parser e a+withAnyInt8# p = Parser \fp !r eob buf n -> case eqAddr# eob buf of+ 1# -> Fail#+ _ -> case indexInt8OffAddr# buf 0# of+ i# -> runParser# (p i#) fp r eob (plusAddr# buf 1#) n+{-# inline withAnyInt8# #-}++withAnyInt16# :: (Int16'# -> Parser e a) -> Parser e a+withAnyInt16# p = Parser \fp !r eob buf n -> case 2# <=# minusAddr# eob buf of+ 0# -> Fail#+ _ -> case indexInt16OffAddr# buf 0# of+ i# -> runParser# (p i#) fp r eob (plusAddr# buf 2#) n+{-# inline withAnyInt16# #-}++withAnyInt32# :: (Int32'# -> Parser e a) -> Parser e a+withAnyInt32# p = Parser \fp !r eob buf n -> case 4# <=# minusAddr# eob buf of+ 0# -> Fail#+ _ -> case indexInt32OffAddr# buf 0# of+ i# -> runParser# (p i#) fp r eob (plusAddr# buf 4#) n+{-# inline withAnyInt32# #-}++withAnyInt64# :: (Int# -> Parser e a) -> Parser e a+withAnyInt64# p = Parser \fp !r eob buf n -> case 8# <=# minusAddr# eob buf of+ 0# -> Fail#+ _ -> case indexInt64OffAddr# buf 0# of+ i# -> runParser# (p i#) fp r eob (plusAddr# buf 8#) n+{-# inline withAnyInt64# #-}++--------------------------------------------------------------------------------++-- | Parse any 'Word8' (byte).+anyWord8 :: Parser e Word8+anyWord8 = withAnyWord8# (\w# -> pure (W8# w#))+{-# inline anyWord8 #-}++-- | Skip any 'Word8' (byte).+anyWord8_ :: Parser e ()+anyWord8_ = () <$ anyWord8+{-# inline anyWord8_ #-}++-- | Parse any 'Word16'.+anyWord16 :: Parser e Word16+anyWord16 = withAnyWord16# (\w# -> pure (W16# w#))+{-# inline anyWord16 #-}++-- | Skip any 'Word16'.+anyWord16_ :: Parser e ()+anyWord16_ = () <$ anyWord16+{-# inline anyWord16_ #-}++-- | Parse any 'Word32'.+anyWord32 :: Parser e Word32+anyWord32 = withAnyWord32# (\w# -> pure (W32# w#))+{-# inline anyWord32 #-}++-- | Skip any 'Word32'.+anyWord32_ :: Parser e ()+anyWord32_ = () <$ anyWord32+{-# inline anyWord32_ #-}++-- | Parse any 'Word64'.+anyWord64 :: Parser e Word64+anyWord64 = withAnyWord64# (\w# -> pure (W64# w#))+{-# inline anyWord64 #-}++-- | Skip any 'Word64'.+anyWord64_ :: Parser e ()+anyWord64_ = () <$ anyWord64+{-# inline anyWord64_ #-}++-- | Parse any 'Word'.+anyWord :: Parser e Word+anyWord = withAnyWord64# (\w# -> pure (W# w#))+{-# inline anyWord #-}++-- | Skip any 'Word'.+anyWord_ :: Parser e ()+anyWord_ = () <$ anyWord+{-# inline anyWord_ #-}++--------------------------------------------------------------------------------++-- | Parse any 'Int8'.+anyInt8 :: Parser e Int8+anyInt8 = withAnyInt8# (\i# -> pure (I8# i#))+{-# inline anyInt8 #-}++-- | Parse any 'Int16'.+anyInt16 :: Parser e Int16+anyInt16 = withAnyInt16# (\i# -> pure (I16# i#))+{-# inline anyInt16 #-}++-- | Parse any 'Int32'.+anyInt32 :: Parser e Int32+anyInt32 = withAnyInt32# (\i# -> pure (I32# i#))+{-# inline anyInt32 #-}++-- | Parse any 'Int64'.+anyInt64 :: Parser e Int64+anyInt64 = withAnyInt64# (\i# -> pure (I64# i#))+{-# inline anyInt64 #-}++-- | Parse any 'Int'.+anyInt :: Parser e Int+anyInt = withAnyInt64# (\i# -> pure (I# i#))+{-# inline anyInt #-}++--------------------------------------------------------------------------------++-- | Parse any 'Word16' (little-endian).+anyWord16le :: Parser e Word16+anyWord16le = anyWord16+{-# inline anyWord16le #-}++-- | Parse any 'Word16' (big-endian).+anyWord16be :: Parser e Word16+anyWord16be = withAnyWord16# (\w# -> pure (W16# (byteSwap16'# w#)))+{-# inline anyWord16be #-}++-- | Parse any 'Word32' (little-endian).+anyWord32le :: Parser e Word32+anyWord32le = anyWord32+{-# inline anyWord32le #-}++-- | Parse any 'Word32' (big-endian).+anyWord32be :: Parser e Word32+anyWord32be = withAnyWord32# (\w# -> pure (W32# (byteSwap32'# w#)))+{-# inline anyWord32be #-}++-- | Parse any 'Word64' (little-endian).+anyWord64le :: Parser e Word64+anyWord64le = anyWord64+{-# inline anyWord64le #-}++-- | Parse any 'Word64' (big-endian).+anyWord64be :: Parser e Word64+anyWord64be = withAnyWord64# (\w# -> pure (W64# (byteSwap# w#)))+{-# inline anyWord64be #-}++--------------------------------------------------------------------------------++-- | Parse any 'Int16' (little-endian).+anyInt16le :: Parser e Int16+anyInt16le = anyInt16+{-# inline anyInt16le #-}++-- | Parse any 'Int16' (big-endian).+anyInt16be :: Parser e Int16+anyInt16be = withAnyWord16# (\w# -> pure (I16# (word16ToInt16# (byteSwap16'# w#))))+{-# inline anyInt16be #-}++-- | Parse any 'Int32' (little-endian).+anyInt32le :: Parser e Int32+anyInt32le = anyInt32+{-# inline anyInt32le #-}++-- | Parse any 'Int32' (big-endian).+anyInt32be :: Parser e Int32+anyInt32be = withAnyWord32# (\w# -> pure (I32# (word32ToInt32# (byteSwap32'# w#))))+{-# inline anyInt32be #-}++-- | Parse any 'Int64' (little-endian).+anyInt64le :: Parser e Int64+anyInt64le = anyInt64+{-# inline anyInt64le #-}++-- | Parse any 'Int64' (big-endian).+anyInt64be :: Parser e Int64+anyInt64be = withAnyWord64# (\w# -> pure (I64# (word2Int# (byteSwap# w#))))+{-# inline anyInt64be #-}
test/Test.hs view
@@ -1,9 +1,16 @@+{-# LANGUAGE ScopedTypeVariables #-}+ module Main where import Data.ByteString (ByteString)+import qualified Data.ByteString as B import FlatParse.Basic import Test.HUnit import Test.Hspec+import Test.Hspec.QuickCheck+import Data.Word+import Data.Int+import Data.Bits main :: IO () main = hspec $ do@@ -201,6 +208,39 @@ describe "readInteger" $ do pure () + describe "Explicit-endianness machine integers" $ do+ describe "Unsigned" $ do+ prop "parses Word8s" $ do+ \(w :: Word8) -> anyWord8 `shouldParseWith` (w8AsByteString w, w)+ prop "parses Word16s (LE)" $ do+ \(w :: Word16) -> anyWord16le `shouldParseWith` (w16leAsByteString w, w)+ prop "parses Word16s (BE)" $ do+ \(w :: Word16) -> anyWord16be `shouldParseWith` (B.reverse (w16leAsByteString w), w)+ prop "parses Word32s (LE)" $ do+ \(w :: Word32) -> anyWord32le `shouldParseWith` (w32leAsByteString w, w)+ prop "parses Word32s (BE)" $ do+ \(w :: Word32) -> anyWord32be `shouldParseWith` (B.reverse (w32leAsByteString w), w)+ prop "parses Word64s (LE)" $ do+ \(w :: Word64) -> anyWord64le `shouldParseWith` (w64leAsByteString w, w)+ prop "parses Word64s (BE)" $ do+ \(w :: Word64) -> anyWord64be `shouldParseWith` (B.reverse (w64leAsByteString w), w)++ describe "Signed" $ do+ prop "parses Int8s" $ do+ \(i :: Int8) -> anyInt8 `shouldParseWith` (w8AsByteString i, i)+ prop "parses Int16s (LE)" $ do+ \(i :: Int16) -> anyInt16le `shouldParseWith` (w16leAsByteString i, i)+ prop "parses Int16s (BE)" $ do+ \(i :: Int16) -> anyInt16be `shouldParseWith` (B.reverse (w16leAsByteString i), i)+ prop "parses Int32s (LE)" $ do+ \(i :: Int32) -> anyInt32le `shouldParseWith` (w32leAsByteString i, i)+ prop "parses Int32s (BE)" $ do+ \(i :: Int32) -> anyInt32be `shouldParseWith` (B.reverse (w32leAsByteString i), i)+ prop "parses Int64s (LE)" $ do+ \(i :: Int64) -> anyInt64le `shouldParseWith` (w64leAsByteString i, i)+ prop "parses Int64s (BE)" $ do+ \(i :: Int64) -> anyInt64be `shouldParseWith` (B.reverse (w64leAsByteString i), i)+ describe "Combinators" $ do describe "(<|>)" $ do pure ()@@ -295,3 +335,36 @@ describe "unpackUTF8" $ do pure ()++--------------------------------------------------------------------------------++w8AsByteString :: (Bits w, Num w, Integral w) => w -> ByteString+w8AsByteString w = B.pack [b1]+ where+ b1 = fromIntegral $ w .&. 0x00FF++w16leAsByteString :: (Bits w, Num w, Integral w) => w -> ByteString+w16leAsByteString w = B.pack [b1, b2]+ where+ b1 = fromIntegral $ w .&. 0x00FF+ b2 = fromIntegral $ (w .&. 0xFF00) `shiftR` 8++w32leAsByteString :: (Bits w, Num w, Integral w) => w -> ByteString+w32leAsByteString w = B.pack [b1, b2, b3, b4]+ where+ b1 = fromIntegral $ w .&. 0x000000FF+ b2 = fromIntegral $ (w .&. 0x0000FF00) `shiftR` 8+ b3 = fromIntegral $ (w .&. 0x00FF0000) `shiftR` 16+ b4 = fromIntegral $ (w .&. 0xFF000000) `shiftR` 24++w64leAsByteString :: (Bits w, Num w, Integral w) => w -> ByteString+w64leAsByteString w = B.pack [b1, b2, b3, b4, b5, b6, b7, b8]+ where+ b1 = fromIntegral $ w .&. 0x00000000000000FF+ b2 = fromIntegral $ (w .&. 0x000000000000FF00) `shiftR` 8+ b3 = fromIntegral $ (w .&. 0x0000000000FF0000) `shiftR` 16+ b4 = fromIntegral $ (w .&. 0x00000000FF000000) `shiftR` 24+ b5 = fromIntegral $ (w .&. 0x000000FF00000000) `shiftR` 32+ b6 = fromIntegral $ (w .&. 0x0000FF0000000000) `shiftR` 40+ b7 = fromIntegral $ (w .&. 0x00FF000000000000) `shiftR` 48+ b8 = fromIntegral $ (w .&. 0xFF00000000000000) `shiftR` 56