diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Revision history for bytesmith
 
+## 0.3.11.1 -- 2024-02-28
+
+* Update package metadata.
+* Remove dependency on `run-st` library.
+
 ## 0.3.11.0 -- 2024-01-05
 
 * Add `Data.Bytes.Parser.Latin.hexWord32`.
diff --git a/Setup.hs b/Setup.hs
deleted file mode 100644
--- a/Setup.hs
+++ /dev/null
@@ -1,2 +0,0 @@
-import Distribution.Simple
-main = defaultMain
diff --git a/bench/Main.hs b/bench/Main.hs
--- a/bench/Main.hs
+++ b/bench/Main.hs
@@ -4,24 +4,28 @@
 import Data.Char (ord)
 import Data.Primitive (ByteArray)
 import Data.Word (Word8)
-import Gauge.Main (defaultMain,bench,whnf)
+import Gauge.Main (bench, defaultMain, whnf)
 
 import qualified Data.Bytes.Parser as P
 import qualified Data.Bytes.Parser.Latin as Latin
 import qualified GHC.Exts as Exts
 
 main :: IO ()
-main = defaultMain
-  [ bench "decPositiveInteger" $ whnf
-      (\x -> P.parseByteArray (Latin.decUnsignedInteger ()) x)
-      encodedBigNumber
-  ]
+main =
+  defaultMain
+    [ bench "decPositiveInteger" $
+        whnf
+          (\x -> P.parseByteArray (Latin.decUnsignedInteger ()) x)
+          encodedBigNumber
+    ]
 
 encodedBigNumber :: ByteArray
-encodedBigNumber = stringToByteArray $ show $ id @Integer $
-  246246357264327645234627753190240202405243024304504230544
-  *
-  732345623640035232405249305932503920593209520932095234651
+encodedBigNumber =
+  stringToByteArray $
+    show $
+      id @Integer $
+        246246357264327645234627753190240202405243024304504230544
+          * 732345623640035232405249305932503920593209520932095234651
 
 stringToByteArray :: String -> ByteArray
 stringToByteArray =
diff --git a/bytesmith.cabal b/bytesmith.cabal
--- a/bytesmith.cabal
+++ b/bytesmith.cabal
@@ -1,79 +1,88 @@
-cabal-version: 2.2
-name: bytesmith
-version: 0.3.11.0
-synopsis: Nonresumable byte parser
+cabal-version:   3.0
+name:            bytesmith
+version:         0.3.11.1
+synopsis:        Nonresumable byte parser
 description:
   Parse bytes as fast as possible. This is a nonresumable parser
   that aggresively uses `UnboxedSums` to avoid performing any
   allocations.
-homepage: https://github.com/andrewthad/bytesmith
-bug-reports: https://github.com/andrewthad/bytesmith/issues
-license: BSD-3-Clause
-license-file: LICENSE
-author: Andrew Martin
-maintainer: andrew.thaddeus@gmail.com
-copyright: 2019 Andrew Martin
-category: Data
-extra-source-files: CHANGELOG.md
-tested-with: GHC == 8.6.5 || == 8.8.4 || == 8.10.7 || == 9.0.2 || == 9.2.5 || == 9.4.3
 
+homepage:        https://github.com/byteverse/bytesmith
+bug-reports:     https://github.com/byteverse/bytesmith/issues
+license:         BSD-3-Clause
+license-file:    LICENSE
+author:          Andrew Martin
+maintainer:      amartin@layer3com.com
+copyright:       2019 Andrew Martin
+category:        Data
+extra-doc-files: CHANGELOG.md
+tested-with:     GHC ==9.4.8 || ==9.6.3 || ==9.8.1
+
+common build-settings
+  default-language: Haskell2010
+  ghc-options:      -Wall -Wunused-packages
+
 library
+  import:          build-settings
   exposed-modules:
     Data.Bytes.Parser
-    Data.Bytes.Parser.BigEndian
-    Data.Bytes.Parser.LittleEndian
     Data.Bytes.Parser.Ascii
     Data.Bytes.Parser.Base128
+    Data.Bytes.Parser.BigEndian
     Data.Bytes.Parser.Latin
     Data.Bytes.Parser.Leb128
+    Data.Bytes.Parser.LittleEndian
     Data.Bytes.Parser.Rebindable
     Data.Bytes.Parser.Unsafe
     Data.Bytes.Parser.Utf8
+
   other-modules:
     Data.Bytes.Parser.Internal
     Data.Bytes.Parser.Types
+
   build-depends:
-    , base >=4.12 && <5
-    , byteslice >=0.2.6 && <0.3
-    , bytestring >=0.10.8 && <=0.12
-    , contiguous >= 0.6 && < 0.7
-    , natural-arithmetic >=0.1.3
-    , primitive >=0.7 && <0.10
-    , run-st >=0.1 && <0.2
-    , text-short >=0.1.3 && <0.2
-    , wide-word >=0.1.0.9 && <0.2
-  hs-source-dirs: src
-  ghc-options: -O2 -Wall
-  default-language: Haskell2010
+    , base                >=4.12    && <5
+    , byteslice           >=0.2.6   && <0.3
+    , bytestring          >=0.10.8  && <0.13
+    , contiguous          >=0.6     && <0.7
+    , natural-arithmetic  >=0.1.3
+    , primitive           >=0.7     && <0.10
+    , text-short          >=0.1.3   && <0.2
+    , wide-word           >=0.1.0.9 && <0.2
 
+  hs-source-dirs:  src
+  ghc-options:     -O2
+
 test-suite test
-  default-language: Haskell2010
-  type: exitcode-stdio-1.0
+  import:         build-settings
+  type:           exitcode-stdio-1.0
   hs-source-dirs: test
-  main-is: Main.hs
-  ghc-options: -Wall -O2
+  main-is:        Main.hs
   build-depends:
-    , base >=4.12.0.0 && <5
+    , base              >=4.12.0.0 && <5
+    , byte-order
+    , byteslice
     , bytesmith
     , primitive
-    , byteslice
-    , tasty-hunit
     , tasty
+    , tasty-hunit
     , tasty-quickcheck
-    , byte-order
     , text-short
     , wide-word
 
 benchmark bench
-  type: exitcode-stdio-1.0
+  import:         build-settings
+  type:           exitcode-stdio-1.0
   build-depends:
     , base
-    , byteslice
-    , bytestring
+    , bytesmith
     , gauge
     , primitive
-    , bytesmith
-  ghc-options: -Wall -O2
-  default-language: Haskell2010
+
+  ghc-options:    -O2
   hs-source-dirs: bench
-  main-is: Main.hs
+  main-is:        Main.hs
+
+source-repository head
+  type:     git
+  location: git://github.com/byteverse/bytesmith.git
diff --git a/src/Data/Bytes/Parser.hs b/src/Data/Bytes/Parser.hs
--- a/src/Data/Bytes/Parser.hs
+++ b/src/Data/Bytes/Parser.hs
@@ -1,90 +1,104 @@
-{-# language BangPatterns #-}
-{-# language BinaryLiterals #-}
-{-# language DataKinds #-}
-{-# language DeriveFunctor #-}
-{-# language DerivingStrategies #-}
-{-# language GADTSyntax #-}
-{-# language KindSignatures #-}
-{-# language LambdaCase #-}
-{-# language MagicHash #-}
-{-# language MultiWayIf #-}
-{-# language PolyKinds #-}
-{-# language RankNTypes #-}
-{-# language ScopedTypeVariables #-}
-{-# language StandaloneDeriving #-}
-{-# language TypeApplications #-}
-{-# language UnboxedSums #-}
-{-# language UnboxedTuples #-}
-{-# language CPP #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE BinaryLiterals #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE GADTSyntax #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE MultiWayIf #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE UnboxedTuples #-}
 
--- | Parse non-resumable sequence of bytes. To parse a byte sequence
--- as text, use the @Ascii@, @Latin@, and @Utf8@ modules instead.
--- Functions for parsing decimal-encoded numbers are found in those
--- modules.
+{- | Parse non-resumable sequence of bytes. To parse a byte sequence
+as text, use the @Ascii@, @Latin@, and @Utf8@ modules instead.
+Functions for parsing decimal-encoded numbers are found in those
+modules.
+-}
 module Data.Bytes.Parser
   ( -- * Types
     Parser
-  , Result(..)
-  , Slice(..)
+  , Result (..)
+  , Slice (..)
+
     -- * Run Parsers
+
     -- ** Result
   , parseByteArray
   , parseBytes
   , parseBytesEffectfully
   , parseBytesEither
   , parseBytesMaybe
+
     -- * One Byte
   , any
+
     -- * Many Bytes
   , take
   , takeN
   , takeUpTo
   , takeWhile
   , takeTrailedBy
+
     -- * Skip
   , skipWhile
   , skipTrailedBy
   , skipTrailedBy2
   , skipTrailedBy2#
   , skipTrailedBy3#
+
     -- * Match
   , byteArray
   , bytes
   , satisfy
   , satisfyWith
   , cstring
+
     -- * End of Input
   , endOfInput
   , isEndOfInput
   , remaining
   , peekRemaining
+
     -- * Scanning
   , scan
+
     -- * Lookahead
   , peek
   , peek'
+
     -- * Control Flow
   , fail
   , orElse
   , annotate
   , (<?>)
   , mapErrorEffectfully
+
     -- * Repetition
   , replicate
+
     -- * Subparsing
   , delimit
   , measure
   , measure_
   , measure_#
+
     -- * Lift Effects
   , effect
+
     -- * Box Result
   , boxWord32
   , boxIntPair
+
     -- * Unbox Result
   , unboxWord32
   , unboxIntPair
+
     -- * Specialized Bind
+
     -- | Sometimes, GHC ends up building join points in a way that
     -- boxes arguments unnecessarily. In this situation, special variants
     -- of monadic @>>=@ can be helpful. If @C#@, @I#@, etc. never
@@ -96,26 +110,26 @@
   , bindFromCharToIntPair
   , bindFromMaybeCharToIntPair
   , bindFromMaybeCharToLifted
+
     -- * Specialized Pure
   , pureIntPair
+
     -- * Specialized Fail
   , failIntPair
   ) where
 
-import Prelude hiding (length,any,fail,takeWhile,take,replicate)
+import Prelude hiding (any, fail, length, replicate, take, takeWhile)
 
-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))
-import Data.Bytes.Parser.Unsafe (unconsume,expose,cursor)
-import Data.Bytes.Types (Bytes(..),BytesN(BytesN))
-import Data.Primitive (ByteArray(..))
-import Data.Primitive.Contiguous (Contiguous,Element)
+import Data.Bytes.Parser.Internal (Parser (..), Result#, ST#, boxBytes, fail, unboxBytes, uneffectful, uneffectful#, uneffectfulInt#)
+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))
+import Data.Primitive (ByteArray (..))
+import Data.Primitive.Contiguous (Contiguous, Element)
 import Foreign.C.String (CString)
-import GHC.Exts (Int(I#),Word#,Int#,Char#,runRW#,(+#),(-#),(>=#))
-import GHC.ST (ST(..))
-import GHC.Word (Word32(W32#),Word8)
+import GHC.Exts (Char#, Int (I#), Int#, Word#, runRW#, (+#), (-#), (>=#))
+import GHC.ST (ST (..))
+import GHC.Word (Word32 (W32#), Word8)
 
 import qualified Arithmetic.Nat as Nat
 import qualified Arithmetic.Types as Arithmetic
@@ -125,49 +139,52 @@
 import qualified Data.Primitive.Contiguous as C
 import qualified GHC.Exts as Exts
 
--- | Parse a byte sequence. This can succeed even if the
--- entire slice was not consumed by the parser.
+{- | 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 #-}
+{-# INLINE parseBytes #-}
 parseBytes p !b = runResultST action
-  where
+ where
   action :: forall s. ST# s (Result# e a)
   action s0 = case p @s of
     Parser f -> f (unboxBytes b) s0
 
--- | Variant of 'parseBytesEither' that discards the error message on failure.
--- Just like 'parseBytesEither', this does not impose any checks on the length
--- of the remaining input.
+{- | Variant of 'parseBytesEither' that discards the error message on failure.
+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 #-}
+{-# INLINE parseBytesMaybe #-}
 parseBytesMaybe p !b = runMaybeST action
-  where
+ where
   action :: forall s. ST# s (Result# e a)
   action s0 = case p @s of
     Parser f -> f (unboxBytes b) s0
 
--- | Variant of 'parseBytes' that discards the new offset and the
--- remaining length. This does not, however, require the remaining
--- length to be zero. Use 'endOfInput' to accomplish that.
+{- | Variant of 'parseBytes' that discards the new offset and the
+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 #-}
+{-# INLINE parseBytesEither #-}
 parseBytesEither p !b = runEitherST action
-  where
+ where
   action :: forall s. ST# s (Result# e a)
   action s0 = case p @s of
     Parser f -> f (unboxBytes b) s0
 
 -- 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
+{-# 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
+{-# INLINE runEitherST #-}
+runEitherST f = case (runRW# (\s0 -> case f s0 of (# _, r #) -> r)) of
   (# e | #) -> Left e
   (# | (# x, _, _ #) #) -> Right x
 
@@ -177,49 +194,56 @@
 -- 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
+{-# 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 #-}
+{-# 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.
+{- | 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 #)
-  )
+{-# INLINE parseBytesEffectfully #-}
+parseBytesEffectfully (Parser f) !b =
+  ST
+    ( \s0 -> case f (unboxBytes b) s0 of
+        (# s1, r #) -> (# s1, boxPublicResult r #)
+    )
 
 -- | 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 #) #) #)
-  )
+{-# 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 #-}
+{-# INLINE byteArray #-}
 byteArray e !expected = bytes e (B.fromByteArray expected)
 
 -- | Consume input matching the byte sequence.
 bytes :: e -> Bytes -> Parser e s ()
-bytes e !expected = Parser
-  ( \actual@(# _, off, len #) s ->
-    let r = if B.isPrefixOf expected (boxBytes actual)
-          then let !(I# movement) = length expected in
-            (# | (# (), off +# movement, len -# movement #) #)
-          else (# e | #)
-     in (# s, r #)
-  )
+bytes e !expected =
+  Parser
+    ( \actual@(# _, off, len #) s ->
+        let r =
+              if B.isPrefixOf expected (boxBytes actual)
+                then
+                  let !(I# movement) = length expected
+                   in (# | (# (), off +# movement, len -# movement #) #)
+                else (# e | #)
+         in (# s, r #)
+    )
 
+{- FOURMOLU_DISABLE -}
 -- | Consume input matching the @NUL@-terminated C String.
 cstring :: e -> CString -> Parser e s ()
 cstring e (Exts.Ptr ptr0) = Parser
@@ -241,6 +265,7 @@
               _ -> (# s, (# e | #) #)
      in go ptr0 off0 len0
   )
+{- FOURMOLU_ENABLE -}
 
 infix 0 <?>
 
@@ -248,57 +273,65 @@
 (<?>) :: Parser x s a -> e -> Parser e s a
 (<?>) = annotate
 
--- | Annotate a parser. If the parser fails, the error will
---   be returned.
+{- | Annotate a parser. If the parser fails, the error will
+  be returned.
+-}
 annotate :: Parser x s a -> e -> Parser e s a
 annotate p e = p `orElse` fail e
 
--- | Consumes and returns the next byte in the input.
--- Fails if no characters are left.
+{- | Consumes and returns the next byte in the input.
+Fails if no characters are left.
+-}
 any :: e -> Parser e s Word8
-{-# inline any #-}
-any e = uneffectful $ \chunk -> if length chunk > 0
-  then
-    let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8
-     in Internal.Success w (offset chunk + 1) (length chunk - 1)
-  else Internal.Failure e
+{-# INLINE any #-}
+any e = uneffectful $ \chunk ->
+  if length chunk > 0
+    then
+      let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8
+       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.
---
---   /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.
+{- | Match any byte, 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 Word8)
-{-# inline peek #-}
+{-# INLINE peek #-}
 peek = uneffectful $ \chunk ->
-  let v = if length chunk > 0
-        then Just (B.unsafeIndex chunk 0)
-        else Nothing
-  in Internal.Success v (offset chunk) (length chunk)
+  let v =
+        if length chunk > 0
+          then Just (B.unsafeIndex chunk 0)
+          else Nothing
+   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.
+{- | 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 Internal.Success (B.unsafeIndex chunk 0) (offset chunk) (length chunk)
-  else Internal.Failure e
+{-# INLINE peek' #-}
+peek' e = uneffectful $ \chunk ->
+  if length chunk > 0
+    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
---   successive invocations of the predicate on each byte of the input
---   until one returns 'Nothing' or the input ends.
---
---   This parser does not fail. It will return the initial state
---   if the predicate returns 'Nothing' on the first byte of input.
---
---   /Note/: Because this parser does not fail, do not use it with
---   combinators such a 'many', because such parsers loop until a
---   failure occurs. Careless use will thus result in an infinite loop.
+{- | A stateful scanner. The predicate consumes and transforms a
+  state argument, and each transformed state is passed to
+  successive invocations of the predicate on each byte of the input
+  until one returns 'Nothing' or the input ends.
+
+  This parser does not fail. It will return the initial state
+  if the predicate returns 'Nothing' on the first byte of input.
+
+  /Note/: Because this parser does not fail, do not use it with
+  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 #-}
+{-# INLINE scan #-}
 scan s0 t = do
   let go s = do
         mw <- peek
@@ -313,26 +346,28 @@
 -- Does not check to see if any characters are left. This
 -- is not exported.
 anyUnsafe :: Parser e s Word8
-{-# inline anyUnsafe #-}
+{-# INLINE anyUnsafe #-}
 anyUnsafe = uneffectful $ \chunk ->
   let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8
    in Internal.Success w (offset chunk + 1) (length chunk - 1)
 
--- | Take while the predicate is matched. This is always inlined. This
--- always succeeds.
+{- | Take while the predicate is matched. This is always inlined. This
+always succeeds.
+-}
 takeWhile :: (Word8 -> Bool) -> Parser e s Bytes
-{-# inline takeWhile #-}
+{-# INLINE takeWhile #-}
 takeWhile f = uneffectful $ \chunk -> case B.takeWhile f chunk of
   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.
--- Visually, the cursor advancement and resulting @Bytes@ for
--- @takeTrailedBy 0x19@ look like this:
---
--- >  0x10 0x13 0x08 0x15 0x19 0x23 0x17 | input
--- > |---->---->---->---->----|          | cursor
--- > {----*----*----*----}               | result bytes
+{- | Take bytes until the specified byte is encountered. Consumes
+the matched byte as well. Fails if the byte is not present.
+Visually, the cursor advancement and resulting @Bytes@ for
+@takeTrailedBy 0x19@ look like this:
+
+>  0x10 0x13 0x08 0x15 0x19 0x23 0x17 | input
+> |---->---->---->---->----|          | cursor
+> {\----*----*----*----\}               | result bytes
+-}
 takeTrailedBy :: e -> Word8 -> Parser e s Bytes
 takeTrailedBy e !w = do
   !start <- cursor
@@ -341,107 +376,129 @@
   !arr <- expose
   pure (Bytes arr start (end - (start + 1)))
 
--- | Skip all characters until the character from the is encountered
--- and then consume the matching byte as well.
+{- | 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 #-}
+{-# INLINE skipTrailedBy #-}
 skipTrailedBy e !w = uneffectful# (\c -> skipUntilConsumeByteLoop e w c)
 
 skipUntilConsumeByteLoop ::
-     e -- Error message
-  -> Word8 -- byte to match
-  -> Bytes -- Chunk
-  -> Result# e ()
-skipUntilConsumeByteLoop e !w !c = if length c > 0
-  then if PM.indexByteArray (array c) (offset c) /= (w :: Word8)
-    then skipUntilConsumeByteLoop e w (B.unsafeDrop 1 c)
-    else (# | (# (), unI (offset c + 1), unI (length c - 1) #) #)
-  else (# e | #)
+  e -> -- Error message
+  Word8 -> -- byte to match
+  Bytes -> -- Chunk
+  Result# e ()
+skipUntilConsumeByteLoop e !w !c =
+  if length c > 0
+    then
+      if PM.indexByteArray (array c) (offset c) /= (w :: Word8)
+        then skipUntilConsumeByteLoop e w (B.unsafeDrop 1 c)
+        else (# | (# (), unI (offset c + 1), unI (length c - 1) #) #)
+    else (# e | #)
 
--- | Skip all bytes until either of the bytes in encountered. Then,
--- consume the matched byte. @True@ indicates that the first argument
--- byte was encountered. @False@ indicates that the second argument
--- byte was encountered.
+{- | Skip all bytes until either of the bytes in encountered. Then,
+consume the matched byte. @True@ indicates that the first argument
+byte was encountered. @False@ indicates that the second argument
+byte was encountered.
+-}
 skipTrailedBy2 ::
-     e -- ^ Error message
-  -> Word8 -- ^ First trailer, @False@ indicates that this was encountered
-  -> Word8 -- ^ Second trailer, @True@ indicates that this was encountered
-  -> Parser e s Bool
-{-# inline skipTrailedBy2 #-}
+  -- | Error message
+  e ->
+  -- | First trailer, @False@ indicates that this was encountered
+  Word8 ->
+  -- | Second trailer, @True@ indicates that this was encountered
+  Word8 ->
+  Parser e s Bool
+{-# INLINE skipTrailedBy2 #-}
 skipTrailedBy2 e !wa !wb = boxBool (skipTrailedBy2# e wa wb)
 
 skipTrailedBy2# ::
-     e -- ^ Error message
-  -> Word8 -- ^ First trailer, 0 indicates that this was encountered
-  -> Word8 -- ^ Second trailer, 1 indicates that this was encountered
-  -> Parser e s Int#
-{-# inline skipTrailedBy2# #-}
+  -- | Error message
+  e ->
+  -- | First trailer, 0 indicates that this was encountered
+  Word8 ->
+  -- | Second trailer, 1 indicates that this was encountered
+  Word8 ->
+  Parser e s Int#
+{-# INLINE skipTrailedBy2# #-}
 skipTrailedBy2# e !wa !wb =
   uneffectfulInt# (\c -> skipUntilConsumeByteEitherLoop e wa wb c)
 
 skipTrailedBy3# ::
-     e -- ^ Error message
-  -> Word8 -- ^ First trailer, 0 indicates that this was encountered
-  -> Word8 -- ^ Second trailer, 1 indicates that this was encountered
-  -> Word8 -- ^ Third trailer, 2 indicates that this was encountered
-  -> Parser e s Int#
-{-# inline skipTrailedBy3# #-}
+  -- | Error message
+  e ->
+  -- | First trailer, 0 indicates that this was encountered
+  Word8 ->
+  -- | Second trailer, 1 indicates that this was encountered
+  Word8 ->
+  -- | Third trailer, 2 indicates that this was encountered
+  Word8 ->
+  Parser e s Int#
+{-# INLINE skipTrailedBy3# #-}
 skipTrailedBy3# e !wa !wb !wc =
   uneffectfulInt# (\c -> skipUntilConsumeByte3Loop e wa wb wc c)
 
 skipUntilConsumeByteEitherLoop ::
-     e -- Error message
-  -> Word8 -- first trailer
-  -> Word8 -- second trailer
-  -> Bytes -- Chunk
-  -> Result# e Int#
-skipUntilConsumeByteEitherLoop e !wa !wb !c = if length c > 0
-  then let byte = PM.indexByteArray (array c) (offset c) in
-    if | byte == wa -> (# | (# 0#, unI (offset c + 1), unI (length c - 1) #) #)
-       | byte == wb -> (# | (# 1#, unI (offset c + 1), unI (length c - 1) #) #)
-       | otherwise -> skipUntilConsumeByteEitherLoop e wa wb (B.unsafeDrop 1 c)
-  else (# e | #)
+  e -> -- Error message
+  Word8 -> -- first trailer
+  Word8 -> -- second trailer
+  Bytes -> -- Chunk
+  Result# e Int#
+skipUntilConsumeByteEitherLoop e !wa !wb !c =
+  if length c > 0
+    then
+      let byte = PM.indexByteArray (array c) (offset c)
+       in if
+            | byte == wa -> (# | (# 0#, unI (offset c + 1), unI (length c - 1) #) #)
+            | byte == wb -> (# | (# 1#, unI (offset c + 1), unI (length c - 1) #) #)
+            | otherwise -> skipUntilConsumeByteEitherLoop e wa wb (B.unsafeDrop 1 c)
+    else (# e | #)
 
 skipUntilConsumeByte3Loop ::
-     e -- Error message
-  -> Word8 -- first trailer
-  -> Word8 -- second trailer
-  -> Word8 -- third trailer
-  -> Bytes -- Chunk
-  -> Result# e Int#
-skipUntilConsumeByte3Loop e !wa !wb !wc !c = if length c > 0
-  then let byte = PM.indexByteArray (array c) (offset c) in
-    if | byte == wa -> (# | (# 0#, unI (offset c + 1), unI (length c - 1) #) #)
-       | byte == wb -> (# | (# 1#, unI (offset c + 1), unI (length c - 1) #) #)
-       | byte == wc -> (# | (# 2#, unI (offset c + 1), unI (length c - 1) #) #)
-       | otherwise -> skipUntilConsumeByte3Loop e wa wb wc (B.unsafeDrop 1 c)
-  else (# e | #)
+  e -> -- Error message
+  Word8 -> -- first trailer
+  Word8 -> -- second trailer
+  Word8 -> -- third trailer
+  Bytes -> -- Chunk
+  Result# e Int#
+skipUntilConsumeByte3Loop e !wa !wb !wc !c =
+  if length c > 0
+    then
+      let byte = PM.indexByteArray (array c) (offset c)
+       in if
+            | byte == wa -> (# | (# 0#, unI (offset c + 1), unI (length c - 1) #) #)
+            | byte == wb -> (# | (# 1#, unI (offset c + 1), unI (length c - 1) #) #)
+            | byte == wc -> (# | (# 2#, unI (offset c + 1), unI (length c - 1) #) #)
+            | otherwise -> skipUntilConsumeByte3Loop e wa wb wc (B.unsafeDrop 1 c)
+    else (# e | #)
 
--- | Take the given number of bytes. Fails if there is not enough
---   remaining input.
+{- | Take the given number of bytes. Fails if there is not enough
+  remaining input.
+-}
 take :: e -> Int -> Parser e s Bytes
-{-# inline take #-}
-take e n = uneffectful $ \chunk -> if n <= B.length chunk
-  then case B.unsafeTake n chunk of
-    bs -> Internal.Success bs (offset chunk + n) (length chunk - n)
-  else Internal.Failure e
+{-# INLINE take #-}
+take e n = uneffectful $ \chunk ->
+  if n <= B.length chunk
+    then case B.unsafeTake n chunk of
+      bs -> Internal.Success bs (offset chunk + n) (length chunk - n)
+    else Internal.Failure e
 
 -- | Variant of 'take' that tracks the length of the result in the result type.
 takeN :: e -> Arithmetic.Nat n -> Parser e s (BytesN n)
-takeN e n0 = uneffectful $ \chunk -> if n <= B.length chunk
-  then case B.unsafeTake n chunk of
-    Bytes theChunk theOff _ -> Internal.Success (BytesN theChunk theOff) (offset chunk + n) (length chunk - n)
-  else Internal.Failure e
-  where
+takeN e n0 = uneffectful $ \chunk ->
+  if n <= B.length chunk
+    then case B.unsafeTake n chunk of
+      Bytes theChunk theOff _ -> Internal.Success (BytesN theChunk theOff) (offset chunk + n) (length chunk - n)
+    else Internal.Failure e
+ where
   !n = Nat.demote n0
 
-
-
--- | Take at most the given number of bytes. This is greedy. It will
---   consume as many bytes as there are available until it has consumed
---   @n@ bytes. This never fails.
+{- | Take at most the given number of bytes. This is greedy. It will
+  consume as many bytes as there are available until it has consumed
+  @n@ bytes. This never fails.
+-}
 takeUpTo :: Int -> Parser e s Bytes
-{-# inline takeUpTo #-}
+{-# INLINE takeUpTo #-}
 takeUpTo n = uneffectful $ \chunk ->
   let m = min n (B.length chunk)
    in case B.unsafeTake m chunk of
@@ -449,68 +506,76 @@
 
 -- | Consume all remaining bytes in the input.
 remaining :: Parser e s Bytes
-{-# inline remaining #-}
+{-# INLINE remaining #-}
 remaining = uneffectful $ \chunk ->
   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 #-}
+{-# INLINE peekRemaining #-}
 peekRemaining = uneffectful $ \b@(Bytes _ off len) ->
   Internal.Success b off len
 
 -- | Skip while the predicate is matched. This is always inlined.
 skipWhile :: (Word8 -> Bool) -> Parser e s ()
-{-# inline skipWhile #-}
-skipWhile f = go where
-  go = isEndOfInput >>= \case
-    True -> pure ()
-    False -> do
-      w <- anyUnsafe
-      if f w
-        then go
-        else unconsume 1
+{-# INLINE skipWhile #-}
+skipWhile f = go
+ where
+  go =
+    isEndOfInput >>= \case
+      True -> pure ()
+      False -> do
+        w <- anyUnsafe
+        if f w
+          then go
+          else unconsume 1
 
--- | The parser @satisfy p@ succeeds for any byte for which the
---   predicate @p@ returns 'True'. Returns the byte that is
---   actually parsed.
+{- | The parser @satisfy p@ succeeds for any byte for which the
+  predicate @p@ returns 'True'. Returns the byte that is
+  actually parsed.
+-}
 satisfy :: e -> (Word8 -> Bool) -> Parser e s Word8
 satisfy e p = satisfyWith e id p
-{-# inline satisfy #-}
+{-# INLINE satisfy #-}
 
--- | The parser @satisfyWith f p@ transforms a byte, and succeeds
---   if the predicate @p@ returns 'True' on the transformed value.
---   The parser returns the transformed byte that was parsed.
+{- | The parser @satisfyWith f p@ transforms a byte, and succeeds
+  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 > 0
-  then case B.unsafeIndex chunk 0 of
-    w ->
-      let v = f w
-      in if p v
-        then Internal.Success v (offset chunk + 1) (length chunk - 1)
-        else Internal.Failure e
-  else Internal.Failure e
+{-# INLINE satisfyWith #-}
+satisfyWith e f p = uneffectful $ \chunk ->
+  if length chunk > 0
+    then case B.unsafeIndex chunk 0 of
+      w ->
+        let v = f w
+         in if p v
+              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 ()
-{-# inline endOfInput #-}
-endOfInput e = uneffectful $ \chunk -> if length chunk == 0
-  then Internal.Success () (offset chunk) 0
-  else Internal.Failure e
+{-# INLINE endOfInput #-}
+endOfInput e = uneffectful $ \chunk ->
+  if length chunk == 0
+    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.
+{- | Returns true if there are no more bytes in the input. Returns
+false otherwise. Always succeeds.
+-}
 isEndOfInput :: Parser e s Bool
-{-# inline isEndOfInput #-}
+{-# INLINE isEndOfInput #-}
 isEndOfInput = uneffectful $ \chunk ->
   Internal.Success (length chunk == 0) (offset chunk) (length chunk)
 
 boxPublicResult :: Result# e a -> Result e a
-{-# inline boxPublicResult #-}
+{-# INLINE boxPublicResult #-}
 boxPublicResult (# | (# a, b, c #) #) = Success (Slice (I# b) (I# c) a)
 boxPublicResult (# e | #) = Failure e
 
+{- FOURMOLU_DISABLE -}
 -- | Convert a 'Word32' parser to a 'Word#' parser.
 unboxWord32 :: Parser e s Word32 -> Parser e s Word#
 {-# inline unboxWord32 #-}
@@ -524,17 +589,20 @@
 #endif
         a, b, c #) #) #)
   )
+{- FOURMOLU_ENABLE -}
 
 -- | 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
-      (# e | #) -> (# s1, (# e | #) #)
-      (# | (# (I# y, I# z), b, c #) #) -> (# s1, (# | (# (# y, z #), b, c #) #) #)
-  )
+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
+          (# e | #) -> (# s1, (# e | #) #)
+          (# | (# (I# y, I# z), b, c #) #) -> (# s1, (# | (# (# y, z #), b, c #) #) #)
+    )
 
+{- FOURMOLU_DISABLE -}
 -- | 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
@@ -549,233 +617,263 @@
 #endif
         a), b, c #) #) #)
   )
+{- FOURMOLU_ENABLE -}
 
 -- | Convert a @(# Int#, Int# #)@ parser to a @(Int,Int)@ parser.
 boxInt :: Parser e s Int# -> Parser e s Int
-{-# inline boxInt #-}
-boxInt (Parser f) = Parser
-  (\x s0 -> case f x s0 of
-    (# s1, r #) -> case r of
-      (# e | #) -> (# s1, (# e | #) #)
-      (# | (# y, b, c #) #) -> (# s1, (# | (# I# y, b, c #) #) #)
-  )
+{-# INLINE boxInt #-}
+boxInt (Parser f) =
+  Parser
+    ( \x s0 -> case f x s0 of
+        (# s1, r #) -> case r of
+          (# e | #) -> (# s1, (# e | #) #)
+          (# | (# y, b, c #) #) -> (# s1, (# | (# I# y, b, c #) #) #)
+    )
 
 -- | Convert a @(# Int#, Int# #)@ parser to a @(Int,Int)@ parser.
 boxBool :: Parser e s Int# -> Parser e s Bool
-{-# inline boxBool #-}
-boxBool (Parser f) = Parser
-  (\x s0 -> case f x s0 of
-    (# s1, r #) -> case r of
-      (# e | #) -> (# s1, (# e | #) #)
-      (# | (# y, b, c #) #) -> (# s1, (# | (# case y of {1# -> True; _ -> False}, b, c #) #) #)
-  )
+{-# INLINE boxBool #-}
+boxBool (Parser f) =
+  Parser
+    ( \x s0 -> case f x s0 of
+        (# s1, r #) -> case r of
+          (# e | #) -> (# s1, (# e | #) #)
+          (# | (# y, b, c #) #) -> (# s1, (# | (# case y of 1# -> True; _ -> False, b, c #) #) #)
+    )
 
 -- | 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
-      (# e | #) -> (# s1, (# e | #) #)
-      (# | (# (# y, z #), b, c #) #) -> (# s1, (# | (# (I# y, I# z), b, c #) #) #)
-  )
-
+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
+          (# e | #) -> (# s1, (# e | #) #)
+          (# | (# (# y, z #), b, c #) #) -> (# s1, (# | (# (I# y, I# z), b, c #) #) #)
+    )
 
--- | There is a law-abiding instance of 'Alternative' for 'Parser'.
--- However, it is not terribly useful since error messages seldom
--- have a 'Monoid' instance. This function is a variant of @\<|\>@
--- that is right-biased in its treatment of error messages.
--- Consequently, @orElse@ lacks an identity.
--- See <https://github.com/bos/attoparsec/issues/122 attoparsec issue #122>
--- for more discussion of this topic.
+{- | There is a law-abiding instance of 'Alternative' for 'Parser'.
+However, it is not terribly useful since error messages seldom
+have a 'Monoid' instance. This function is a variant of @\<|\>@
+that is right-biased in its treatment of error messages.
+Consequently, @orElse@ lacks an identity.
+See <https://github.com/bos/attoparsec/issues/122 attoparsec issue #122>
+for more discussion of this topic.
+-}
 infixl 3 `orElse`
+
 orElse :: Parser x s a -> Parser e s a -> Parser e s a
-{-# inline orElse #-}
-orElse (Parser f) (Parser g) = Parser
-  (\x s0 -> case f x s0 of
-    (# s1, r0 #) -> case r0 of
-      (# _ | #) -> g x s1
-      (# | r #) -> (# s1, (# | r #) #)
-  )
+{-# INLINE orElse #-}
+orElse (Parser f) (Parser g) =
+  Parser
+    ( \x s0 -> case f x s0 of
+        (# s1, r0 #) -> case r0 of
+          (# _ | #) -> g x s1
+          (# | r #) -> (# s1, (# | r #) #)
+    )
 
 -- | Effectfully adjusts the error message if an error occurs.
 mapErrorEffectfully :: (e1 -> ST s e2) -> Parser e1 s a -> Parser e2 s a
-{-# inline mapErrorEffectfully #-}
-mapErrorEffectfully f (Parser g) = Parser
-  (\x s0 -> case g x s0 of
-    (# s1, r0 #) -> case r0 of
-      (# e | #) -> case f e of
-        ST h -> case h s1 of
-          (# s2, e' #) -> (# s2, (# e' | #) #)
-      (# | r #) -> (# s1, (# | r #) #)
-  )
+{-# INLINE mapErrorEffectfully #-}
+mapErrorEffectfully f (Parser g) =
+  Parser
+    ( \x s0 -> case g x s0 of
+        (# s1, r0 #) -> case r0 of
+          (# e | #) -> case f e of
+            ST h -> case h s1 of
+              (# s2, e' #) -> (# s2, (# e' | #) #)
+          (# | r #) -> (# s1, (# | r #) #)
+    )
 
 bindFromCharToLifted :: Parser s e Char# -> (Char# -> Parser s e a) -> Parser s e a
-{-# inline bindFromCharToLifted #-}
-bindFromCharToLifted (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
-  )
+{-# INLINE bindFromCharToLifted #-}
+bindFromCharToLifted (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 = 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
-  )
+{-# INLINE bindFromCharToIntPair #-}
+bindFromCharToIntPair (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
+    )
 
 bindFromLiftedToInt :: Parser s e a -> (a -> Parser s e Int#) -> Parser s e Int#
-{-# inline bindFromLiftedToInt #-}
-bindFromLiftedToInt (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
-  )
+{-# INLINE bindFromLiftedToInt #-}
+bindFromLiftedToInt (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 = 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
-  )
+{-# INLINE bindFromLiftedToIntPair #-}
+bindFromLiftedToIntPair (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
+    )
 
 bindFromIntToIntPair :: Parser s e Int# -> (Int# -> Parser s e (# Int#, Int# #)) -> Parser s e (# Int#, Int# #)
-{-# inline bindFromIntToIntPair #-}
-bindFromIntToIntPair (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
-  )
+{-# INLINE bindFromIntToIntPair #-}
+bindFromIntToIntPair (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
+    )
 
 bindFromMaybeCharToIntPair ::
-     Parser s e (# (# #) | Char# #)
-  -> ((# (# #) | Char# #) -> Parser s e (# Int#, Int# #))
-  -> Parser s e (# Int#, Int# #)
-{-# inline bindFromMaybeCharToIntPair #-}
-bindFromMaybeCharToIntPair (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
-  )
+  Parser s e (# (# #) | Char# #) ->
+  ((# (# #) | Char# #) -> Parser s e (# Int#, Int# #)) ->
+  Parser s e (# Int#, Int# #)
+{-# INLINE bindFromMaybeCharToIntPair #-}
+bindFromMaybeCharToIntPair (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
+    )
 
 bindFromMaybeCharToLifted ::
-     Parser s e (# (# #) | Char# #)
-  -> ((# (# #) | Char# #) -> Parser s e a)
-  -> Parser s e a
-{-# inline bindFromMaybeCharToLifted #-}
-bindFromMaybeCharToLifted (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
-  )
+  Parser s e (# (# #) | Char# #) ->
+  ((# (# #) | Char# #) -> Parser s e a) ->
+  Parser s e a
+{-# INLINE bindFromMaybeCharToLifted #-}
+bindFromMaybeCharToLifted (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
+    )
 
 pureIntPair ::
-     (# Int#, Int# #)
-  -> Parser s e (# Int#, Int# #)
-{-# inline pureIntPair #-}
-pureIntPair a = Parser
-  (\(# _, b, c #) s -> (# s, (# | (# a, b, c #) #) #))
+  (# Int#, Int# #) ->
+  Parser s e (# Int#, Int# #)
+{-# INLINE pureIntPair #-}
+pureIntPair a =
+  Parser
+    (\(# _, b, c #) s -> (# s, (# | (# a, b, c #) #) #))
 
 failIntPair :: e -> Parser e s (# Int#, Int# #)
-{-# inline failIntPair #-}
-failIntPair e = Parser
-  (\(# _, _, _ #) s -> (# s, (# e | #) #))
+{-# INLINE failIntPair #-}
+failIntPair e =
+  Parser
+    (\(# _, _, _ #) s -> (# s, (# e | #) #))
 
--- | Augment a parser with the number of bytes that were consume while
--- it executed.
-measure :: Parser e s a -> Parser e s (Int,a)
-{-# inline measure #-}
-measure (Parser f) = Parser
-  (\x@(# _, pre, _ #) s0 -> case f x s0 of
-    (# s1, r #) -> case r of
-      (# e | #) -> (# s1, (# e | #) #)
-      (# | (# y, post, c #) #) -> (# s1, (# | (# (I# (post -# pre), y),post,c #) #) #)
-  )
+{- | Augment a parser with the number of bytes that were consume while
+it executed.
+-}
+measure :: Parser e s a -> Parser e s (Int, a)
+{-# INLINE measure #-}
+measure (Parser f) =
+  Parser
+    ( \x@(# _, pre, _ #) s0 -> case f x s0 of
+        (# s1, r #) -> case r of
+          (# e | #) -> (# s1, (# e | #) #)
+          (# | (# y, post, c #) #) -> (# s1, (# | (# (I# (post -# pre), y), post, c #) #) #)
+    )
 
--- | Run a parser and discard the result, returning instead the number
--- of bytes that the parser consumed.
+{- | Run a parser and discard the result, returning instead the number
+of bytes that the parser consumed.
+-}
 measure_ :: Parser e s a -> Parser e s Int
-{-# inline measure_ #-}
+{-# INLINE measure_ #-}
 measure_ p = boxInt (measure_# p)
 
 -- | Variant of 'measure_' with an unboxed result.
 measure_# :: Parser e s a -> Parser e s Int#
-{-# inline measure_# #-}
-measure_# (Parser f) = Parser
-  (\x@(# _, pre, _ #) s0 -> case f x s0 of
-    (# s1, r #) -> case r of
-      (# e | #) -> (# s1, (# e | #) #)
-      (# | (# _, post, c #) #) -> (# s1, (# | (# post -# pre,post,c #) #) #)
-  )
-
+{-# INLINE measure_# #-}
+measure_# (Parser f) =
+  Parser
+    ( \x@(# _, pre, _ #) s0 -> case f x s0 of
+        (# s1, r #) -> case r of
+          (# e | #) -> (# s1, (# e | #) #)
+          (# | (# _, post, c #) #) -> (# s1, (# | (# post -# pre, post, c #) #) #)
+    )
 
+{- | Run a parser in a delimited context, failing if the requested number
+of bytes are not available or if the delimited parser does not
+consume all input. This combinator can be understood as a composition
+of 'take', 'effect', 'parseBytesEffectfully', and 'endOfInput'. It is
+provided as a single combinator because for convenience and because it is
+easy to make mistakes when manually assembling the aforementioned parsers.
+The pattern of prefixing an encoding with its length is common.
+This is discussed more in
+<https://github.com/bos/attoparsec/issues/129 attoparsec issue #129>.
 
--- | Run a parser in a delimited context, failing if the requested number
--- of bytes are not available or if the delimited parser does not
--- consume all input. This combinator can be understood as a composition
--- of 'take', 'effect', 'parseBytesEffectfully', and 'endOfInput'. It is
--- provided as a single combinator because for convenience and because it is
--- easy to make mistakes when manually assembling the aforementioned parsers.
--- The pattern of prefixing an encoding with its length is common.
--- This is discussed more in
--- <https://github.com/bos/attoparsec/issues/129 attoparsec issue #129>.
---
--- > delimit e1 e2 n remaining === take e1 n
+> delimit e1 e2 n remaining === take e1 n
+-}
 delimit ::
-     e -- ^ Error message when not enough bytes are present
-  -> e -- ^ Error message when delimited parser does not consume all input
-  -> 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
-      (# s1, r #) -> case r of
-        (# e | #) -> (# s1, (# e | #) #)
-        (# | (# a, newOff, leftovers #) #) -> case leftovers of
-          0# -> (# s1, (# | (# a, newOff, len -# n #) #) #)
-          _ -> (# s1, (# eleftovers | #) #)
-    _ -> (# s0, (# esz | #) #)
-  )
+  -- | Error message when not enough bytes are present
+  e ->
+  -- | Error message when delimited parser does not consume all input
+  e ->
+  -- | Exact number of bytes delimited parser is expected to consume
+  Int ->
+  -- | Parser to execute in delimited context
+  Parser e s a ->
+  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
+          (# s1, r #) -> case r of
+            (# e | #) -> (# s1, (# e | #) #)
+            (# | (# a, newOff, leftovers #) #) -> case leftovers of
+              0# -> (# s1, (# | (# a, newOff, len -# n #) #) #)
+              _ -> (# s1, (# eleftovers | #) #)
+        _ -> (# s0, (# esz | #) #)
+    )
 
--- | Replicate a parser @n@ times, writing the results into
--- an array of length @n@. For @Array@ and @SmallArray@, this
--- is lazy in the elements, so be sure the they result of the
--- parser is evaluated appropriately to avoid unwanted thunks.
-replicate :: forall arr e s a. (Contiguous arr, Element arr a)
-  => Int -- ^ Number of times to run the parser
-  -> Parser e s a -- ^ Parser
-  -> Parser e s (arr a)
-{-# inline replicate #-}
+{- | Replicate a parser @n@ times, writing the results into
+an array of length @n@. For @Array@ and @SmallArray@, this
+is lazy in the elements, so be sure the they result of the
+parser is evaluated appropriately to avoid unwanted thunks.
+-}
+replicate ::
+  forall arr e s a.
+  (Contiguous arr, Element arr a) =>
+  -- | Number of times to run the parser
+  Int ->
+  -- | Parser
+  Parser e s a ->
+  Parser e s (arr a)
+{-# INLINE replicate #-}
 replicate !len p = do
   marr <- effect (C.new len)
   let go :: Int -> Parser e s (arr a)
-      go !ix = if ix < len
-        then do
-          a <- p
-          effect (C.write marr ix a)
-          go (ix + 1)
-        else effect (C.unsafeFreeze marr)
+      go !ix =
+        if ix < len
+          then do
+            a <- p
+            effect (C.write marr ix a)
+            go (ix + 1)
+          else effect (C.unsafeFreeze marr)
   go 0
 
 unI :: Int -> Int#
-{-# inline unI #-}
+{-# INLINE unI #-}
 unI (I# w) = w
diff --git a/src/Data/Bytes/Parser/Ascii.hs b/src/Data/Bytes/Parser/Ascii.hs
--- a/src/Data/Bytes/Parser/Ascii.hs
+++ b/src/Data/Bytes/Parser/Ascii.hs
@@ -1,41 +1,40 @@
-{-# language BangPatterns #-}
-{-# language BinaryLiterals #-}
-{-# language DataKinds #-}
-{-# language DeriveFunctor #-}
-{-# language DerivingStrategies #-}
-{-# language GADTSyntax #-}
-{-# language KindSignatures #-}
-{-# language LambdaCase #-}
-{-# language MagicHash #-}
-{-# language MultiWayIf #-}
-{-# language PolyKinds #-}
-{-# language RankNTypes #-}
-{-# language ScopedTypeVariables #-}
-{-# language StandaloneDeriving #-}
-{-# language TypeApplications #-}
-{-# language UnboxedSums #-}
-{-# language UnboxedTuples #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE BinaryLiterals #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE GADTSyntax #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE UnboxedTuples #-}
 
--- | Parse input as ASCII-encoded text. Some parsers in this module,
--- like 'any' and 'peek', fail if they encounter a byte above @0x7F@.
--- Others, like numeric parsers and skipping parsers, leave the cursor
--- at the position of the offending byte without failing.
+{- | Parse input as ASCII-encoded text. Some parsers in this module,
+like 'any' and 'peek', fail if they encounter a byte above @0x7F@.
+Others, like numeric parsers and skipping parsers, leave the cursor
+at the position of the offending byte without failing.
+-}
 module Data.Bytes.Parser.Ascii
   ( -- * Matching
     Latin.char
   , Latin.char2
   , Latin.char3
   , Latin.char4
+
     -- * Case-Insensitive Matching
   , charInsensitive
+
     -- * Get Character
   , any
   , any#
   , peek
   , opt
+
     -- * Match Many
   , shortTrailedBy
   , takeShortWhile
+
     -- * Skip
   , Latin.skipDigits
   , Latin.skipDigits1
@@ -45,6 +44,7 @@
   , skipAlpha1
   , skipTrailedBy
   , skipWhile
+
     -- * Numbers
   , Latin.decWord
   , Latin.decWord8
@@ -52,47 +52,49 @@
   , Latin.decWord32
   ) where
 
-import Prelude hiding (length,any,fail,takeWhile)
+import Prelude hiding (any, fail, length, takeWhile)
 
+import Control.Monad.ST (runST)
 import Data.Bits (clearBit)
-import Data.Bytes.Types (Bytes(..))
-import Data.Bytes.Parser.Internal (Parser(..),uneffectful,Result#,uneffectful#)
-import Data.Bytes.Parser.Internal (Result(..),indexLatinCharArray,upcastUnitSuccess)
+import Data.Bytes.Parser.Internal (Parser (..), Result (..), Result#, indexLatinCharArray, uneffectful, uneffectful#, upcastUnitSuccess)
+import Data.Bytes.Types (Bytes (..))
 import Data.Char (ord)
-import Data.Word (Word8)
 import Data.Text.Short (ShortText)
-import Control.Monad.ST.Run (runByteArrayST)
-import GHC.Exts (Int(I#),Char(C#),Int#,Char#,(-#),(+#),(<#),ord#,indexCharArray#,chr#)
-import GHC.Exts (gtChar#)
+import Data.Word (Word8)
+import GHC.Exts (Char (C#), Char#, Int (I#), Int#, chr#, gtChar#, indexCharArray#, ord#, (+#), (-#), (<#))
 
 import qualified Data.ByteString.Short.Internal as BSS
-import qualified Data.Text.Short.Unsafe as TS
 import qualified Data.Bytes as Bytes
 import qualified Data.Bytes.Parser.Latin as Latin
 import qualified Data.Bytes.Parser.Unsafe as Unsafe
 import qualified Data.Primitive as PM
+import qualified Data.Text.Short.Unsafe as TS
 
--- | Consume the next character, failing if it does not match the expected
--- value or if there is no more input. This check for equality is case
--- insensitive.
---
--- Precondition: The argument must be a letter (@[a-zA-Z]@). Behavior is
--- undefined if it is not.
+{- | Consume the next character, failing if it does not match the expected
+value or if there is no more input. This check for equality is case
+insensitive.
+
+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 Success () (offset chunk + 1) (length chunk - 1)
+{-# INLINE charInsensitive #-}
+charInsensitive e !c = uneffectful $ \chunk ->
+  if length chunk > 0
+    then
+      if clearBit (PM.indexByteArray (array chunk) (offset chunk) :: Word8) 5 == w
+        then Success () (offset chunk + 1) (length chunk - 1)
+        else Failure e
     else Failure e
-  else Failure e
-  where
+ where
   w = clearBit (fromIntegral @Int @Word8 (ord c)) 5
 
--- | Consume input until the trailer is found. Then, consume
--- the trailer as well. This fails if the trailer is not
--- found or if any non-ASCII characters are encountered.
+{- | Consume input until the trailer is found. Then, consume
+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 #-}
+{-# INLINE skipTrailedBy #-}
 skipTrailedBy e !c = do
   let go = do
         !d <- any e
@@ -101,30 +103,32 @@
           else go
   go
 
--- | Consume characters matching the predicate. The stops when it
--- encounters a non-matching character or when it encounters a byte
--- above @0x7F@. This never fails.
+{- | Consume characters matching the predicate. The stops when it
+encounters a non-matching character or when it encounters a byte
+above @0x7F@. This never fails.
+-}
 takeShortWhile :: (Char -> Bool) -> Parser e s ShortText
-{-# inline takeShortWhile #-}
+{-# INLINE takeShortWhile #-}
 takeShortWhile p = do
   !start <- Unsafe.cursor
   skipWhile p
   end <- Unsafe.cursor
   src <- Unsafe.expose
   let len = end - start
-      !r = runByteArrayST $ do
+      !r = runST $ do
         marr <- PM.newByteArray len
         PM.copyByteArray marr 0 src start len
         PM.unsafeFreezeByteArray marr
-  pure
-    $ TS.fromShortByteStringUnsafe
-    $ byteArrayToShortByteString
-    $ r
+  pure $
+    TS.fromShortByteStringUnsafe $
+      byteArrayToShortByteString $
+        r
 
--- | Consume input through the next occurrence of the target
--- character and return the consumed input, excluding the
--- target character, as a 'ShortText'. This fails if it
--- encounters any bytes above @0x7F@.
+{- | Consume input through the next occurrence of the target
+character and return the consumed input, excluding the
+target character, as a 'ShortText'. This fails if it
+encounters any bytes above @0x7F@.
+-}
 shortTrailedBy :: e -> Char -> Parser e s ShortText
 shortTrailedBy e !c = do
   !start <- Unsafe.cursor
@@ -132,133 +136,147 @@
   end <- Unsafe.cursor
   src <- Unsafe.expose
   let len = end - start - 1
-      !r = runByteArrayST $ do
+      !r = runST $ do
         marr <- PM.newByteArray len
         PM.copyByteArray marr 0 src start len
         PM.unsafeFreezeByteArray marr
-  pure
-    $ TS.fromShortByteStringUnsafe
-    $ byteArrayToShortByteString
-    $ r
-
+  pure $
+    TS.fromShortByteStringUnsafe $
+      byteArrayToShortByteString $
+        r
 
 -- | 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 Success c (offset chunk + 1) (length chunk - 1)
-          else Failure e
-  else Failure e
+{-# INLINE any #-}
+any e = uneffectful $ \chunk ->
+  if length chunk > 0
+    then
+      let c = indexLatinCharArray (array chunk) (offset chunk)
+       in if c < '\128'
+            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#
-{-# inline any# #-}
-any# e = Parser
-  (\(# arr, off, len #) s0 -> case len of
-    0# -> (# s0, (# e | #) #)
-    _ ->
-      let !w = indexCharArray# arr off
-       in case ord# w <# 128# of
-            1# -> (# s0, (# | (# w, off +# 1#, len -# 1# #) #) #)
-            _ -> (# s0, (# e | #) #)
-  )
+{-# INLINE any# #-}
+any# e =
+  Parser
+    ( \(# arr, off, len #) s0 -> case len of
+        0# -> (# s0, (# e | #) #)
+        _ ->
+          let !w = indexCharArray# arr off
+           in case ord# w <# 128# of
+                1# -> (# s0, (# | (# w, off +# 1#, len -# 1# #) #) #)
+                _ -> (# s0, (# e | #) #)
+    )
 
 unI :: Int -> Int#
-{-# inline unI #-}
+{-# 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.
+{- | 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 Success
-                 (C# (chr# (unI (fromIntegral w))))
-                 (offset chunk)
-                 (length chunk)
-          else Failure e
-  else Failure e
+{-# 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
+              Success
+                (C# (chr# (unI (fromIntegral w))))
+                (offset chunk)
+                (length chunk)
+            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
--- end of the input has been reached.
+{- | Consume the next byte, interpreting it as an ASCII-encoded character.
+Fails if the byte is above @0x7F@. Returns @Nothing@ if the
+end of the input has been reached.
+-}
 opt :: e -> Parser e s (Maybe Char)
-{-# inline opt #-}
-opt e = uneffectful $ \chunk -> if length chunk > 0
-  then
-    let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8
-     in if w < 128
-          then Success
-                 (Just (C# (chr# (unI (fromIntegral w)))))
-                 (offset chunk + 1)
-                 (length chunk - 1)
-          else Failure e
-  else Success Nothing (offset chunk) (length chunk)
+{-# INLINE opt #-}
+opt e = uneffectful $ \chunk ->
+  if length chunk > 0
+    then
+      let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8
+       in if w < 128
+            then
+              Success
+                (Just (C# (chr# (unI (fromIntegral w)))))
+                (offset chunk + 1)
+                (length chunk - 1)
+            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
--- above @0x7F@. This never fails.
+{- | Consume characters matching the predicate. The stops when it
+encounters a non-matching character or when it encounters a byte
+above @0x7F@. This never fails.
+-}
 skipWhile :: (Char -> Bool) -> Parser e s ()
-{-# inline skipWhile #-}
-skipWhile p = Parser
-  ( \(# arr, off0, len0 #) s0 ->
-    let go off len = case len of
-          0# -> (# (), off, 0# #)
-          _ -> let c = indexCharArray# arr off in
-            case p (C# c) of
-              True -> case gtChar# c '\x7F'# of
-                1# -> (# (), off, len #)
-                _ -> go (off +# 1# ) (len -# 1# )
-              False -> (# (), off, len #)
-     in (# s0, (# | go off0 len0 #) #)
-  )
+{-# INLINE skipWhile #-}
+skipWhile p =
+  Parser
+    ( \(# arr, off0, len0 #) s0 ->
+        let go off len = case len of
+              0# -> (# (), off, 0# #)
+              _ ->
+                let c = indexCharArray# arr off
+                 in case p (C# c) of
+                      True -> case gtChar# c '\x7F'# of
+                        1# -> (# (), off, len #)
+                        _ -> go (off +# 1#) (len -# 1#)
+                      False -> (# (), off, len #)
+         in (# s0, (# | go off0 len0 #) #)
+    )
 
--- | Skip uppercase and lowercase letters until a non-alpha
--- character is encountered.
+{- | Skip uppercase and lowercase letters until a non-alpha
+character is encountered.
+-}
 skipAlpha :: Parser e s ()
-{-# inline skipAlpha #-}
+{-# INLINE skipAlpha #-}
 skipAlpha = uneffectful# $ \c ->
   upcastUnitSuccess (skipAlphaAsciiLoop c)
 
--- | Skip uppercase and lowercase letters until a non-alpha
--- character is encountered.
+{- | Skip uppercase and lowercase letters until a non-alpha
+character is encountered.
+-}
 skipAlpha1 :: e -> Parser e s ()
-{-# inline skipAlpha1 #-}
+{-# 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)
-     in if (w >= 'a' && w <= 'z') || (w >= 'A' && w <= 'Z')
-          then skipAlphaAsciiLoop (Bytes.unsafeDrop 1 c)
-          else (# unI (offset c), unI (length c) #)
-  else (# unI (offset c), unI (length c) #)
+  Bytes -> -- Chunk
+  (# Int#, Int# #)
+{-# INLINE skipAlphaAsciiLoop #-}
+skipAlphaAsciiLoop !c =
+  if length c > 0
+    then
+      let w = indexLatinCharArray (array c) (offset c)
+       in if (w >= 'a' && w <= 'z') || (w >= 'A' && w <= 'Z')
+            then skipAlphaAsciiLoop (Bytes.unsafeDrop 1 c)
+            else (# unI (offset c), unI (length c) #)
+    else (# unI (offset c), unI (length c) #)
 
 skipAlphaAsciiLoop1Start ::
-     e
-  -> Bytes -- chunk
-  -> Result# e ()
-{-# inline skipAlphaAsciiLoop1Start #-}
-skipAlphaAsciiLoop1Start e !c = if length c > 0
-  then 
-    let w = indexLatinCharArray (array c) (offset c)
-     in if (w >= 'a' && w <= 'z') || (w >= 'A' && w <= 'Z')
-          then upcastUnitSuccess (skipAlphaAsciiLoop (Bytes.unsafeDrop 1 c))
-          else (# e | #)
-  else (# e | #)
+  e ->
+  Bytes -> -- chunk
+  Result# e ()
+{-# INLINE skipAlphaAsciiLoop1Start #-}
+skipAlphaAsciiLoop1Start e !c =
+  if length c > 0
+    then
+      let w = indexLatinCharArray (array c) (offset c)
+       in if (w >= 'a' && w <= 'z') || (w >= 'A' && w <= 'Z')
+            then upcastUnitSuccess (skipAlphaAsciiLoop (Bytes.unsafeDrop 1 c))
+            else (# e | #)
+    else (# e | #)
 
 byteArrayToShortByteString :: PM.ByteArray -> BSS.ShortByteString
-{-# inline byteArrayToShortByteString #-}
+{-# INLINE byteArrayToShortByteString #-}
 byteArrayToShortByteString (PM.ByteArray x) = BSS.SBS x
diff --git a/src/Data/Bytes/Parser/Base128.hs b/src/Data/Bytes/Parser/Base128.hs
--- a/src/Data/Bytes/Parser/Base128.hs
+++ b/src/Data/Bytes/Parser/Base128.hs
@@ -1,5 +1,5 @@
-{-# language BangPatterns #-}
-{-# language TypeApplications #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE TypeApplications #-}
 
 module Data.Bytes.Parser.Base128
   ( -- * Unsigned
@@ -9,9 +9,9 @@
   ) where
 
 import Control.Monad (when)
-import Data.Bits (testBit,unsafeShiftL,(.|.),bit,clearBit)
+import Data.Bits (bit, clearBit, testBit, unsafeShiftL, (.|.))
 import Data.Bytes.Parser (Parser)
-import Data.Word (Word8,Word16,Word32,Word64)
+import Data.Word (Word16, Word32, Word64, Word8)
 
 import qualified Data.Bytes.Parser as P
 
diff --git a/src/Data/Bytes/Parser/BigEndian.hs b/src/Data/Bytes/Parser/BigEndian.hs
--- a/src/Data/Bytes/Parser/BigEndian.hs
+++ b/src/Data/Bytes/Parser/BigEndian.hs
@@ -1,20 +1,14 @@
-{-# language BangPatterns #-}
-{-# language BinaryLiterals #-}
-{-# language DataKinds #-}
-{-# language DeriveFunctor #-}
-{-# language DerivingStrategies #-}
-{-# language GADTSyntax #-}
-{-# language KindSignatures #-}
-{-# language LambdaCase #-}
-{-# language MagicHash #-}
-{-# language MultiWayIf #-}
-{-# language PolyKinds #-}
-{-# language RankNTypes #-}
-{-# language ScopedTypeVariables #-}
-{-# language StandaloneDeriving #-}
-{-# language TypeApplications #-}
-{-# language UnboxedSums #-}
-{-# language UnboxedTuples #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE BinaryLiterals #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE GADTSyntax #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE UnboxedSums #-}
 
 -- | Big-endian fixed-width numbers.
 module Data.Bytes.Parser.BigEndian
@@ -25,12 +19,15 @@
   , word64
   , word128
   , word256
+
     -- * Signed
   , int8
   , int16
   , int32
   , int64
+
     -- * Many
+
     -- ** Unsigned
   , word16Array
   , word32Array
@@ -39,20 +36,20 @@
   , word256Array
   ) where
 
-import Prelude hiding (length,any,fail,takeWhile)
+import Prelude hiding (any, fail, length, takeWhile)
 
+#if MIN_VERSION_base(4,18,0)
+#else
 import Control.Applicative (liftA2)
-import Data.Bits ((.|.),unsafeShiftL)
-import Data.Bytes.Types (Bytes(..))
-import Data.Bytes.Parser.Internal (Parser,uneffectful)
-import Data.Bytes.Parser.Internal (Result(..))
-import Data.Bytes.Parser.Internal (swapArray16,swapArray32,swapArray64,swapArray256)
-import Data.Bytes.Parser.Internal (swapArray128)
-import Data.Word (Word8,Word16,Word32,Word64)
-import Data.Int (Int8,Int16,Int32,Int64)
-import Data.Primitive (ByteArray(..),PrimArray(..))
-import Data.WideWord (Word128(Word128),Word256(Word256))
-import GHC.ByteOrder (ByteOrder(LittleEndian,BigEndian),targetByteOrder)
+#endif
+import Data.Bits (unsafeShiftL, (.|.))
+import Data.Bytes.Parser.Internal (Parser, Result (..), swapArray128, swapArray16, swapArray256, swapArray32, swapArray64, uneffectful)
+import Data.Bytes.Types (Bytes (..))
+import Data.Int (Int16, Int32, Int64, Int8)
+import Data.Primitive (ByteArray (..), PrimArray (..))
+import Data.WideWord (Word128 (Word128), Word256 (Word256))
+import Data.Word (Word16, Word32, Word64, Word8)
+import GHC.ByteOrder (ByteOrder (BigEndian, LittleEndian), targetByteOrder)
 
 import qualified Data.Bytes as Bytes
 import qualified Data.Bytes.Parser as P
@@ -62,14 +59,18 @@
 word8 :: e -> Parser e s Word8
 word8 = P.any
 
--- | Parse an array of big-endian unsigned 16-bit words. If the host is
--- big-endian, the implementation is optimized to simply @memcpy@ bytes
--- into the result array. The result array always has elements in
--- native-endian byte order.
+{- | Parse an array of big-endian unsigned 16-bit words. If the host is
+big-endian, the implementation is optimized to simply @memcpy@ bytes
+into the result array. The result array always has elements in
+native-endian byte order.
+-}
 word16Array ::
-     e -- ^ Error message if not enough bytes are present
-  -> Int -- ^ Number of big-endian 16-bit words to expect
-  -> Parser e s (PrimArray Word16) -- ^ Native-endian elements
+  -- | Error message if not enough bytes are present
+  e ->
+  -- | Number of big-endian 16-bit words to expect
+  Int ->
+  -- | Native-endian elements
+  Parser e s (PrimArray Word16)
 word16Array e !n = case targetByteOrder of
   BigEndian -> fmap (asWord16s . Bytes.toByteArrayClone) (P.take e (n * 2))
   LittleEndian -> do
@@ -79,9 +80,12 @@
 
 -- | Parse an array of big-endian unsigned 32-bit words.
 word32Array ::
-     e -- ^ Error message if not enough bytes are present
-  -> Int -- ^ Number of big-endian 32-bit words to expect
-  -> Parser e s (PrimArray Word32) -- ^ Native-endian elements
+  -- | Error message if not enough bytes are present
+  e ->
+  -- | Number of big-endian 32-bit words to expect
+  Int ->
+  -- | Native-endian elements
+  Parser e s (PrimArray Word32)
 word32Array e !n = case targetByteOrder of
   BigEndian -> fmap (asWord32s . Bytes.toByteArrayClone) (P.take e (n * 4))
   LittleEndian -> do
@@ -91,9 +95,12 @@
 
 -- | Parse an array of big-endian unsigned 64-bit words.
 word64Array ::
-     e -- ^ Error message if not enough bytes are present
-  -> Int -- ^ Number of big-endian 64-bit words to consume
-  -> Parser e s (PrimArray Word64) -- ^ Native-endian elements
+  -- | Error message if not enough bytes are present
+  e ->
+  -- | Number of big-endian 64-bit words to consume
+  Int ->
+  -- | Native-endian elements
+  Parser e s (PrimArray Word64)
 word64Array e !n = case targetByteOrder of
   BigEndian -> fmap (asWord64s . Bytes.toByteArrayClone) (P.take e (n * 8))
   LittleEndian -> do
@@ -103,9 +110,12 @@
 
 -- | Parse an array of big-endian unsigned 256-bit words.
 word256Array ::
-     e -- ^ Error message if not enough bytes are present
-  -> Int -- ^ Number of big-endian 256-bit words to consume
-  -> Parser e s (PrimArray Word256) -- ^ Native-endian elements
+  -- | Error message if not enough bytes are present
+  e ->
+  -- | Number of big-endian 256-bit words to consume
+  Int ->
+  -- | Native-endian elements
+  Parser e s (PrimArray Word256)
 word256Array e !n = case targetByteOrder of
   BigEndian -> fmap (asWord256s . Bytes.toByteArrayClone) (P.take e (n * 32))
   LittleEndian -> do
@@ -115,9 +125,12 @@
 
 -- | Parse an array of big-endian unsigned 128-bit words.
 word128Array ::
-     e -- ^ Error message if not enough bytes are present
-  -> Int -- ^ Number of big-endian 128-bit words to consume
-  -> Parser e s (PrimArray Word128) -- ^ Native-endian elements
+  -- | Error message if not enough bytes are present
+  e ->
+  -- | Number of big-endian 128-bit words to consume
+  Int ->
+  -- | Native-endian elements
+  Parser e s (PrimArray Word128)
 word128Array e !n = case targetByteOrder of
   BigEndian -> fmap (asWord128s . Bytes.toByteArrayClone) (P.take e (n * 16))
   LittleEndian -> do
@@ -142,58 +155,64 @@
 
 -- | Unsigned 16-bit word.
 word16 :: e -> Parser e s Word16
-word16 e = uneffectful $ \chunk -> if length chunk >= 2
-  then
-    let wa = PM.indexByteArray (array chunk) (offset chunk) :: Word8
-        wb = PM.indexByteArray (array chunk) (offset chunk + 1) :: Word8
-     in Success
-          (fromIntegral @Word @Word16 (unsafeShiftL (fromIntegral wa) 8 .|. fromIntegral wb))
-          (offset chunk + 2) (length chunk - 2)
-  else Failure e
+word16 e = uneffectful $ \chunk ->
+  if length chunk >= 2
+    then
+      let wa = PM.indexByteArray (array chunk) (offset chunk) :: Word8
+          wb = PM.indexByteArray (array chunk) (offset chunk + 1) :: Word8
+       in Success
+            (fromIntegral @Word @Word16 (unsafeShiftL (fromIntegral wa) 8 .|. fromIntegral wb))
+            (offset chunk + 2)
+            (length chunk - 2)
+    else Failure e
 
 -- | Unsigned 32-bit word.
 word32 :: e -> Parser e s Word32
-word32 e = uneffectful $ \chunk -> if length chunk >= 4
-  then
-    let wa = PM.indexByteArray (array chunk) (offset chunk) :: Word8
-        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 Success
-          (fromIntegral @Word @Word32
-            ( unsafeShiftL (fromIntegral wa) 24 .|.
-              unsafeShiftL (fromIntegral wb) 16 .|.
-              unsafeShiftL (fromIntegral wc) 8 .|.
-              fromIntegral wd
+word32 e = uneffectful $ \chunk ->
+  if length chunk >= 4
+    then
+      let wa = PM.indexByteArray (array chunk) (offset chunk) :: Word8
+          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 Success
+            ( fromIntegral @Word @Word32
+                ( unsafeShiftL (fromIntegral wa) 24
+                    .|. unsafeShiftL (fromIntegral wb) 16
+                    .|. unsafeShiftL (fromIntegral wc) 8
+                    .|. fromIntegral wd
+                )
             )
-          )
-          (offset chunk + 4) (length chunk - 4)
-  else Failure e
+            (offset chunk + 4)
+            (length chunk - 4)
+    else Failure e
 
 -- | Unsigned 64-bit word.
 word64 :: e -> Parser e s Word64
-word64 e = uneffectful $ \chunk -> if length chunk >= 8
-  then
-    let wa = PM.indexByteArray (array chunk) (offset chunk) :: Word8
-        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
-        we = PM.indexByteArray (array chunk) (offset chunk + 4) :: Word8
-        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 Success
-          ( unsafeShiftL (fromIntegral wa) 56 .|.
-            unsafeShiftL (fromIntegral wb) 48 .|.
-            unsafeShiftL (fromIntegral wc) 40 .|.
-            unsafeShiftL (fromIntegral wd) 32 .|.
-            unsafeShiftL (fromIntegral we) 24 .|.
-            unsafeShiftL (fromIntegral wf) 16 .|.
-            unsafeShiftL (fromIntegral wg) 8 .|.
-            fromIntegral wh
-          )
-          (offset chunk + 8) (length chunk - 8)
-  else Failure e
+word64 e = uneffectful $ \chunk ->
+  if length chunk >= 8
+    then
+      let wa = PM.indexByteArray (array chunk) (offset chunk) :: Word8
+          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
+          we = PM.indexByteArray (array chunk) (offset chunk + 4) :: Word8
+          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 Success
+            ( unsafeShiftL (fromIntegral wa) 56
+                .|. unsafeShiftL (fromIntegral wb) 48
+                .|. unsafeShiftL (fromIntegral wc) 40
+                .|. unsafeShiftL (fromIntegral wd) 32
+                .|. unsafeShiftL (fromIntegral we) 24
+                .|. unsafeShiftL (fromIntegral wf) 16
+                .|. unsafeShiftL (fromIntegral wg) 8
+                .|. fromIntegral wh
+            )
+            (offset chunk + 8)
+            (length chunk - 8)
+    else Failure e
 
 -- | Unsigned 128-bit word.
 word128 :: e -> Parser e s Word128
diff --git a/src/Data/Bytes/Parser/Internal.hs b/src/Data/Bytes/Parser/Internal.hs
--- a/src/Data/Bytes/Parser/Internal.hs
+++ b/src/Data/Bytes/Parser/Internal.hs
@@ -1,26 +1,19 @@
-{-# language BangPatterns #-}
-{-# language BinaryLiterals #-}
-{-# language DataKinds #-}
-{-# language DeriveFunctor #-}
-{-# language DerivingStrategies #-}
-{-# language GADTSyntax #-}
-{-# language KindSignatures #-}
-{-# language LambdaCase #-}
-{-# language MagicHash #-}
-{-# language MultiWayIf #-}
-{-# language NamedFieldPuns #-}
-{-# language PolyKinds #-}
-{-# language RankNTypes #-}
-{-# language ScopedTypeVariables #-}
-{-# language StandaloneDeriving #-}
-{-# language TypeApplications #-}
-{-# language UnboxedSums #-}
-{-# language UnboxedTuples #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE BinaryLiterals #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE GADTSyntax #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE UnboxedTuples #-}
 
 module Data.Bytes.Parser.Internal
-  ( Parser(..)
-  , Result(..)
-  , InternalStep(..)
+  ( Parser (..)
+  , Result (..)
+  , InternalStep (..)
   , Bytes#
   , ST#
   , Result#
@@ -34,7 +27,7 @@
   , fail
   , indexLatinCharArray
   , upcastUnitSuccess
-    -- Swapping
+  -- Swapping
   , swapArray16
   , swapArray32
   , swapArray64
@@ -42,15 +35,15 @@
   , swapArray256
   ) where
 
-import Prelude hiding (length,any,fail,takeWhile)
+import Prelude hiding (any, fail, length, takeWhile)
 
 import Control.Applicative (Alternative)
-import Control.Monad.ST.Run (runByteArrayST)
-import Data.Primitive (ByteArray(ByteArray))
-import Data.Bytes.Types (Bytes(..))
+import Control.Monad.ST (runST)
+import Data.Bytes.Types (Bytes (..))
 import Data.Kind (Type)
+import Data.Primitive (ByteArray (ByteArray))
 import Data.Word (Word8)
-import GHC.Exts (TYPE,RuntimeRep,Int(I#),Int#,State#,ByteArray#,Char(C#))
+import GHC.Exts (ByteArray#, Char (C#), Int (I#), Int#, RuntimeRep, State#, TYPE)
 
 import qualified Control.Applicative
 import qualified Control.Monad
@@ -59,71 +52,81 @@
 
 -- | A non-resumable parser.
 newtype Parser :: forall (r :: RuntimeRep). Type -> Type -> TYPE r -> Type where
-  Parser :: forall (r :: RuntimeRep) (e :: Type) (s :: Type) (a :: TYPE r).
-    { runParser :: (# ByteArray#, Int#, Int# #) -> ST# s (Result# e a) } -> Parser e s a
+  Parser ::
+    forall (r :: RuntimeRep) (e :: Type) (s :: Type) (a :: TYPE r).
+    {runParser :: (# ByteArray#, Int#, Int# #) -> ST# s (Result# e a)} ->
+    Parser e s a
 
 -- The result of running a parser. Used internally.
 data Result e a
   = Failure e
-    -- An error message indicating what went wrong.
-  | Success !a !Int !Int
-    -- The parsed value, the offset after the last consumed byte, and the
-    -- number of bytes remaining in parsed slice.
+  | -- An error message indicating what went wrong.
+    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 -> Result e a) -> Parser e s a
-{-# inline uneffectful #-}
-uneffectful f = Parser
-  ( \b s0 -> (# s0, unboxResult (f (boxBytes b)) #) )
+{-# INLINE uneffectful #-}
+uneffectful f =
+  Parser
+    (\b s0 -> (# s0, unboxResult (f (boxBytes b)) #))
 
 -- This is like uneffectful but for parsers that always succeed.
 -- These combinators typically have names that begin with @try@.
 unfailing :: (Bytes -> InternalStep a) -> Parser e s a
-{-# inline unfailing #-}
-unfailing f = Parser
-  ( \b s0 -> (# s0, case f (boxBytes b) of { InternalStep a (I# off) (I# len) -> (# | (# a, off, len #) #) } #) )
+{-# INLINE unfailing #-}
+unfailing f =
+  Parser
+    (\b s0 -> (# s0, case f (boxBytes b) of InternalStep a (I# off) (I# len) -> (# | (# a, off, len #) #) #))
 
 boxBytes :: Bytes# -> Bytes
-{-# inline boxBytes #-}
+{-# INLINE boxBytes #-}
 boxBytes (# a, b, c #) = Bytes (ByteArray a) (I# b) (I# c)
 
 unboxBytes :: Bytes -> Bytes#
-{-# inline unboxBytes #-}
-unboxBytes (Bytes (ByteArray a) (I# b) (I# c)) = (# a,b,c #)
+{-# INLINE unboxBytes #-}
+unboxBytes (Bytes (ByteArray a) (I# b) (I# c)) = (# a, b, c #)
 
 type Bytes# = (# ByteArray#, Int#, Int# #)
 type ST# s (a :: TYPE r) = State# s -> (# State# s, a #)
 type Result# e (a :: TYPE r) =
-  (# e
-  | (# a, Int#, Int# #) #) -- ints are offset and length
+  (#
+    e |
+    (# a, Int#, Int# #) -- ints are offset and length
+  #)
 
 unboxResult :: Result e a -> Result# e a
-{-# inline unboxResult #-}
+{-# 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.
-instance Monoid e => Alternative (Parser e s) where
-  {-# inline empty #-}
-  {-# inline (<|>) #-}
+{- | Combines the error messages using '<>' when both
+parsers fail.
+-}
+instance (Monoid e) => Alternative (Parser e s) where
+  {-# INLINE empty #-}
+  {-# INLINE (<|>) #-}
   empty = fail mempty
-  Parser f <|> Parser g = Parser
-    (\x s0 -> case f x s0 of
-      (# s1, r0 #) -> case r0 of
-        (# eRight | #) -> case g x s1 of
-          (# s2, r1 #) -> case r1 of
-            (# eLeft | #) -> (# s2, (# eRight <> eLeft | #) #)
-            (# | r #) -> (# s2, (# | r #) #)
-        (# | r #) -> (# s1, (# | r #) #)
-    )
+  Parser f <|> Parser g =
+    Parser
+      ( \x s0 -> case f x s0 of
+          (# s1, r0 #) -> case r0 of
+            (# eRight | #) -> case g x s1 of
+              (# s2, r1 #) -> case r1 of
+                (# eLeft | #) -> (# s2, (# eRight <> eLeft | #) #)
+                (# | r #) -> (# s2, (# | r #) #)
+            (# | r #) -> (# s1, (# | r #) #)
+      )
 
 -- | Fail with the provided error message.
 fail ::
-     e -- ^ Error message
-  -> Parser e s a
-{-# inline fail #-}
+  -- | Error message
+  e ->
+  Parser e s a
+{-# INLINE fail #-}
 fail e = uneffectful $ \_ -> Failure e
 
 instance Applicative (Parser e s) where
@@ -131,165 +134,175 @@
   (<*>) = Control.Monad.ap
 
 instance Monad (Parser e s) where
-  {-# inline (>>=) #-}
+  {-# INLINE (>>=) #-}
   (>>=) = bindParser
 
 instance Functor (Parser e s) where
-  {-# inline fmap #-}
-  fmap f (Parser g) = Parser
-    (\x s0 -> case g x s0 of
-      (# s1, r #) -> case r of
-        (# e | #) -> (# s1, (# e | #) #)
-        (# | (# a, b, c #) #) -> (# s1, (# | (# f a, b, c #) #) #)
-    )
+  {-# INLINE fmap #-}
+  fmap f (Parser g) =
+    Parser
+      ( \x s0 -> case g x s0 of
+          (# s1, r #) -> case r of
+            (# e | #) -> (# s1, (# e | #) #)
+            (# | (# a, b, c #) #) -> (# s1, (# | (# f a, b, c #) #) #)
+      )
 
 indexLatinCharArray :: ByteArray -> Int -> Char
-{-# inline indexLatinCharArray #-}
+{-# INLINE indexLatinCharArray #-}
 indexLatinCharArray (ByteArray arr) (I# off) =
   C# (Exts.indexCharArray# arr off)
 
 uneffectful# :: (Bytes -> Result# e a) -> Parser e s a
-{-# inline uneffectful# #-}
-uneffectful# f = Parser
-  ( \b s0 -> (# s0, (f (boxBytes b)) #) )
+{-# INLINE uneffectful# #-}
+uneffectful# f =
+  Parser
+    (\b s0 -> (# s0, (f (boxBytes b)) #))
 
-uneffectfulInt# :: (Bytes -> Result# e Int# ) -> Parser e s Int#
-{-# inline uneffectfulInt# #-}
-uneffectfulInt# f = Parser
-  ( \b s0 -> (# s0, (f (boxBytes b)) #) )
+uneffectfulInt# :: (Bytes -> Result# e Int#) -> Parser e s Int#
+{-# INLINE uneffectfulInt# #-}
+uneffectfulInt# f =
+  Parser
+    (\b s0 -> (# s0, (f (boxBytes b)) #))
 
 upcastUnitSuccess :: (# Int#, Int# #) -> Result# e ()
-{-# inline upcastUnitSuccess #-}
+{-# INLINE upcastUnitSuccess #-}
 upcastUnitSuccess (# b, c #) = (# | (# (), b, c #) #)
 
 swapArray16 :: Bytes -> ByteArray
-swapArray16 (Bytes{array,offset,length}) = runByteArrayST $ do
+swapArray16 (Bytes {array, offset, length}) = runST $ do
   dst <- PM.newByteArray length
-  let go !ixSrc !ixDst !len = if len > 0
-        then do
-          let v0 = PM.indexByteArray array ixSrc :: Word8
-              v1 = PM.indexByteArray array (ixSrc + 1) :: Word8
-          PM.writeByteArray dst ixDst v1
-          PM.writeByteArray dst (ixDst + 1) v0
-          go (ixSrc + 2) (ixDst + 2) (len - 2)
-        else pure ()
+  let go !ixSrc !ixDst !len =
+        if len > 0
+          then do
+            let v0 = PM.indexByteArray array ixSrc :: Word8
+                v1 = PM.indexByteArray array (ixSrc + 1) :: Word8
+            PM.writeByteArray dst ixDst v1
+            PM.writeByteArray dst (ixDst + 1) v0
+            go (ixSrc + 2) (ixDst + 2) (len - 2)
+          else pure ()
   go offset 0 length
   PM.unsafeFreezeByteArray dst
 
 swapArray32 :: Bytes -> ByteArray
-swapArray32 (Bytes{array,offset,length}) = runByteArrayST $ do
+swapArray32 (Bytes {array, offset, length}) = runST $ do
   dst <- PM.newByteArray length
-  let go !ixSrc !ixDst !len = if len > 0
-        then do
-          let v0 = PM.indexByteArray array ixSrc :: Word8
-              v1 = PM.indexByteArray array (ixSrc + 1) :: Word8
-              v2 = PM.indexByteArray array (ixSrc + 2) :: Word8
-              v3 = PM.indexByteArray array (ixSrc + 3) :: Word8
-          PM.writeByteArray dst ixDst v3
-          PM.writeByteArray dst (ixDst + 1) v2
-          PM.writeByteArray dst (ixDst + 2) v1
-          PM.writeByteArray dst (ixDst + 3) v0
-          go (ixSrc + 4) (ixDst + 4) (len - 4)
-        else pure ()
+  let go !ixSrc !ixDst !len =
+        if len > 0
+          then do
+            let v0 = PM.indexByteArray array ixSrc :: Word8
+                v1 = PM.indexByteArray array (ixSrc + 1) :: Word8
+                v2 = PM.indexByteArray array (ixSrc + 2) :: Word8
+                v3 = PM.indexByteArray array (ixSrc + 3) :: Word8
+            PM.writeByteArray dst ixDst v3
+            PM.writeByteArray dst (ixDst + 1) v2
+            PM.writeByteArray dst (ixDst + 2) v1
+            PM.writeByteArray dst (ixDst + 3) v0
+            go (ixSrc + 4) (ixDst + 4) (len - 4)
+          else pure ()
   go offset 0 length
   PM.unsafeFreezeByteArray dst
 
 swapArray64 :: Bytes -> ByteArray
-swapArray64 (Bytes{array,offset,length}) = runByteArrayST $ do
+swapArray64 (Bytes {array, offset, length}) = runST $ do
   dst <- PM.newByteArray length
-  let go !ixSrc !ixDst !len = if len > 0
-        then do
-          let v0 = PM.indexByteArray array ixSrc :: Word8
-              v1 = PM.indexByteArray array (ixSrc + 1) :: Word8
-              v2 = PM.indexByteArray array (ixSrc + 2) :: Word8
-              v3 = PM.indexByteArray array (ixSrc + 3) :: Word8
-              v4 = PM.indexByteArray array (ixSrc + 4) :: Word8
-              v5 = PM.indexByteArray array (ixSrc + 5) :: Word8
-              v6 = PM.indexByteArray array (ixSrc + 6) :: Word8
-              v7 = PM.indexByteArray array (ixSrc + 7) :: Word8
-          PM.writeByteArray dst ixDst v7
-          PM.writeByteArray dst (ixDst + 1) v6
-          PM.writeByteArray dst (ixDst + 2) v5
-          PM.writeByteArray dst (ixDst + 3) v4
-          PM.writeByteArray dst (ixDst + 4) v3
-          PM.writeByteArray dst (ixDst + 5) v2
-          PM.writeByteArray dst (ixDst + 6) v1
-          PM.writeByteArray dst (ixDst + 7) v0
-          go (ixSrc + 8) (ixDst + 8) (len - 8)
-        else pure ()
+  let go !ixSrc !ixDst !len =
+        if len > 0
+          then do
+            let v0 = PM.indexByteArray array ixSrc :: Word8
+                v1 = PM.indexByteArray array (ixSrc + 1) :: Word8
+                v2 = PM.indexByteArray array (ixSrc + 2) :: Word8
+                v3 = PM.indexByteArray array (ixSrc + 3) :: Word8
+                v4 = PM.indexByteArray array (ixSrc + 4) :: Word8
+                v5 = PM.indexByteArray array (ixSrc + 5) :: Word8
+                v6 = PM.indexByteArray array (ixSrc + 6) :: Word8
+                v7 = PM.indexByteArray array (ixSrc + 7) :: Word8
+            PM.writeByteArray dst ixDst v7
+            PM.writeByteArray dst (ixDst + 1) v6
+            PM.writeByteArray dst (ixDst + 2) v5
+            PM.writeByteArray dst (ixDst + 3) v4
+            PM.writeByteArray dst (ixDst + 4) v3
+            PM.writeByteArray dst (ixDst + 5) v2
+            PM.writeByteArray dst (ixDst + 6) v1
+            PM.writeByteArray dst (ixDst + 7) v0
+            go (ixSrc + 8) (ixDst + 8) (len - 8)
+          else pure ()
   go offset 0 length
   PM.unsafeFreezeByteArray dst
 
 swapArray128 :: Bytes -> ByteArray
-swapArray128 (Bytes{array,offset,length}) = runByteArrayST $ do
+swapArray128 (Bytes {array, offset, length}) = runST $ do
   dst <- PM.newByteArray length
-  let go !ixSrc !ixDst !len = if len > 0
-        then do
-          let v0 = PM.indexByteArray array ixSrc :: Word8
-              v1 = PM.indexByteArray array (ixSrc + 1) :: Word8
-              v2 = PM.indexByteArray array (ixSrc + 2) :: Word8
-              v3 = PM.indexByteArray array (ixSrc + 3) :: Word8
-              v4 = PM.indexByteArray array (ixSrc + 4) :: Word8
-              v5 = PM.indexByteArray array (ixSrc + 5) :: Word8
-              v6 = PM.indexByteArray array (ixSrc + 6) :: Word8
-              v7 = PM.indexByteArray array (ixSrc + 7) :: Word8
-              v8 = PM.indexByteArray array (ixSrc + 8) :: Word8
-              v9 = PM.indexByteArray array (ixSrc + 9) :: Word8
-              v10 = PM.indexByteArray array (ixSrc + 10) :: Word8
-              v11 = PM.indexByteArray array (ixSrc + 11) :: Word8
-              v12 = PM.indexByteArray array (ixSrc + 12) :: Word8
-              v13 = PM.indexByteArray array (ixSrc + 13) :: Word8
-              v14 = PM.indexByteArray array (ixSrc + 14) :: Word8
-              v15 = PM.indexByteArray array (ixSrc + 15) :: Word8
-          PM.writeByteArray dst ixDst v15
-          PM.writeByteArray dst (ixDst + 1) v14
-          PM.writeByteArray dst (ixDst + 2) v13
-          PM.writeByteArray dst (ixDst + 3) v12
-          PM.writeByteArray dst (ixDst + 4) v11
-          PM.writeByteArray dst (ixDst + 5) v10
-          PM.writeByteArray dst (ixDst + 6) v9
-          PM.writeByteArray dst (ixDst + 7) v8
-          PM.writeByteArray dst (ixDst + 8) v7
-          PM.writeByteArray dst (ixDst + 9) v6
-          PM.writeByteArray dst (ixDst + 10) v5
-          PM.writeByteArray dst (ixDst + 11) v4
-          PM.writeByteArray dst (ixDst + 12) v3
-          PM.writeByteArray dst (ixDst + 13) v2
-          PM.writeByteArray dst (ixDst + 14) v1
-          PM.writeByteArray dst (ixDst + 15) v0
-          go (ixSrc + 16) (ixDst + 16) (len - 16)
-        else pure ()
+  let go !ixSrc !ixDst !len =
+        if len > 0
+          then do
+            let v0 = PM.indexByteArray array ixSrc :: Word8
+                v1 = PM.indexByteArray array (ixSrc + 1) :: Word8
+                v2 = PM.indexByteArray array (ixSrc + 2) :: Word8
+                v3 = PM.indexByteArray array (ixSrc + 3) :: Word8
+                v4 = PM.indexByteArray array (ixSrc + 4) :: Word8
+                v5 = PM.indexByteArray array (ixSrc + 5) :: Word8
+                v6 = PM.indexByteArray array (ixSrc + 6) :: Word8
+                v7 = PM.indexByteArray array (ixSrc + 7) :: Word8
+                v8 = PM.indexByteArray array (ixSrc + 8) :: Word8
+                v9 = PM.indexByteArray array (ixSrc + 9) :: Word8
+                v10 = PM.indexByteArray array (ixSrc + 10) :: Word8
+                v11 = PM.indexByteArray array (ixSrc + 11) :: Word8
+                v12 = PM.indexByteArray array (ixSrc + 12) :: Word8
+                v13 = PM.indexByteArray array (ixSrc + 13) :: Word8
+                v14 = PM.indexByteArray array (ixSrc + 14) :: Word8
+                v15 = PM.indexByteArray array (ixSrc + 15) :: Word8
+            PM.writeByteArray dst ixDst v15
+            PM.writeByteArray dst (ixDst + 1) v14
+            PM.writeByteArray dst (ixDst + 2) v13
+            PM.writeByteArray dst (ixDst + 3) v12
+            PM.writeByteArray dst (ixDst + 4) v11
+            PM.writeByteArray dst (ixDst + 5) v10
+            PM.writeByteArray dst (ixDst + 6) v9
+            PM.writeByteArray dst (ixDst + 7) v8
+            PM.writeByteArray dst (ixDst + 8) v7
+            PM.writeByteArray dst (ixDst + 9) v6
+            PM.writeByteArray dst (ixDst + 10) v5
+            PM.writeByteArray dst (ixDst + 11) v4
+            PM.writeByteArray dst (ixDst + 12) v3
+            PM.writeByteArray dst (ixDst + 13) v2
+            PM.writeByteArray dst (ixDst + 14) v1
+            PM.writeByteArray dst (ixDst + 15) v0
+            go (ixSrc + 16) (ixDst + 16) (len - 16)
+          else pure ()
   go offset 0 length
   PM.unsafeFreezeByteArray dst
 
 swapArray256 :: Bytes -> ByteArray
-swapArray256 (Bytes{array,offset,length}) = runByteArrayST $ do
+swapArray256 (Bytes {array, offset, length}) = runST $ do
   dst <- PM.newByteArray length
-  let go !ixSrc !ixDst !len = if len > 0
-        then do
-          let loop !i
-                | i < 32 = do
-                    let v = PM.indexByteArray array (ixSrc + i) :: Word8
-                    PM.writeByteArray dst (ixDst + (31 - i)) v
-                    loop (i + 1)
-                | otherwise = pure ()
-          loop 0
-          go (ixSrc + 32) (ixDst + 32) (len - 32)
-        else pure ()
+  let go !ixSrc !ixDst !len =
+        if len > 0
+          then do
+            let loop !i
+                  | i < 32 = do
+                      let v = PM.indexByteArray array (ixSrc + i) :: Word8
+                      PM.writeByteArray dst (ixDst + (31 - i)) v
+                      loop (i + 1)
+                  | otherwise = pure ()
+            loop 0
+            go (ixSrc + 32) (ixDst + 32) (len - 32)
+          else pure ()
   go offset 0 length
   PM.unsafeFreezeByteArray dst
 
 pureParser :: a -> Parser e s a
-{-# inline pureParser #-}
-pureParser a = Parser
-  (\(# _, b, c #) s -> (# s, (# | (# a, b, c #) #) #))
+{-# INLINE pureParser #-}
+pureParser a =
+  Parser
+    (\(# _, b, c #) s -> (# s, (# | (# a, b, c #) #) #))
 
 bindParser :: Parser e s a -> (a -> Parser e s b) -> Parser e s b
-{-# inline bindParser #-}
-bindParser (Parser f) g = Parser
-  (\x@(# arr, _, _ #) s0 -> case f x s0 of
-    (# s1, r0 #) -> case r0 of
-      (# e | #) -> (# s1, (# e | #) #)
-      (# | (# y, b, c #) #) ->
-        runParser (g y) (# arr, b, c #) s1
-  )
+{-# INLINE bindParser #-}
+bindParser (Parser f) g =
+  Parser
+    ( \x@(# arr, _, _ #) s0 -> case f x s0 of
+        (# s1, r0 #) -> case r0 of
+          (# e | #) -> (# s1, (# e | #) #)
+          (# | (# y, b, c #) #) ->
+            runParser (g y) (# arr, b, c #) s1
+    )
diff --git a/src/Data/Bytes/Parser/Latin.hs b/src/Data/Bytes/Parser/Latin.hs
--- a/src/Data/Bytes/Parser/Latin.hs
+++ b/src/Data/Bytes/Parser/Latin.hs
@@ -1,1302 +1,1524 @@
-{-# language BangPatterns #-}
-{-# language BinaryLiterals #-}
-{-# language DataKinds #-}
-{-# language DeriveFunctor #-}
-{-# language DerivingStrategies #-}
-{-# language GADTSyntax #-}
-{-# language KindSignatures #-}
-{-# language LambdaCase #-}
-{-# language MagicHash #-}
-{-# language MultiWayIf #-}
-{-# language PolyKinds #-}
-{-# language RankNTypes #-}
-{-# language ScopedTypeVariables #-}
-{-# language StandaloneDeriving #-}
-{-# language TypeApplications #-}
-{-# language UnboxedSums #-}
-{-# language UnboxedTuples #-}
-{-# language CPP #-}
-
--- | Parse input as though it were text encoded by
--- ISO 8859-1 (Latin-1). All byte sequences are valid
--- text under ISO 8859-1.
-module Data.Bytes.Parser.Latin
-  ( -- * Matching
-    -- ** Required
-    char
-  , char2
-  , char3
-  , char4
-  , char5
-  , char6
-  , char7
-  , char8
-  , char9
-  , char10
-  , char11
-  , char12
-    -- ** Try
-  , trySatisfy
-  , trySatisfyThen
-    -- * One Character
-  , any
-  , opt
-  , opt#
-    -- * Many Characters
-  , takeTrailedBy
-    -- * Lookahead
-  , peek
-  , peek'
-    -- * Skip
-  , skipDigits
-  , skipDigits1
-  , skipChar
-  , skipChar1
-  , skipTrailedBy
-  , skipUntil
-  , skipWhile
-    -- * End of Input
-  , endOfInput
-  , isEndOfInput
-    -- * Numbers
-    -- ** Decimal
-    -- *** Unsigned
-  , decWord
-  , decWord8
-  , decWord16
-  , decWord32
-  , decWord64
-    -- *** Signed
-  , decUnsignedInt
-  , decUnsignedInt#
-  , decSignedInt
-  , decStandardInt
-  , decTrailingInt
-  , decTrailingInt#
-  , decSignedInteger
-  , decUnsignedInteger
-  , decTrailingInteger
-    -- ** Hexadecimal
-    -- *** Variable Length
-  , hexWord8
-  , hexWord16
-  , hexWord32
-    -- *** Fixed Length
-  , hexFixedWord8
-  , hexFixedWord16
-  , hexFixedWord32
-  , hexFixedWord64
-  , hexFixedWord128
-  , hexFixedWord256
-    -- *** Digit
-  , hexNibbleLower
-  , tryHexNibbleLower
-  , hexNibble
-  , tryHexNibble
-  ) where
-
-import Prelude hiding (length,any,fail,takeWhile)
-
-import Data.Bits ((.|.))
-import Data.Bytes.Types (Bytes(..))
-import Data.Bytes.Parser.Internal (InternalStep(..),unfailing)
-import Data.Bytes.Parser (bindFromLiftedToInt,isEndOfInput,endOfInput)
-import Data.Bytes.Parser.Internal (Parser(..),ST#,uneffectful,Result#,uneffectful#)
-import Data.Bytes.Parser.Internal (Result(..),indexLatinCharArray,upcastUnitSuccess)
-import Data.Bytes.Parser.Internal (boxBytes)
-import Data.Bytes.Parser.Unsafe (expose,cursor,unconsume)
-import Data.Char (ord)
-import Data.Kind (Type)
-import Data.WideWord (Word256(Word256),Word128(Word128))
-import Data.Word (Word8)
-import GHC.Exts (Int(I#),Char(C#),Word#,Int#,Char#,(+#),(-#),indexCharArray#)
-import GHC.Exts (TYPE,RuntimeRep,int2Word#,or#)
-import GHC.Exts (ltWord#,gtWord#,notI#)
-import GHC.Word (Word(W#),Word8(W8#),Word16(W16#),Word32(W32#),Word64(W64#))
-
-import qualified GHC.Exts as Exts
-import qualified Data.Bytes as Bytes
-import qualified Data.Primitive as PM
-
--- | Runs the predicate on the next character in the input. If the
--- predicate is matched, this consumes the character. Otherwise,
--- the character is not consumed. This returns @False@ if the end
--- 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 -> Success False (offset chunk) (length chunk)
-  _ -> case f (indexLatinCharArray (array chunk) (offset chunk)) of
-    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
--- runs the parser on the remaining input. If the function returns
--- @Nothing@, this does not consume the tested character, and it
--- runs the default parser on the input (which includes the tested
--- character). If there is no input remaining, this also runs the
--- default parser. This combinator never fails.
-trySatisfyThen :: forall (r :: RuntimeRep) (e :: Type) (s :: Type) (a :: TYPE r).
-     Parser e s a -- ^ Default parser. Runs on @Nothing@ or end of input.
-  -> (Char -> Maybe (Parser e s a)) -- ^ Parser-selecting predicate
-  -> Parser e s a
-{-# inline trySatisfyThen #-}
-trySatisfyThen (Parser g) f = Parser
-  (\input@(# arr,off0,len0 #) s0 -> case len0 of
-    0# -> g input s0
-    _ -> case f (C# (indexCharArray# arr off0)) of
-      Nothing -> g input s0
-      Just (Parser p) -> p (# arr, off0 +# 1#, len0 -# 1# #) s0
-  )
-
--- | 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 ()
-{-# inline char #-}
-char e !c = uneffectful $ \chunk -> if length chunk > 0
-  then if indexLatinCharArray (array chunk) (offset chunk) == c
-    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 ()
-{-# 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
-         -> 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 ()
-{-# 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
-         -> 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 ()
-{-# 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
-         -> 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
-     , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
-     , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
-     , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
-     , indexLatinCharArray (array chunk) (offset chunk + 4) == c4
-         -> 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
-     , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
-     , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
-     , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
-     , indexLatinCharArray (array chunk) (offset chunk + 4) == c4
-     , indexLatinCharArray (array chunk) (offset chunk + 5) == c5
-         -> 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
-     , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
-     , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
-     , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
-     , indexLatinCharArray (array chunk) (offset chunk + 4) == c4
-     , indexLatinCharArray (array chunk) (offset chunk + 5) == c5
-     , indexLatinCharArray (array chunk) (offset chunk + 6) == c6
-         -> 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
-     , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
-     , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
-     , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
-     , indexLatinCharArray (array chunk) (offset chunk + 4) == c4
-     , indexLatinCharArray (array chunk) (offset chunk + 5) == c5
-     , indexLatinCharArray (array chunk) (offset chunk + 6) == c6
-     , indexLatinCharArray (array chunk) (offset chunk + 7) == c7
-         -> 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
-     , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
-     , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
-     , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
-     , indexLatinCharArray (array chunk) (offset chunk + 4) == c4
-     , indexLatinCharArray (array chunk) (offset chunk + 5) == c5
-     , indexLatinCharArray (array chunk) (offset chunk + 6) == c6
-     , indexLatinCharArray (array chunk) (offset chunk + 7) == c7
-     , indexLatinCharArray (array chunk) (offset chunk + 8) == c8
-         -> 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
-     , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
-     , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
-     , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
-     , indexLatinCharArray (array chunk) (offset chunk + 4) == c4
-     , indexLatinCharArray (array chunk) (offset chunk + 5) == c5
-     , indexLatinCharArray (array chunk) (offset chunk + 6) == c6
-     , indexLatinCharArray (array chunk) (offset chunk + 7) == c7
-     , indexLatinCharArray (array chunk) (offset chunk + 8) == c8
-     , indexLatinCharArray (array chunk) (offset chunk + 9) == c9
-         -> 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
-     , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
-     , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
-     , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
-     , indexLatinCharArray (array chunk) (offset chunk + 4) == c4
-     , indexLatinCharArray (array chunk) (offset chunk + 5) == c5
-     , indexLatinCharArray (array chunk) (offset chunk + 6) == c6
-     , indexLatinCharArray (array chunk) (offset chunk + 7) == c7
-     , indexLatinCharArray (array chunk) (offset chunk + 8) == c8
-     , indexLatinCharArray (array chunk) (offset chunk + 9) == c9
-     , indexLatinCharArray (array chunk) (offset chunk + 10) == c10
-         -> 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
-     , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
-     , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
-     , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
-     , indexLatinCharArray (array chunk) (offset chunk + 4) == c4
-     , indexLatinCharArray (array chunk) (offset chunk + 5) == c5
-     , indexLatinCharArray (array chunk) (offset chunk + 6) == c6
-     , indexLatinCharArray (array chunk) (offset chunk + 7) == c7
-     , indexLatinCharArray (array chunk) (offset chunk + 8) == c8
-     , indexLatinCharArray (array chunk) (offset chunk + 9) == c9
-     , indexLatinCharArray (array chunk) (offset chunk + 10) == c10
-     , indexLatinCharArray (array chunk) (offset chunk + 11) == c11
-         -> 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 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 -> Success Nothing (offset chunk) (length chunk)
-  _ -> Success
-    (Just (indexLatinCharArray (array chunk) (offset chunk)))
-    (offset chunk + 1) (length chunk - 1)
-
--- | Variant of @opt@ with unboxed result.
-opt# :: Parser e s (# (# #) | Char# #)
-{-# inline opt# #-}
-opt# = Parser
-  (\(# arr, off, len #) s0 -> case len of
-    0# -> (# s0, (# | (# (# (# #) | #), off, len #) #) #)
-    _ -> (# s0, (# | (# (# | indexCharArray# arr off #), off +# 1#, len -# 1# #) #) #)
-  )
-
-skipDigitsAsciiLoop ::
-     Bytes -- Chunk
-  -> (# Int#, Int# #)
-skipDigitsAsciiLoop !c = if length c > 0
-  then
-    let w = indexLatinCharArray (array c) (offset c)
-     in if w >= '0' && w <= '9'
-          then skipDigitsAsciiLoop (Bytes.unsafeDrop 1 c)
-          else (# unI (offset c), unI (length c) #)
-  else (# unI (offset c), unI (length c) #)
-
-skipDigitsAscii1LoopStart ::
-     e
-  -> Bytes -- chunk
-  -> Result# e ()
-skipDigitsAscii1LoopStart e !c = if length c > 0
-  then
-    let w = indexLatinCharArray (array c) (offset c)
-     in if w >= '0' && w <= '9'
-          then upcastUnitSuccess (skipDigitsAsciiLoop (Bytes.unsafeDrop 1 c))
-          else (# e | #)
-  else (# e | #)
-
--- | 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
-
--- | Skip the characters @0-9@ until a non-digit is encountered.
--- This parser does not fail.
-skipDigits :: Parser e s ()
-skipDigits = uneffectful# $ \c ->
-  upcastUnitSuccess (skipDigitsAsciiLoop c)
-
-unI :: Int -> Int#
-{-# inline unI #-}
-unI (I# w) = w
-
--- | 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
-
-skipLoop ::
-     Char -- byte to match
-  -> Bytes -- Chunk
-  -> (# Int#, Int# #)
-skipLoop !w !c = if length c > 0
-  then if indexLatinCharArray (array c) (offset c) == w
-    then skipLoop w (Bytes.unsafeDrop 1 c)
-    else (# unI (offset c), unI (length c) #)
-  else (# unI (offset c), unI (length c) #)
-
-skipLoop1Start ::
-     e
-  -> Char -- byte to match
-  -> Bytes -- chunk
-  -> Result# e ()
-skipLoop1Start e !w !chunk0 = if length chunk0 > 0
-  then if indexLatinCharArray (array chunk0) (offset chunk0) == w
-    then upcastUnitSuccess (skipLoop w (Bytes.unsafeDrop 1 chunk0))
-    else (# e | #)
-  else (# e | #)
-
--- | Parse a decimal-encoded 8-bit word. If the number is larger
--- than 255, this parser fails.
-decWord8 :: e -> Parser e s Word8
-decWord8 e = Parser
-  (\chunk0 s0 -> case decSmallWordStart e 256 (boxBytes chunk0) s0 of
-    (# s1, r #) -> (# s1, upcastWord8Result r #)
-  )
-
--- | Parse a hexadecimal-encoded 8-bit word. If the number is larger
--- than 255, this parser fails. This allows leading zeroes and is
--- insensitive to case. For example, @00A@, @0a@ and @A@ would all
--- be accepted as the same number.
-hexWord8 :: e -> Parser e s Word8
-hexWord8 e = Parser
-  (\chunk0 s0 -> case hexSmallWordStart e 256 (boxBytes chunk0) s0 of
-    (# s1, r #) -> (# s1, upcastWord8Result r #)
-  )
-
--- | Parse a hexadecimal-encoded 16-bit word. If the number is larger
--- than 65535, this parser fails. This allows leading zeroes and is
--- insensitive to case. For example, @0100a@ and @100A@ would both
--- be accepted as the same number.
-hexWord16 :: e -> Parser e s Word16
-hexWord16 e = Parser
-  (\chunk0 s0 -> case hexSmallWordStart e 65536 (boxBytes chunk0) s0 of
-    (# s1, r #) -> (# s1, upcastWord16Result r #)
-  )
-
-hexWord32 :: e -> Parser e s Word32
-hexWord32 e = Parser
-  (\chunk0 s0 -> case hexSmallWordStart e 4294967296 (boxBytes chunk0) s0 of
-    (# s1, r #) -> (# s1, upcastWord32Result r #)
-  )
-
--- | Parse a decimal-encoded 16-bit word. If the number is larger
--- than 65535, this parser fails.
-decWord16 :: e -> Parser e s Word16
-decWord16 e = Parser
-  (\chunk0 s0 -> case decSmallWordStart e 65536 (boxBytes chunk0) s0 of
-    (# s1, r #) -> (# s1, upcastWord16Result r #)
-  )
-
--- | Parse a decimal-encoded 32-bit word. If the number is larger
--- than 4294967295, this parser fails.
-decWord32 :: e -> Parser e s Word32
--- This will not work on 32-bit platforms.
-decWord32 e = Parser
-  (\chunk0 s0 -> case decSmallWordStart e 4294967296 (boxBytes chunk0) s0 of
-    (# s1, r #) -> (# s1, upcastWord32Result r #)
-  )
-
--- | Parse a decimal-encoded number. If the number is too large to be
--- represented by a machine word, this fails with the provided
--- error message. This accepts any number of leading zeroes.
-decWord :: e -> Parser e s Word
-decWord e = Parser
-  (\chunk0 s0 -> case decWordStart e (boxBytes chunk0) s0 of
-    (# s1, r #) -> (# s1, upcastWordResult r #)
-  )
-
--- | Parse a decimal-encoded unsigned number. If the number is
--- too large to be represented by a 64-bit word, this fails with
--- the provided error message. This accepts any number of leading
--- zeroes.
-decWord64 :: e -> Parser e s Word64
-decWord64 e = Parser
-  (\chunk0 s0 -> case decWordStart e (boxBytes chunk0) s0 of
-    (# s1, r #) -> (# s1, upcastWord64Result r #)
-  )
-
-hexSmallWordStart ::
-     e -- Error message
-  -> Word -- Upper Bound
-  -> Bytes -- Chunk
-  -> ST# s (Result# e Word# )
-hexSmallWordStart e !limit !chunk0 s0 = if length chunk0 > 0
-  then case oneHexMaybe (PM.indexByteArray (array chunk0) (offset chunk0)) of
-    Nothing -> (# s0, (# e | #) #)
-    Just w -> (# s0, hexSmallWordMore e w limit (Bytes.unsafeDrop 1 chunk0) #)
-  else (# s0, (# e | #) #)
-
-decSmallWordStart ::
-     e -- Error message
-  -> Word -- Upper Bound
-  -> Bytes -- Chunk
-  -> ST# s (Result# e Word# )
-decSmallWordStart e !limit !chunk0 s0 = if length chunk0 > 0
-  then
-    let !w = fromIntegral @Word8 @Word
-          (PM.indexByteArray (array chunk0) (offset chunk0)) - 48
-     in if w < 10
-          then (# s0, decSmallWordMore e w limit (Bytes.unsafeDrop 1 chunk0) #)
-          else (# s0, (# e | #) #)
-  else (# s0, (# e | #) #)
-
--- This will not inline since it is recursive, but worker
--- wrapper will still happen.
-decWordMore ::
-     e -- Error message
-  -> Word -- Accumulator
-  -> Bytes -- Chunk
-  -> Result# e Word#
-decWordMore e !acc !chunk0 = case len of
-  0 -> (# | (# unW (fromIntegral acc), unI (offset chunk0), 0# #) #)
-  _ ->
-    let !w = fromIntegral @Word8 @Word
-          (PM.indexByteArray (array chunk0) (offset chunk0)) - 48
-     in if w < 10
-          then
-            let (overflow,acc') = unsignedPushBase10 acc w
-             in if overflow
-               then (# e | #)
-               else decWordMore e acc' (Bytes.unsafeDrop 1 chunk0)
-          else (# | (# unW (fromIntegral acc), unI (offset chunk0), len# #) #)
-  where
-  !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# (
-#if MIN_VERSION_base(4,17,0)
-    Exts.wordToWord64# a
-#else
-    a
-#endif
-    ), b, c #) #)
-
-hexSmallWordMore ::
-     e -- Error message
-  -> Word -- Accumulator
-  -> Word -- Upper Bound
-  -> Bytes -- Chunk
-  -> Result# e Word#
-hexSmallWordMore e !acc !limit !chunk0 = if length chunk0 > 0
-  then case oneHexMaybe (PM.indexByteArray (array chunk0) (offset chunk0)) of
-    Nothing -> (# | (# unW acc, unI (offset chunk0), unI (length chunk0)  #) #)
-    Just w -> let w' = acc * 16 + w in
-      if w' < limit
-        then hexSmallWordMore e w' limit (Bytes.unsafeDrop 1 chunk0)
-        else (# e | #)
-  else (# | (# unW acc, unI (offset chunk0), 0# #) #)
-
-decSmallWordMore ::
-     e -- Error message
-  -> Word -- Accumulator
-  -> Word -- Upper Bound
-  -> Bytes -- Chunk
-  -> Result# e Word#
-decSmallWordMore e !acc !limit !chunk0 = if length chunk0 > 0
-  then
-    let !w = fromIntegral @Word8 @Word
-          (PM.indexByteArray (array chunk0) (offset chunk0)) - 48
-     in if w < 10
-          then
-            let w' = acc * 10 + w
-             in if w' < limit
-                  then decSmallWordMore e w' limit (Bytes.unsafeDrop 1 chunk0)
-                  else (# e | #)
-          else (# | (# unW acc, unI (offset chunk0), unI (length chunk0)  #) #)
-  else (# | (# unW acc, unI (offset chunk0), 0# #) #)
-
-unW :: Word -> Word#
-{-# inline unW #-}
-unW (W# w) = w
-
-decWordStart ::
-     e -- Error message
-  -> Bytes -- Chunk
-  -> ST# s (Result# e Word# )
-decWordStart e !chunk0 s0 = if length chunk0 > 0
-  then
-    let !w = fromIntegral @Word8 @Word
-          (PM.indexByteArray (array chunk0) (offset chunk0)) - 48
-     in if w < 10
-          then (# s0, decWordMore e w (Bytes.unsafeDrop 1 chunk0) #)
-          else (# s0, (# e | #) #)
-  else (# s0, (# e | #) #)
-
--- Precondition: the word is small enough
-upcastWord16Result :: Result# e Word# -> Result# e Word16
-{-# 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
-upcastWord32Result :: Result# e Word# -> Result# e Word32
-{-# 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
-upcastWord8Result :: Result# e Word# -> Result# e Word8
-{-# inline upcastWord8Result #-}
-upcastWord8Result (# e | #) = (# e | #)
-upcastWord8Result (# | (# a, b, c #) #) = (# | (# W8# (
-#if MIN_VERSION_base(4,16,0)
-  Exts.wordToWord8#
-#endif
-  a), b, c #) #)
-
--- | Parse a decimal-encoded number. If the number is too large to be
--- represented by a machine integer, this fails with the provided
--- error message. This rejects input with that is preceeded by plus
--- or minus. Consequently, it does not parse negative numbers. Use
--- 'decStandardInt' or 'decSignedInt' for that purpose. On a 64-bit
--- platform 'decWord' will successfully parse 9223372036854775808
--- (i.e. @2 ^ 63@), but 'decUnsignedInt' will fail. This parser allows
--- leading zeroes.
-decUnsignedInt :: e -> Parser e s Int
-decUnsignedInt e = Parser
-  (\chunk0 s0 -> case decPosIntStart e (boxBytes chunk0) s0 of
-    (# s1, r #) -> (# s1, upcastIntResult r #)
-  )
-
--- | Variant of 'decUnsignedInt' with an unboxed result.
-decUnsignedInt# :: e -> Parser e s Int#
-decUnsignedInt# e = Parser
-  (\chunk0 s0 -> decPosIntStart e (boxBytes chunk0) s0)
-
--- | Parse a decimal-encoded number. If the number is too large to be
--- represented by a machine integer, this fails with the provided
--- error message. This allows the number to optionally be prefixed
--- by plus or minus. If the sign prefix is not present, the number
--- is interpreted as positive. This allows leading zeroes.
-decSignedInt :: e -> Parser e s Int
-decSignedInt e = Parser
-  (\chunk0 s0 -> case runParser (decSignedInt# e) chunk0 s0 of
-    (# s1, r #) -> (# s1, upcastIntResult r #)
-  )
-
--- | Variant of 'decUnsignedInt' that lets the caller supply a leading
--- digit. This is useful when parsing formats like JSON where integers with
--- leading zeroes are considered invalid. The calling context must
--- consume the first digit before calling this parser. Results are
--- always positive numbers.
-decTrailingInt ::
-     e -- ^ Error message
-  -> Int -- ^ Leading digit, should be between @0@ and @9@.
-  -> Parser e s Int
-decTrailingInt e (I# w) = Parser
-  (\chunk0 s0 -> case runParser (decTrailingInt# e w) chunk0 s0 of
-    (# s1, r #) -> (# s1, upcastIntResult r #)
-  )
-
-decTrailingInt# ::
-     e -- Error message
-  -> Int# -- Leading digit, should be between @0@ and @9@.
-  -> Parser e s Int#
-decTrailingInt# e !w =
-  Parser (\chunk0 s0 -> (# s0, decPosIntMore e (W# (int2Word# w)) maxIntAsWord (boxBytes chunk0) #))
-
-maxIntAsWord :: Word
-maxIntAsWord = fromIntegral (maxBound :: Int)
-
--- | Parse a decimal-encoded number. If the number is too large to be
--- represented by a machine integer, this fails with the provided
--- error message. This allows the number to optionally be prefixed
--- by minus. If the minus prefix is not present, the number
--- is interpreted as positive. The disallows a leading plus sign.
--- For example, 'decStandardInt' rejects @+42@, but 'decSignedInt'
--- allows it.
-decStandardInt :: e -> Parser e s Int
-decStandardInt e = Parser
-  (\chunk0 s0 -> case runParser (decStandardInt# e) chunk0 s0 of
-    (# s1, r #) -> (# s1, upcastIntResult r #)
-  )
-
-decSignedInt# :: e -> Parser e s Int#
-{-# noinline decSignedInt# #-}
-decSignedInt# e = any e `bindFromLiftedToInt` \c -> case c of
-  '+' -> Parser -- plus sign
-    (\chunk0 s0 -> decPosIntStart e (boxBytes chunk0) s0)
-  '-' -> Parser -- minus sign
-    (\chunk0 s0 -> decNegIntStart e (boxBytes chunk0) s0)
-  _ -> Parser -- no sign, there should be a digit here
-    (\chunk0 s0 ->
-      let !w = char2Word c - 48
-        in if w < 10
-             then (# s0, decPosIntMore e w maxIntAsWord (boxBytes chunk0) #)
-             else (# s0, (# e | #) #)
-    )
-
--- This is the same as decSignedInt except that we disallow
--- a leading plus sign.
-decStandardInt# :: e -> Parser e s Int#
-{-# noinline decStandardInt# #-}
-decStandardInt# e = any e `bindFromLiftedToInt` \c -> case c of
-  '-' -> Parser -- minus sign
-    (\chunk0 s0 -> decNegIntStart e (boxBytes chunk0) s0)
-  _ -> Parser -- no sign, there should be a digit here
-    (\chunk0 s0 ->
-      let !w = char2Word c - 48
-        in if w < 10
-             then (# s0, decPosIntMore e w maxIntAsWord (boxBytes chunk0) #)
-             else (# s0, (# e | #) #)
-    )
-
--- | Variant of 'decUnsignedInteger' that lets the caller supply a leading
--- digit. This is useful when parsing formats like JSON where integers with
--- leading zeroes are considered invalid. The calling context must
--- consume the first digit before calling this parser. Results are
--- always positive numbers.
-decTrailingInteger ::
-     Int -- ^ Leading digit, should be between @0@ and @9@.
-  -> Parser e s Integer
-decTrailingInteger (I# w) =
-  Parser (\chunk0 s0 -> (# s0, (# | decIntegerChunks (I# w) 10 0 (boxBytes chunk0) #) #))
-
--- | Parse a decimal-encoded positive integer of arbitrary
--- size. This rejects input that begins with a plus or minus
--- sign.
-decUnsignedInteger :: e -> Parser e s Integer
-decUnsignedInteger e = Parser
-  (\chunk0 s0 -> decUnsignedIntegerStart e (boxBytes chunk0) s0)
-
--- | Parse a decimal-encoded integer of arbitrary size.
--- This accepts input that begins with a plus or minus sign.
--- Input without a sign prefix is interpreted as positive.
-decSignedInteger :: e -> Parser e s Integer
-{-# noinline decSignedInteger #-}
-decSignedInteger e = any e >>= \c -> case c of
-  '+' -> do
-    decUnsignedInteger e
-  '-' -> do
-    x <- decUnsignedInteger e
-    pure $! negate x
-  _ -> Parser -- no sign, there should be a digit here
-    (\chunk0 s0 ->
-      let !w = char2Word c - 48 in
-      if w < 10
-        then
-          let !r = decIntegerChunks
-                (fromIntegral @Word @Int w)
-                10
-                0
-                (boxBytes chunk0)
-           in (# s0, (# | r #) #)
-        else (# s0, (# e | #) #)
-    )
-
-decPosIntStart ::
-     e -- Error message
-  -> Bytes -- Chunk
-  -> ST# s (Result# e Int# )
-decPosIntStart e !chunk0 s0 = if length chunk0 > 0
-  then
-    let !w = fromIntegral @Word8 @Word
-          (PM.indexByteArray (array chunk0) (offset chunk0)) - 48
-     in if w < 10
-          then (# s0, decPosIntMore e w maxIntAsWord (Bytes.unsafeDrop 1 chunk0) #)
-          else (# s0, (# e | #) #)
-  else (# s0, (# e | #) #)
-
-decNegIntStart ::
-     e -- Error message
-  -> Bytes -- Chunk
-  -> ST# s (Result# e Int# )
-decNegIntStart e !chunk0 s0 = if length chunk0 > 0
-  then
-    let !w = fromIntegral @Word8 @Word
-          (PM.indexByteArray (array chunk0) (offset chunk0)) - 48
-     in if w < 10
-          then
-            case decPosIntMore e w (maxIntAsWord + 1) (Bytes.unsafeDrop 1 chunk0) of
-             (# | (# x, y, z #) #) ->
-               (# s0, (# | (# (notI# x +# 1# ), y, z #) #) #)
-             (# err | #) ->
-               (# s0, (# err | #) #)
-          else (# s0, (# e | #) #)
-  else (# s0, (# e | #) #)
-
-decUnsignedIntegerStart ::
-     e
-  -> Bytes
-  -> ST# s (Result# e Integer)
-decUnsignedIntegerStart e !chunk0 s0 = if length chunk0 > 0
-  then
-    let !w = (PM.indexByteArray (array chunk0) (offset chunk0)) - 48
-     in if w < (10 :: Word8)
-          then
-            let !r = decIntegerChunks
-                  (fromIntegral @Word8 @Int w)
-                  10
-                  0
-                  (Bytes.unsafeDrop 1 chunk0)
-             in (# s0, (# | r #) #)
-          else (# s0, (# e | #) #)
-  else (# s0, (# e | #) #)
-
--- This will not inline since it is recursive, but worker
--- wrapper will still happen. Fails if the accumulator
--- exceeds the upper bound.
-decPosIntMore ::
-     e -- Error message
-  -> Word -- Accumulator, precondition: less than or equal to bound
-  -> Word -- Inclusive Upper Bound, either (2^63 - 1) or 2^63
-  -> Bytes -- Chunk
-  -> Result# e Int#
-decPosIntMore e !acc !upper !chunk0 = if len > 0
-  then
-    let !w = fromIntegral @Word8 @Word
-          (PM.indexByteArray (array chunk0) (offset chunk0)) - 48
-     in if w < 10
-          then
-            let (overflow,acc') = positivePushBase10 acc w upper
-             in if overflow
-               then (# e | #)
-               else decPosIntMore e acc' upper (Bytes.unsafeDrop 1 chunk0)
-          else (# | (# unI (fromIntegral acc), unI (offset chunk0), len# #) #)
-  else (# | (# unI (fromIntegral acc), unI (offset chunk0), 0# #) #)
-  where
-  !len@(I# len# ) = length chunk0
-
--- This will not inline since it is recursive, but worker
--- wrapper will still happen. When the accumulator
--- exceeds the size of a machine integer, this pushes the
--- accumulated machine int and the shift amount onto the
--- stack.
--- We are intentionally lazy in the accumulator. There is
--- no need to force this on every iteration. We do however,
--- force it preemptively every time it changes.
--- Because of how we track overflow, we are able to use the
--- same function for both positive and negative numbers.
-decIntegerChunks ::
-     Int -- Chunk accumulator (e.g. 236)
-  -> Int -- Chunk base-ten bound (e.g. 1000)
-  -> Integer -- Accumulator
-  -> Bytes -- Chunk
-  -> (# Integer, Int#, Int# #)
-decIntegerChunks !nAcc !eAcc acc !chunk0 = if len > 0
-  then
-    let !w = fromIntegral @Word8 @Word
-          (PM.indexByteArray (array chunk0) (offset chunk0)) - 48
-     in if w < 10
-          then let !eAcc' = eAcc * 10 in
-            if eAcc' >= eAcc
-              then decIntegerChunks
-                (nAcc * 10 + fromIntegral @Word @Int w)
-                eAcc'
-                acc
-                (Bytes.unsafeDrop 1 chunk0)
-              else
-                -- In this case, notice that we deliberately
-                -- unconsume the digit that would have caused
-                -- an overflow.
-                let !r = (acc * fromIntegral @Int @Integer eAcc)
-                       + (fromIntegral @Int @Integer nAcc)
-                 in decIntegerChunks 0 1 r chunk0
-          else
-            let !r = (acc * fromIntegral @Int @Integer eAcc)
-                   + (fromIntegral @Int @Integer nAcc)
-             in (# r, unI (offset chunk0), len# #)
-  else
-    let !r = (acc * fromIntegral @Int @Integer eAcc)
-           + (fromIntegral @Int @Integer nAcc)
-     in (# r, unI (offset chunk0), 0# #)
-  where
-  !len@(I# len# ) = length chunk0
-
-upcastIntResult :: Result# e Int# -> Result# e Int
-upcastIntResult (# e | #) = (# e | #)
-upcastIntResult (# | (# a, b, c #) #) = (# | (# I# a, b, c #) #)
-
-char2Word :: Char -> Word
-char2Word = fromIntegral . ord
-
--- | Take characters until the specified character is encountered.
--- Consumes the matched character as well. Fails if the character
--- is not present.  Visually, the cursor advancement and resulting
--- @Bytes@ for @takeTrailedBy \'D\'@ look like this:
---
--- >  A B C D E F | input
--- > |->->->-|    | cursor
--- > {-*-*-}      | result bytes
-takeTrailedBy :: e -> Char -> Parser e s Bytes
-takeTrailedBy e !w = do
-  !start <- cursor
-  skipTrailedBy e w
-  !end <- cursor
-  !arr <- expose
-  pure (Bytes arr start (end - (start + 1)))
-
--- | Skip all characters until the terminator is encountered
--- and then consume the matching character as well. Visually,
--- @skipTrailedBy \'C\'@ advances the cursor like this:
---
--- >  A Z B Y C X C W
--- > |->->->->-|
---
--- This fails if it reaches the end of input without encountering
--- the character.
-skipTrailedBy :: e -> Char -> Parser e s ()
-skipTrailedBy e !w = uneffectful# $ \c ->
-  skipUntilConsumeLoop e w c
-
--- | Skip all characters until the terminator is encountered.
--- This does not consume the terminator. Visually, @skipUntil \'C\'@
--- advances the cursor like this:
---
--- >  A Z B Y C X C W
--- > |->->->-|
---
--- This succeeds if it reaches the end of the input without
--- encountering the terminator. It never fails.
-skipUntil :: Char -> Parser e s ()
-skipUntil !w = uneffectful# $ \c -> skipUntilLoop w c
-
-skipUntilLoop ::
-     Char -- byte to match
-  -> Bytes -- Chunk
-  -> Result# e ()
-skipUntilLoop !w !c = case length c of
-  0 -> (# | (# (), unI (offset c), 0# #) #)
-  _ -> if indexLatinCharArray (array c) (offset c) /= w
-    then skipUntilLoop w (Bytes.unsafeDrop 1 c)
-    else (# | (# (), unI (offset c), unI (length c) #) #)
-
-skipUntilConsumeLoop ::
-     e -- Error message
-  -> Char -- byte to match
-  -> Bytes -- Chunk
-  -> Result# e ()
-skipUntilConsumeLoop e !w !c = case length c of
-  0 -> (# e | #)
-  _ -> if indexLatinCharArray (array c) (offset c) /= w
-    then skipUntilConsumeLoop e w (Bytes.unsafeDrop 1 c)
-    else (# | (# (), unI (offset c + 1), unI (length c - 1) #) #)
-
-
--- | Parse exactly eight ASCII-encoded characters, interpreting them as the
--- hexadecimal encoding of a 32-bit number. Note that this rejects a sequence
--- such as @BC5A9@, requiring @000BC5A9@ instead. This is insensitive to case.
-hexFixedWord32 :: e -> Parser e s Word32
-{-# inline hexFixedWord32 #-}
-hexFixedWord32 e = Parser
-  (\x s0 -> case runParser (hexFixedWord32# e) x s0 of
-    (# 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 #) #) #)
-  )
-
-hexFixedWord32# :: e -> Parser e s Word#
-{-# noinline hexFixedWord32# #-}
-hexFixedWord32# e = uneffectfulWord# $ \chunk -> if length chunk >= 8
-  then
-    let !w0@(W# n0) = oneHex $ PM.indexByteArray (array chunk) (offset chunk)
-        !w1@(W# n1) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 1)
-        !w2@(W# n2) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 2)
-        !w3@(W# n3) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 3)
-        !w4@(W# n4) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 4)
-        !w5@(W# n5) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 5)
-        !w6@(W# n6) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 6)
-        !w7@(W# n7) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 7)
-     in if | w0 .|. w1 .|. w2 .|. w3 .|. w4 .|. w5 .|. w6 .|. w7 /= maxBound ->
-             (# |
-                (# (n0 `Exts.timesWord#` 268435456##) `Exts.plusWord#`
-                   (n1 `Exts.timesWord#` 16777216##) `Exts.plusWord#`
-                   (n2 `Exts.timesWord#` 1048576##) `Exts.plusWord#`
-                   (n3 `Exts.timesWord#` 65536##) `Exts.plusWord#`
-                   (n4 `Exts.timesWord#` 4096##) `Exts.plusWord#`
-                   (n5 `Exts.timesWord#` 256##) `Exts.plusWord#`
-                   (n6 `Exts.timesWord#` 16##) `Exts.plusWord#`
-                   n7
-                ,  unI (offset chunk) +# 8#
-                ,  unI (length chunk) -# 8# #) #)
-           | otherwise -> (# e | #)
-  else (# e | #)
-
--- | Parse exactly 16 ASCII-encoded characters, interpreting them as the
--- hexadecimal encoding of a 64-bit number. Note that this rejects a sequence
--- such as @BC5A9@, requiring @00000000000BC5A9@ instead. This is insensitive
--- to case.
-hexFixedWord64 :: e -> Parser e s Word64
-{-# inline hexFixedWord64 #-}
-hexFixedWord64 e = Parser
-  (\x s0 -> case runParser (hexFixedWord64# e) x s0 of
-    (# 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 #) #) #)
-  )
-
-hexFixedWord128 :: e -> Parser e s Word128
-hexFixedWord128 e = Word128
-  <$> hexFixedWord64 e
-  <*> hexFixedWord64 e
-
-hexFixedWord256 :: e -> Parser e s Word256
-hexFixedWord256 e = Word256
-  <$> hexFixedWord64 e
-  <*> hexFixedWord64 e
-  <*> hexFixedWord64 e
-  <*> hexFixedWord64 e
-
-hexFixedWord64# :: e -> Parser e s Word#
-{-# noinline hexFixedWord64# #-}
-hexFixedWord64# e = uneffectfulWord# $ \chunk -> if length chunk >= 16
-  then
-    let go !off !len !acc = case len of
-          0 -> case acc of
-            W# r ->
-              (# | (# r
-              ,  unI off
-              ,  unI (length chunk) -# 16# #) #)
-          _ -> case oneHexMaybe (PM.indexByteArray (array chunk) off) of
-            Nothing -> (# e | #)
-            Just w -> go (off + 1) (len - 1) ((acc * 16) + w)
-     in go (offset chunk) (16 :: Int) (0 :: Word)
-  else (# e | #)
-
--- | Parse exactly four ASCII-encoded characters, interpreting
--- them as the hexadecimal encoding of a 16-bit number. Note that
--- this rejects a sequence such as @5A9@, requiring @05A9@ instead.
--- This is insensitive to case. This is particularly useful when
--- parsing escape sequences in C or JSON, which allow encoding
--- characters in the Basic Multilingual Plane as @\\uhhhh@.
-hexFixedWord16 :: e -> Parser e s Word16
-{-# inline hexFixedWord16 #-}
-hexFixedWord16 e = Parser
-  (\x s0 -> case runParser (hexFixedWord16# e) x s0 of
-    (# 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 #) #) #)
-  )
-
-hexFixedWord16# :: e -> Parser e s Word#
-{-# noinline hexFixedWord16# #-}
-hexFixedWord16# e = uneffectfulWord# $ \chunk -> if length chunk >= 4
-  then
-    let !w0@(W# n0) = oneHex $ PM.indexByteArray (array chunk) (offset chunk)
-        !w1@(W# n1) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 1)
-        !w2@(W# n2) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 2)
-        !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#`
-                   n3
-                ,  unI (offset chunk) +# 4#
-                ,  unI (length chunk) -# 4# #) #)
-           | otherwise -> (# e | #)
-  else (# e | #)
-
--- | Parse exactly two ASCII-encoded characters, interpretting
--- them as the hexadecimal encoding of a 8-bit number. Note that
--- this rejects a sequence such as @A@, requiring @0A@ instead.
--- This is insensitive to case.
-hexFixedWord8 :: e -> Parser e s Word8
-{-# inline hexFixedWord8 #-}
-hexFixedWord8 e = Parser
-  (\x s0 -> case runParser (hexFixedWord8# e) x s0 of
-    (# 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 #) #) #)
-  )
-
-hexFixedWord8# :: e -> Parser e s Word#
-{-# noinline hexFixedWord8# #-}
-hexFixedWord8# e = uneffectfulWord# $ \chunk -> if length chunk >= 2
-  then
-    let !w0@(W# n0) = oneHex $ PM.indexByteArray (array chunk) (offset chunk)
-        !w1@(W# n1) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 1)
-     in if | w0 .|. w1 /= maxBound ->
-             (# |
-                (# (n0 `Exts.timesWord#` 16##) `Exts.plusWord#`
-                   n1
-                ,  unI (offset chunk) +# 2#
-                ,  unI (length chunk) -# 2# #) #)
-           | otherwise -> (# e | #)
-  else (# e | #)
-
--- | Consume a single character that is the lowercase hexadecimal
--- encoding of a 4-bit word. Fails if the character is not in the class
--- @[a-f0-9]@.
-hexNibbleLower :: e -> Parser e s Word
-hexNibbleLower e = uneffectful $ \chunk -> case length chunk of
-  0 -> Failure e
-  _ ->
-    let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8 in
-    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 -> Failure e
-  _ ->
-    let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8 in
-    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
--- the character if it is not in the class @[a-f0-9]@. The parser
--- never fails.
-tryHexNibbleLower :: Parser e s (Maybe Word)
-tryHexNibbleLower = unfailing $ \chunk -> case length chunk of
-  0 -> InternalStep Nothing (offset chunk) (length chunk)
-  _ ->
-    let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8 in
-    if | w >= 48 && w < 58 -> InternalStep (Just (fromIntegral w - 48)) (offset chunk + 1) (length chunk - 1)
-       | w >= 97 && w < 103 -> InternalStep (Just (fromIntegral w - 87)) (offset chunk + 1) (length chunk - 1)
-       | otherwise -> InternalStep Nothing (offset chunk) (length chunk)
-
--- | Consume a single character that is the case-insensitive hexadecimal
--- encoding of a 4-bit word. Returns @Nothing@ without consuming
--- the character if it is not in the class @[a-fA-F0-9]@. This parser
--- never fails.
-tryHexNibble :: Parser e s (Maybe Word)
-tryHexNibble = unfailing $ \chunk -> case length chunk of
-  0 -> InternalStep Nothing (offset chunk) (length chunk)
-  _ ->
-    let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8 in
-    if | w >= 48 && w < 58 -> InternalStep (Just (fromIntegral w - 48)) (offset chunk + 1) (length chunk - 1)
-       | w >= 65 && w < 71 -> InternalStep (Just (fromIntegral w - 55)) (offset chunk + 1) (length chunk - 1)
-       | w >= 97 && w < 103 -> InternalStep (Just (fromIntegral w - 87)) (offset chunk + 1) (length chunk - 1)
-       | otherwise -> InternalStep Nothing (offset chunk) (length chunk)
-
--- 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)
-  | w >= 97 && w < 103 = (fromIntegral w - 87)
-  | otherwise = maxBound
-
-oneHexMaybe :: Word8 -> Maybe Word
-{-# inline oneHexMaybe #-}
-oneHexMaybe w
-  | w >= 48 && w < 58 = Just (fromIntegral w - 48)
-  | w >= 65 && w < 71 = Just (fromIntegral w - 55)
-  | w >= 97 && w < 103 = Just (fromIntegral w - 87)
-  | otherwise = Nothing
-
-uneffectfulWord# :: (Bytes -> Result# e Word#) -> Parser e s Word#
-{-# inline uneffectfulWord# #-}
-uneffectfulWord# f = Parser
-  ( \b s0 -> (# s0, (f (boxBytes b)) #) )
-
--- Precondition: the arguments are non-negative. Boolean is
--- true when overflow happens. Performs: a * 10 + b
--- 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
-      !cb = int2Word# (gtWord# r1 upper)
-      !cc = int2Word# (ltWord# r1 0##)
-      !c = ca `or#` cb `or#` cc
-   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
-      !cb = int2Word# (ltWord# r1 r0)
-      !c = ca `or#` cb
-   in (case c of { 0## -> False; _ -> True }, W# r1)
-
--- | Skip while the predicate is matched. This is always inlined.
-skipWhile :: (Char -> Bool) -> Parser e s ()
-{-# inline skipWhile #-}
-skipWhile f = go where
-  go = isEndOfInput >>= \case
-    True -> pure ()
-    False -> do
-      w <- anyUnsafe
-      if f w
-        then go
-        else unconsume 1
-
--- Interpret the next byte as an Latin1-encoded character.
--- Does not check to see if any characters are left. This
--- is not exported.
-anyUnsafe :: Parser e s Char
-{-# inline anyUnsafe #-}
-anyUnsafe = uneffectful $ \chunk ->
-  let w = indexCharArray (array chunk) (offset chunk) :: Char
-   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
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE BinaryLiterals #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE GADTSyntax #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE MultiWayIf #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE UnboxedSums #-}
+{-# LANGUAGE UnboxedTuples #-}
+
+{- | Parse input as though it were text encoded by
+ISO 8859-1 (Latin-1). All byte sequences are valid
+text under ISO 8859-1.
+-}
+module Data.Bytes.Parser.Latin
+  ( -- * Matching
+
+    -- ** Required
+    char
+  , char2
+  , char3
+  , char4
+  , char5
+  , char6
+  , char7
+  , char8
+  , char9
+  , char10
+  , char11
+  , char12
+
+    -- ** Try
+  , trySatisfy
+  , trySatisfyThen
+
+    -- * One Character
+  , any
+  , opt
+  , opt#
+
+    -- * Many Characters
+  , takeTrailedBy
+
+    -- * Lookahead
+  , peek
+  , peek'
+
+    -- * Skip
+  , skipDigits
+  , skipDigits1
+  , skipChar
+  , skipChar1
+  , skipTrailedBy
+  , skipUntil
+  , skipWhile
+
+    -- * End of Input
+  , endOfInput
+  , isEndOfInput
+
+    -- * Numbers
+
+    -- ** Decimal
+
+    -- *** Unsigned
+  , decWord
+  , decWord8
+  , decWord16
+  , decWord32
+  , decWord64
+
+    -- *** Signed
+  , decUnsignedInt
+  , decUnsignedInt#
+  , decSignedInt
+  , decStandardInt
+  , decTrailingInt
+  , decTrailingInt#
+  , decSignedInteger
+  , decUnsignedInteger
+  , decTrailingInteger
+
+    -- ** Hexadecimal
+
+    -- *** Variable Length
+  , hexWord8
+  , hexWord16
+  , hexWord32
+
+    -- *** Fixed Length
+  , hexFixedWord8
+  , hexFixedWord16
+  , hexFixedWord32
+  , hexFixedWord64
+  , hexFixedWord128
+  , hexFixedWord256
+
+    -- *** Digit
+  , hexNibbleLower
+  , tryHexNibbleLower
+  , hexNibble
+  , tryHexNibble
+  ) where
+
+import Prelude hiding (any, fail, length, takeWhile)
+
+import Data.Bits ((.|.))
+import Data.Bytes.Parser (bindFromLiftedToInt, endOfInput, isEndOfInput)
+import Data.Bytes.Parser.Internal (InternalStep (..), Parser (..), Result (..), Result#, ST#, boxBytes, indexLatinCharArray, uneffectful, uneffectful#, unfailing, upcastUnitSuccess)
+import Data.Bytes.Parser.Unsafe (cursor, expose, unconsume)
+import Data.Bytes.Types (Bytes (..))
+import Data.Char (ord)
+import Data.Kind (Type)
+import Data.WideWord (Word128 (Word128), Word256 (Word256))
+import Data.Word (Word8)
+import GHC.Exts (Char (C#), Char#, Int (I#), Int#, RuntimeRep, TYPE, Word#, gtWord#, indexCharArray#, int2Word#, ltWord#, notI#, or#, (+#), (-#))
+import GHC.Word (Word (W#), Word16 (W16#), Word32 (W32#), Word64 (W64#), Word8 (W8#))
+
+import qualified Data.Bytes as Bytes
+import qualified Data.Primitive as PM
+import qualified GHC.Exts as Exts
+
+{- | Runs the predicate on the next character in the input. If the
+predicate is matched, this consumes the character. Otherwise,
+the character is not consumed. This returns @False@ if the end
+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 -> Success False (offset chunk) (length chunk)
+  _ -> case f (indexLatinCharArray (array chunk) (offset chunk)) of
+    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
+runs the parser on the remaining input. If the function returns
+@Nothing@, this does not consume the tested character, and it
+runs the default parser on the input (which includes the tested
+character). If there is no input remaining, this also runs the
+default parser. This combinator never fails.
+-}
+trySatisfyThen ::
+  forall (r :: RuntimeRep) (e :: Type) (s :: Type) (a :: TYPE r).
+  -- | Default parser. Runs on @Nothing@ or end of input.
+  Parser e s a ->
+  -- | Parser-selecting predicate
+  (Char -> Maybe (Parser e s a)) ->
+  Parser e s a
+{-# INLINE trySatisfyThen #-}
+trySatisfyThen (Parser g) f =
+  Parser
+    ( \input@(# arr, off0, len0 #) s0 -> case len0 of
+        0# -> g input s0
+        _ -> case f (C# (indexCharArray# arr off0)) of
+          Nothing -> g input s0
+          Just (Parser p) -> p (# arr, off0 +# 1#, len0 -# 1# #) s0
+    )
+
+{- | 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 ()
+{-# INLINE char #-}
+char e !c = uneffectful $ \chunk ->
+  if length chunk > 0
+    then
+      if indexLatinCharArray (array chunk) (offset chunk) == c
+        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 ()
+{-# 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 ->
+        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 ()
+{-# 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 ->
+        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 ()
+{-# 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 ->
+        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
+    , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
+    , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
+    , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
+    , indexLatinCharArray (array chunk) (offset chunk + 4) == c4 ->
+        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
+    , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
+    , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
+    , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
+    , indexLatinCharArray (array chunk) (offset chunk + 4) == c4
+    , indexLatinCharArray (array chunk) (offset chunk + 5) == c5 ->
+        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
+    , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
+    , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
+    , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
+    , indexLatinCharArray (array chunk) (offset chunk + 4) == c4
+    , indexLatinCharArray (array chunk) (offset chunk + 5) == c5
+    , indexLatinCharArray (array chunk) (offset chunk + 6) == c6 ->
+        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
+    , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
+    , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
+    , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
+    , indexLatinCharArray (array chunk) (offset chunk + 4) == c4
+    , indexLatinCharArray (array chunk) (offset chunk + 5) == c5
+    , indexLatinCharArray (array chunk) (offset chunk + 6) == c6
+    , indexLatinCharArray (array chunk) (offset chunk + 7) == c7 ->
+        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
+    , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
+    , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
+    , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
+    , indexLatinCharArray (array chunk) (offset chunk + 4) == c4
+    , indexLatinCharArray (array chunk) (offset chunk + 5) == c5
+    , indexLatinCharArray (array chunk) (offset chunk + 6) == c6
+    , indexLatinCharArray (array chunk) (offset chunk + 7) == c7
+    , indexLatinCharArray (array chunk) (offset chunk + 8) == c8 ->
+        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
+    , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
+    , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
+    , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
+    , indexLatinCharArray (array chunk) (offset chunk + 4) == c4
+    , indexLatinCharArray (array chunk) (offset chunk + 5) == c5
+    , indexLatinCharArray (array chunk) (offset chunk + 6) == c6
+    , indexLatinCharArray (array chunk) (offset chunk + 7) == c7
+    , indexLatinCharArray (array chunk) (offset chunk + 8) == c8
+    , indexLatinCharArray (array chunk) (offset chunk + 9) == c9 ->
+        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
+    , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
+    , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
+    , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
+    , indexLatinCharArray (array chunk) (offset chunk + 4) == c4
+    , indexLatinCharArray (array chunk) (offset chunk + 5) == c5
+    , indexLatinCharArray (array chunk) (offset chunk + 6) == c6
+    , indexLatinCharArray (array chunk) (offset chunk + 7) == c7
+    , indexLatinCharArray (array chunk) (offset chunk + 8) == c8
+    , indexLatinCharArray (array chunk) (offset chunk + 9) == c9
+    , indexLatinCharArray (array chunk) (offset chunk + 10) == c10 ->
+        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
+    , indexLatinCharArray (array chunk) (offset chunk + 1) == c1
+    , indexLatinCharArray (array chunk) (offset chunk + 2) == c2
+    , indexLatinCharArray (array chunk) (offset chunk + 3) == c3
+    , indexLatinCharArray (array chunk) (offset chunk + 4) == c4
+    , indexLatinCharArray (array chunk) (offset chunk + 5) == c5
+    , indexLatinCharArray (array chunk) (offset chunk + 6) == c6
+    , indexLatinCharArray (array chunk) (offset chunk + 7) == c7
+    , indexLatinCharArray (array chunk) (offset chunk + 8) == c8
+    , indexLatinCharArray (array chunk) (offset chunk + 9) == c9
+    , indexLatinCharArray (array chunk) (offset chunk + 10) == c10
+    , indexLatinCharArray (array chunk) (offset chunk + 11) == c11 ->
+        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 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 -> Success Nothing (offset chunk) (length chunk)
+  _ ->
+    Success
+      (Just (indexLatinCharArray (array chunk) (offset chunk)))
+      (offset chunk + 1)
+      (length chunk - 1)
+
+-- | Variant of @opt@ with unboxed result.
+opt# :: Parser e s (# (# #) | Char# #)
+{-# INLINE opt# #-}
+opt# =
+  Parser
+    ( \(# arr, off, len #) s0 -> case len of
+        0# -> (# s0, (# | (# (# (# #) | #), off, len #) #) #)
+        _ -> (# s0, (# | (# (# | indexCharArray# arr off #), off +# 1#, len -# 1# #) #) #)
+    )
+
+skipDigitsAsciiLoop ::
+  Bytes -> -- Chunk
+  (# Int#, Int# #)
+skipDigitsAsciiLoop !c =
+  if length c > 0
+    then
+      let w = indexLatinCharArray (array c) (offset c)
+       in if w >= '0' && w <= '9'
+            then skipDigitsAsciiLoop (Bytes.unsafeDrop 1 c)
+            else (# unI (offset c), unI (length c) #)
+    else (# unI (offset c), unI (length c) #)
+
+skipDigitsAscii1LoopStart ::
+  e ->
+  Bytes -> -- chunk
+  Result# e ()
+skipDigitsAscii1LoopStart e !c =
+  if length c > 0
+    then
+      let w = indexLatinCharArray (array c) (offset c)
+       in if w >= '0' && w <= '9'
+            then upcastUnitSuccess (skipDigitsAsciiLoop (Bytes.unsafeDrop 1 c))
+            else (# e | #)
+    else (# e | #)
+
+{- | 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
+
+{- | Skip the characters @0-9@ until a non-digit is encountered.
+This parser does not fail.
+-}
+skipDigits :: Parser e s ()
+skipDigits = uneffectful# $ \c ->
+  upcastUnitSuccess (skipDigitsAsciiLoop c)
+
+unI :: Int -> Int#
+{-# INLINE unI #-}
+unI (I# w) = w
+
+{- | 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
+
+skipLoop ::
+  Char -> -- byte to match
+  Bytes -> -- Chunk
+  (# Int#, Int# #)
+skipLoop !w !c =
+  if length c > 0
+    then
+      if indexLatinCharArray (array c) (offset c) == w
+        then skipLoop w (Bytes.unsafeDrop 1 c)
+        else (# unI (offset c), unI (length c) #)
+    else (# unI (offset c), unI (length c) #)
+
+skipLoop1Start ::
+  e ->
+  Char -> -- byte to match
+  Bytes -> -- chunk
+  Result# e ()
+skipLoop1Start e !w !chunk0 =
+  if length chunk0 > 0
+    then
+      if indexLatinCharArray (array chunk0) (offset chunk0) == w
+        then upcastUnitSuccess (skipLoop w (Bytes.unsafeDrop 1 chunk0))
+        else (# e | #)
+    else (# e | #)
+
+{- | Parse a decimal-encoded 8-bit word. If the number is larger
+than 255, this parser fails.
+-}
+decWord8 :: e -> Parser e s Word8
+decWord8 e =
+  Parser
+    ( \chunk0 s0 -> case decSmallWordStart e 256 (boxBytes chunk0) s0 of
+        (# s1, r #) -> (# s1, upcastWord8Result r #)
+    )
+
+{- | Parse a hexadecimal-encoded 8-bit word. If the number is larger
+than 255, this parser fails. This allows leading zeroes and is
+insensitive to case. For example, @00A@, @0a@ and @A@ would all
+be accepted as the same number.
+-}
+hexWord8 :: e -> Parser e s Word8
+hexWord8 e =
+  Parser
+    ( \chunk0 s0 -> case hexSmallWordStart e 256 (boxBytes chunk0) s0 of
+        (# s1, r #) -> (# s1, upcastWord8Result r #)
+    )
+
+{- | Parse a hexadecimal-encoded 16-bit word. If the number is larger
+than 65535, this parser fails. This allows leading zeroes and is
+insensitive to case. For example, @0100a@ and @100A@ would both
+be accepted as the same number.
+-}
+hexWord16 :: e -> Parser e s Word16
+hexWord16 e =
+  Parser
+    ( \chunk0 s0 -> case hexSmallWordStart e 65536 (boxBytes chunk0) s0 of
+        (# s1, r #) -> (# s1, upcastWord16Result r #)
+    )
+
+hexWord32 :: e -> Parser e s Word32
+hexWord32 e =
+  Parser
+    ( \chunk0 s0 -> case hexSmallWordStart e 4294967296 (boxBytes chunk0) s0 of
+        (# s1, r #) -> (# s1, upcastWord32Result r #)
+    )
+
+{- | Parse a decimal-encoded 16-bit word. If the number is larger
+than 65535, this parser fails.
+-}
+decWord16 :: e -> Parser e s Word16
+decWord16 e =
+  Parser
+    ( \chunk0 s0 -> case decSmallWordStart e 65536 (boxBytes chunk0) s0 of
+        (# s1, r #) -> (# s1, upcastWord16Result r #)
+    )
+
+{- | Parse a decimal-encoded 32-bit word. If the number is larger
+than 4294967295, this parser fails.
+-}
+decWord32 :: e -> Parser e s Word32
+-- This will not work on 32-bit platforms.
+decWord32 e =
+  Parser
+    ( \chunk0 s0 -> case decSmallWordStart e 4294967296 (boxBytes chunk0) s0 of
+        (# s1, r #) -> (# s1, upcastWord32Result r #)
+    )
+
+{- | Parse a decimal-encoded number. If the number is too large to be
+represented by a machine word, this fails with the provided
+error message. This accepts any number of leading zeroes.
+-}
+decWord :: e -> Parser e s Word
+decWord e =
+  Parser
+    ( \chunk0 s0 -> case decWordStart e (boxBytes chunk0) s0 of
+        (# s1, r #) -> (# s1, upcastWordResult r #)
+    )
+
+{- | Parse a decimal-encoded unsigned number. If the number is
+too large to be represented by a 64-bit word, this fails with
+the provided error message. This accepts any number of leading
+zeroes.
+-}
+decWord64 :: e -> Parser e s Word64
+decWord64 e =
+  Parser
+    ( \chunk0 s0 -> case decWordStart e (boxBytes chunk0) s0 of
+        (# s1, r #) -> (# s1, upcastWord64Result r #)
+    )
+
+hexSmallWordStart ::
+  e -> -- Error message
+  Word -> -- Upper Bound
+  Bytes -> -- Chunk
+  ST# s (Result# e Word#)
+hexSmallWordStart e !limit !chunk0 s0 =
+  if length chunk0 > 0
+    then case oneHexMaybe (PM.indexByteArray (array chunk0) (offset chunk0)) of
+      Nothing -> (# s0, (# e | #) #)
+      Just w -> (# s0, hexSmallWordMore e w limit (Bytes.unsafeDrop 1 chunk0) #)
+    else (# s0, (# e | #) #)
+
+decSmallWordStart ::
+  e -> -- Error message
+  Word -> -- Upper Bound
+  Bytes -> -- Chunk
+  ST# s (Result# e Word#)
+decSmallWordStart e !limit !chunk0 s0 =
+  if length chunk0 > 0
+    then
+      let !w =
+            fromIntegral @Word8 @Word
+              (PM.indexByteArray (array chunk0) (offset chunk0))
+              - 48
+       in if w < 10
+            then (# s0, decSmallWordMore e w limit (Bytes.unsafeDrop 1 chunk0) #)
+            else (# s0, (# e | #) #)
+    else (# s0, (# e | #) #)
+
+-- This will not inline since it is recursive, but worker
+-- wrapper will still happen.
+decWordMore ::
+  e -> -- Error message
+  Word -> -- Accumulator
+  Bytes -> -- Chunk
+  Result# e Word#
+decWordMore e !acc !chunk0 = case len of
+  0 -> (# | (# unW (fromIntegral acc), unI (offset chunk0), 0# #) #)
+  _ ->
+    let !w =
+          fromIntegral @Word8 @Word
+            (PM.indexByteArray (array chunk0) (offset chunk0))
+            - 48
+     in if w < 10
+          then
+            let (overflow, acc') = unsignedPushBase10 acc w
+             in if overflow
+                  then (# e | #)
+                  else decWordMore e acc' (Bytes.unsafeDrop 1 chunk0)
+          else (# | (# unW (fromIntegral acc), unI (offset chunk0), len# #) #)
+ where
+  !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 #) #)
+
+{- FOURMOLU_DISABLE -}
+-- This only works on 64-bit platforms.
+upcastWord64Result :: Result# e Word# -> Result# e Word64
+{-# 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 -}
+
+hexSmallWordMore ::
+  e -> -- Error message
+  Word -> -- Accumulator
+  Word -> -- Upper Bound
+  Bytes -> -- Chunk
+  Result# e Word#
+hexSmallWordMore e !acc !limit !chunk0 =
+  if length chunk0 > 0
+    then case oneHexMaybe (PM.indexByteArray (array chunk0) (offset chunk0)) of
+      Nothing -> (# | (# unW acc, unI (offset chunk0), unI (length chunk0) #) #)
+      Just w ->
+        let w' = acc * 16 + w
+         in if w' < limit
+              then hexSmallWordMore e w' limit (Bytes.unsafeDrop 1 chunk0)
+              else (# e | #)
+    else (# | (# unW acc, unI (offset chunk0), 0# #) #)
+
+decSmallWordMore ::
+  e -> -- Error message
+  Word -> -- Accumulator
+  Word -> -- Upper Bound
+  Bytes -> -- Chunk
+  Result# e Word#
+decSmallWordMore e !acc !limit !chunk0 =
+  if length chunk0 > 0
+    then
+      let !w =
+            fromIntegral @Word8 @Word
+              (PM.indexByteArray (array chunk0) (offset chunk0))
+              - 48
+       in if w < 10
+            then
+              let w' = acc * 10 + w
+               in if w' < limit
+                    then decSmallWordMore e w' limit (Bytes.unsafeDrop 1 chunk0)
+                    else (# e | #)
+            else (# | (# unW acc, unI (offset chunk0), unI (length chunk0) #) #)
+    else (# | (# unW acc, unI (offset chunk0), 0# #) #)
+
+unW :: Word -> Word#
+{-# INLINE unW #-}
+unW (W# w) = w
+
+decWordStart ::
+  e -> -- Error message
+  Bytes -> -- Chunk
+  ST# s (Result# e Word#)
+decWordStart e !chunk0 s0 =
+  if length chunk0 > 0
+    then
+      let !w =
+            fromIntegral @Word8 @Word
+              (PM.indexByteArray (array chunk0) (offset chunk0))
+              - 48
+       in if w < 10
+            then (# s0, decWordMore e w (Bytes.unsafeDrop 1 chunk0) #)
+            else (# s0, (# e | #) #)
+    else (# s0, (# e | #) #)
+
+{- FOURMOLU_DISABLE -}
+-- Precondition: the word is small enough
+upcastWord16Result :: Result# e Word# -> Result# e Word16
+{-# 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
+upcastWord32Result :: Result# e Word# -> Result# e Word32
+{-# 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
+upcastWord8Result :: Result# e Word# -> Result# e Word8
+{-# 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 -}
+
+{- | Parse a decimal-encoded number. If the number is too large to be
+represented by a machine integer, this fails with the provided
+error message. This rejects input with that is preceeded by plus
+or minus. Consequently, it does not parse negative numbers. Use
+'decStandardInt' or 'decSignedInt' for that purpose. On a 64-bit
+platform 'decWord' will successfully parse 9223372036854775808
+(i.e. @2 ^ 63@), but 'decUnsignedInt' will fail. This parser allows
+leading zeroes.
+-}
+decUnsignedInt :: e -> Parser e s Int
+decUnsignedInt e =
+  Parser
+    ( \chunk0 s0 -> case decPosIntStart e (boxBytes chunk0) s0 of
+        (# s1, r #) -> (# s1, upcastIntResult r #)
+    )
+
+-- | Variant of 'decUnsignedInt' with an unboxed result.
+decUnsignedInt# :: e -> Parser e s Int#
+decUnsignedInt# e =
+  Parser
+    (\chunk0 s0 -> decPosIntStart e (boxBytes chunk0) s0)
+
+{- | Parse a decimal-encoded number. If the number is too large to be
+represented by a machine integer, this fails with the provided
+error message. This allows the number to optionally be prefixed
+by plus or minus. If the sign prefix is not present, the number
+is interpreted as positive. This allows leading zeroes.
+-}
+decSignedInt :: e -> Parser e s Int
+decSignedInt e =
+  Parser
+    ( \chunk0 s0 -> case runParser (decSignedInt# e) chunk0 s0 of
+        (# s1, r #) -> (# s1, upcastIntResult r #)
+    )
+
+{- | Variant of 'decUnsignedInt' that lets the caller supply a leading
+digit. This is useful when parsing formats like JSON where integers with
+leading zeroes are considered invalid. The calling context must
+consume the first digit before calling this parser. Results are
+always positive numbers.
+-}
+decTrailingInt ::
+  -- | Error message
+  e ->
+  -- | Leading digit, should be between @0@ and @9@.
+  Int ->
+  Parser e s Int
+decTrailingInt e (I# w) =
+  Parser
+    ( \chunk0 s0 -> case runParser (decTrailingInt# e w) chunk0 s0 of
+        (# s1, r #) -> (# s1, upcastIntResult r #)
+    )
+
+decTrailingInt# ::
+  e -> -- Error message
+  Int# -> -- Leading digit, should be between @0@ and @9@.
+  Parser e s Int#
+decTrailingInt# e !w =
+  Parser (\chunk0 s0 -> (# s0, decPosIntMore e (W# (int2Word# w)) maxIntAsWord (boxBytes chunk0) #))
+
+maxIntAsWord :: Word
+maxIntAsWord = fromIntegral (maxBound :: Int)
+
+{- | Parse a decimal-encoded number. If the number is too large to be
+represented by a machine integer, this fails with the provided
+error message. This allows the number to optionally be prefixed
+by minus. If the minus prefix is not present, the number
+is interpreted as positive. The disallows a leading plus sign.
+For example, 'decStandardInt' rejects @+42@, but 'decSignedInt'
+allows it.
+-}
+decStandardInt :: e -> Parser e s Int
+decStandardInt e =
+  Parser
+    ( \chunk0 s0 -> case runParser (decStandardInt# e) chunk0 s0 of
+        (# s1, r #) -> (# s1, upcastIntResult r #)
+    )
+
+decSignedInt# :: e -> Parser e s Int#
+{-# NOINLINE decSignedInt# #-}
+decSignedInt# e =
+  any e `bindFromLiftedToInt` \c -> case c of
+    '+' ->
+      Parser -- plus sign
+        (\chunk0 s0 -> decPosIntStart e (boxBytes chunk0) s0)
+    '-' ->
+      Parser -- minus sign
+        (\chunk0 s0 -> decNegIntStart e (boxBytes chunk0) s0)
+    _ ->
+      Parser -- no sign, there should be a digit here
+        ( \chunk0 s0 ->
+            let !w = char2Word c - 48
+             in if w < 10
+                  then (# s0, decPosIntMore e w maxIntAsWord (boxBytes chunk0) #)
+                  else (# s0, (# e | #) #)
+        )
+
+-- This is the same as decSignedInt except that we disallow
+-- a leading plus sign.
+decStandardInt# :: e -> Parser e s Int#
+{-# NOINLINE decStandardInt# #-}
+decStandardInt# e =
+  any e `bindFromLiftedToInt` \c -> case c of
+    '-' ->
+      Parser -- minus sign
+        (\chunk0 s0 -> decNegIntStart e (boxBytes chunk0) s0)
+    _ ->
+      Parser -- no sign, there should be a digit here
+        ( \chunk0 s0 ->
+            let !w = char2Word c - 48
+             in if w < 10
+                  then (# s0, decPosIntMore e w maxIntAsWord (boxBytes chunk0) #)
+                  else (# s0, (# e | #) #)
+        )
+
+{- | Variant of 'decUnsignedInteger' that lets the caller supply a leading
+digit. This is useful when parsing formats like JSON where integers with
+leading zeroes are considered invalid. The calling context must
+consume the first digit before calling this parser. Results are
+always positive numbers.
+-}
+decTrailingInteger ::
+  -- | Leading digit, should be between @0@ and @9@.
+  Int ->
+  Parser e s Integer
+decTrailingInteger (I# w) =
+  Parser (\chunk0 s0 -> (# s0, (# | decIntegerChunks (I# w) 10 0 (boxBytes chunk0) #) #))
+
+{- | Parse a decimal-encoded positive integer of arbitrary
+size. This rejects input that begins with a plus or minus
+sign.
+-}
+decUnsignedInteger :: e -> Parser e s Integer
+decUnsignedInteger e =
+  Parser
+    (\chunk0 s0 -> decUnsignedIntegerStart e (boxBytes chunk0) s0)
+
+{- | Parse a decimal-encoded integer of arbitrary size.
+This accepts input that begins with a plus or minus sign.
+Input without a sign prefix is interpreted as positive.
+-}
+decSignedInteger :: e -> Parser e s Integer
+{-# NOINLINE decSignedInteger #-}
+decSignedInteger e =
+  any e >>= \c -> case c of
+    '+' -> do
+      decUnsignedInteger e
+    '-' -> do
+      x <- decUnsignedInteger e
+      pure $! negate x
+    _ ->
+      Parser -- no sign, there should be a digit here
+        ( \chunk0 s0 ->
+            let !w = char2Word c - 48
+             in if w < 10
+                  then
+                    let !r =
+                          decIntegerChunks
+                            (fromIntegral @Word @Int w)
+                            10
+                            0
+                            (boxBytes chunk0)
+                     in (# s0, (# | r #) #)
+                  else (# s0, (# e | #) #)
+        )
+
+decPosIntStart ::
+  e -> -- Error message
+  Bytes -> -- Chunk
+  ST# s (Result# e Int#)
+decPosIntStart e !chunk0 s0 =
+  if length chunk0 > 0
+    then
+      let !w =
+            fromIntegral @Word8 @Word
+              (PM.indexByteArray (array chunk0) (offset chunk0))
+              - 48
+       in if w < 10
+            then (# s0, decPosIntMore e w maxIntAsWord (Bytes.unsafeDrop 1 chunk0) #)
+            else (# s0, (# e | #) #)
+    else (# s0, (# e | #) #)
+
+decNegIntStart ::
+  e -> -- Error message
+  Bytes -> -- Chunk
+  ST# s (Result# e Int#)
+decNegIntStart e !chunk0 s0 =
+  if length chunk0 > 0
+    then
+      let !w =
+            fromIntegral @Word8 @Word
+              (PM.indexByteArray (array chunk0) (offset chunk0))
+              - 48
+       in if w < 10
+            then case decPosIntMore e w (maxIntAsWord + 1) (Bytes.unsafeDrop 1 chunk0) of
+              (# | (# x, y, z #) #) ->
+                (# s0, (# | (# (notI# x +# 1#), y, z #) #) #)
+              (# err | #) ->
+                (# s0, (# err | #) #)
+            else (# s0, (# e | #) #)
+    else (# s0, (# e | #) #)
+
+decUnsignedIntegerStart ::
+  e ->
+  Bytes ->
+  ST# s (Result# e Integer)
+decUnsignedIntegerStart e !chunk0 s0 =
+  if length chunk0 > 0
+    then
+      let !w = (PM.indexByteArray (array chunk0) (offset chunk0)) - 48
+       in if w < (10 :: Word8)
+            then
+              let !r =
+                    decIntegerChunks
+                      (fromIntegral @Word8 @Int w)
+                      10
+                      0
+                      (Bytes.unsafeDrop 1 chunk0)
+               in (# s0, (# | r #) #)
+            else (# s0, (# e | #) #)
+    else (# s0, (# e | #) #)
+
+-- This will not inline since it is recursive, but worker
+-- wrapper will still happen. Fails if the accumulator
+-- exceeds the upper bound.
+decPosIntMore ::
+  e -> -- Error message
+  Word -> -- Accumulator, precondition: less than or equal to bound
+  Word -> -- Inclusive Upper Bound, either (2^63 - 1) or 2^63
+  Bytes -> -- Chunk
+  Result# e Int#
+decPosIntMore e !acc !upper !chunk0 =
+  if len > 0
+    then
+      let !w =
+            fromIntegral @Word8 @Word
+              (PM.indexByteArray (array chunk0) (offset chunk0))
+              - 48
+       in if w < 10
+            then
+              let (overflow, acc') = positivePushBase10 acc w upper
+               in if overflow
+                    then (# e | #)
+                    else decPosIntMore e acc' upper (Bytes.unsafeDrop 1 chunk0)
+            else (# | (# unI (fromIntegral acc), unI (offset chunk0), len# #) #)
+    else (# | (# unI (fromIntegral acc), unI (offset chunk0), 0# #) #)
+ where
+  !len@(I# len#) = length chunk0
+
+-- This will not inline since it is recursive, but worker
+-- wrapper will still happen. When the accumulator
+-- exceeds the size of a machine integer, this pushes the
+-- accumulated machine int and the shift amount onto the
+-- stack.
+-- We are intentionally lazy in the accumulator. There is
+-- no need to force this on every iteration. We do however,
+-- force it preemptively every time it changes.
+-- Because of how we track overflow, we are able to use the
+-- same function for both positive and negative numbers.
+decIntegerChunks ::
+  Int -> -- Chunk accumulator (e.g. 236)
+  Int -> -- Chunk base-ten bound (e.g. 1000)
+  Integer -> -- Accumulator
+  Bytes -> -- Chunk
+  (# Integer, Int#, Int# #)
+decIntegerChunks !nAcc !eAcc acc !chunk0 =
+  if len > 0
+    then
+      let !w =
+            fromIntegral @Word8 @Word
+              (PM.indexByteArray (array chunk0) (offset chunk0))
+              - 48
+       in if w < 10
+            then
+              let !eAcc' = eAcc * 10
+               in if eAcc' >= eAcc
+                    then
+                      decIntegerChunks
+                        (nAcc * 10 + fromIntegral @Word @Int w)
+                        eAcc'
+                        acc
+                        (Bytes.unsafeDrop 1 chunk0)
+                    else -- In this case, notice that we deliberately
+                    -- unconsume the digit that would have caused
+                    -- an overflow.
+
+                      let !r =
+                            (acc * fromIntegral @Int @Integer eAcc)
+                              + (fromIntegral @Int @Integer nAcc)
+                       in decIntegerChunks 0 1 r chunk0
+            else
+              let !r =
+                    (acc * fromIntegral @Int @Integer eAcc)
+                      + (fromIntegral @Int @Integer nAcc)
+               in (# r, unI (offset chunk0), len# #)
+    else
+      let !r =
+            (acc * fromIntegral @Int @Integer eAcc)
+              + (fromIntegral @Int @Integer nAcc)
+       in (# r, unI (offset chunk0), 0# #)
+ where
+  !len@(I# len#) = length chunk0
+
+upcastIntResult :: Result# e Int# -> Result# e Int
+upcastIntResult (# e | #) = (# e | #)
+upcastIntResult (# | (# a, b, c #) #) = (# | (# I# a, b, c #) #)
+
+char2Word :: Char -> Word
+char2Word = fromIntegral . ord
+
+{- | Take characters until the specified character is encountered.
+Consumes the matched character as well. Fails if the character
+is not present.  Visually, the cursor advancement and resulting
+@Bytes@ for @takeTrailedBy \'D\'@ look like this:
+
+>  A B C D E F | input
+> |->->->-|    | cursor
+> {\-*-*-\}      | result bytes
+-}
+takeTrailedBy :: e -> Char -> Parser e s Bytes
+takeTrailedBy e !w = do
+  !start <- cursor
+  skipTrailedBy e w
+  !end <- cursor
+  !arr <- expose
+  pure (Bytes arr start (end - (start + 1)))
+
+{- | Skip all characters until the terminator is encountered
+and then consume the matching character as well. Visually,
+@skipTrailedBy \'C\'@ advances the cursor like this:
+
+>  A Z B Y C X C W
+> |->->->->-|
+
+This fails if it reaches the end of input without encountering
+the character.
+-}
+skipTrailedBy :: e -> Char -> Parser e s ()
+skipTrailedBy e !w = uneffectful# $ \c ->
+  skipUntilConsumeLoop e w c
+
+{- | Skip all characters until the terminator is encountered.
+This does not consume the terminator. Visually, @skipUntil \'C\'@
+advances the cursor like this:
+
+>  A Z B Y C X C W
+> |->->->-|
+
+This succeeds if it reaches the end of the input without
+encountering the terminator. It never fails.
+-}
+skipUntil :: Char -> Parser e s ()
+skipUntil !w = uneffectful# $ \c -> skipUntilLoop w c
+
+skipUntilLoop ::
+  Char -> -- byte to match
+  Bytes -> -- Chunk
+  Result# e ()
+skipUntilLoop !w !c = case length c of
+  0 -> (# | (# (), unI (offset c), 0# #) #)
+  _ ->
+    if indexLatinCharArray (array c) (offset c) /= w
+      then skipUntilLoop w (Bytes.unsafeDrop 1 c)
+      else (# | (# (), unI (offset c), unI (length c) #) #)
+
+skipUntilConsumeLoop ::
+  e -> -- Error message
+  Char -> -- byte to match
+  Bytes -> -- Chunk
+  Result# e ()
+skipUntilConsumeLoop e !w !c = case length c of
+  0 -> (# e | #)
+  _ ->
+    if indexLatinCharArray (array c) (offset c) /= w
+      then skipUntilConsumeLoop e w (Bytes.unsafeDrop 1 c)
+      else (# | (# (), unI (offset c + 1), unI (length c - 1) #) #)
+
+{- FOURMOLU_DISABLE -}
+-- | Parse exactly eight ASCII-encoded characters, interpreting them as the
+-- hexadecimal encoding of a 32-bit number. Note that this rejects a sequence
+-- such as @BC5A9@, requiring @000BC5A9@ instead. This is insensitive to case.
+hexFixedWord32 :: e -> Parser e s Word32
+{-# inline hexFixedWord32 #-}
+hexFixedWord32 e = Parser
+  (\x s0 -> case runParser (hexFixedWord32# e) x s0 of
+    (# 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 -}
+
+hexFixedWord32# :: e -> Parser e s Word#
+{-# NOINLINE hexFixedWord32# #-}
+hexFixedWord32# e = uneffectfulWord# $ \chunk ->
+  if length chunk >= 8
+    then
+      let !w0@(W# n0) = oneHex $ PM.indexByteArray (array chunk) (offset chunk)
+          !w1@(W# n1) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 1)
+          !w2@(W# n2) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 2)
+          !w3@(W# n3) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 3)
+          !w4@(W# n4) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 4)
+          !w5@(W# n5) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 5)
+          !w6@(W# n6) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 6)
+          !w7@(W# n7) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 7)
+       in if
+            | w0 .|. w1 .|. w2 .|. w3 .|. w4 .|. w5 .|. w6 .|. w7 /= maxBound ->
+                (#
+                  | (#
+                      (n0 `Exts.timesWord#` 268435456##)
+                        `Exts.plusWord#` (n1 `Exts.timesWord#` 16777216##)
+                        `Exts.plusWord#` (n2 `Exts.timesWord#` 1048576##)
+                        `Exts.plusWord#` (n3 `Exts.timesWord#` 65536##)
+                        `Exts.plusWord#` (n4 `Exts.timesWord#` 4096##)
+                        `Exts.plusWord#` (n5 `Exts.timesWord#` 256##)
+                        `Exts.plusWord#` (n6 `Exts.timesWord#` 16##)
+                        `Exts.plusWord#` n7
+                      , unI (offset chunk) +# 8#
+                      , unI (length chunk) -# 8#
+                    #)
+                #)
+            | otherwise -> (# e | #)
+    else (# e | #)
+
+{- FOURMOLU_DISABLE -}
+-- | Parse exactly 16 ASCII-encoded characters, interpreting them as the
+-- hexadecimal encoding of a 64-bit number. Note that this rejects a sequence
+-- such as @BC5A9@, requiring @00000000000BC5A9@ instead. This is insensitive
+-- to case.
+hexFixedWord64 :: e -> Parser e s Word64
+{-# inline hexFixedWord64 #-}
+hexFixedWord64 e = Parser
+  (\x s0 -> case runParser (hexFixedWord64# e) x s0 of
+    (# 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 -}
+
+hexFixedWord128 :: e -> Parser e s Word128
+hexFixedWord128 e =
+  Word128
+    <$> hexFixedWord64 e
+    <*> hexFixedWord64 e
+
+hexFixedWord256 :: e -> Parser e s Word256
+hexFixedWord256 e =
+  Word256
+    <$> hexFixedWord64 e
+    <*> hexFixedWord64 e
+    <*> hexFixedWord64 e
+    <*> hexFixedWord64 e
+
+hexFixedWord64# :: e -> Parser e s Word#
+{-# NOINLINE hexFixedWord64# #-}
+hexFixedWord64# e = uneffectfulWord# $ \chunk ->
+  if length chunk >= 16
+    then
+      let go !off !len !acc = case len of
+            0 -> case acc of
+              W# r ->
+                (#
+                  | (#
+                      r
+                      , unI off
+                      , unI (length chunk) -# 16#
+                    #)
+                #)
+            _ -> case oneHexMaybe (PM.indexByteArray (array chunk) off) of
+              Nothing -> (# e | #)
+              Just w -> go (off + 1) (len - 1) ((acc * 16) + w)
+       in go (offset chunk) (16 :: Int) (0 :: Word)
+    else (# e | #)
+
+{- FOURMOLU_DISABLE -}
+-- | Parse exactly four ASCII-encoded characters, interpreting
+-- them as the hexadecimal encoding of a 16-bit number. Note that
+-- this rejects a sequence such as @5A9@, requiring @05A9@ instead.
+-- This is insensitive to case. This is particularly useful when
+-- parsing escape sequences in C or JSON, which allow encoding
+-- characters in the Basic Multilingual Plane as @\\uhhhh@.
+hexFixedWord16 :: e -> Parser e s Word16
+{-# inline hexFixedWord16 #-}
+hexFixedWord16 e = Parser
+  (\x s0 -> case runParser (hexFixedWord16# e) x s0 of
+    (# 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 #) #) #)
+  )
+
+hexFixedWord16# :: e -> Parser e s Word#
+{-# noinline hexFixedWord16# #-}
+hexFixedWord16# e = uneffectfulWord# $ \chunk -> if length chunk >= 4
+  then
+    let !w0@(W# n0) = oneHex $ PM.indexByteArray (array chunk) (offset chunk)
+        !w1@(W# n1) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 1)
+        !w2@(W# n2) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 2)
+        !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#`
+                   n3
+                ,  unI (offset chunk) +# 4#
+                ,  unI (length chunk) -# 4# #) #)
+           | otherwise -> (# e | #)
+  else (# e | #)
+
+-- | Parse exactly two ASCII-encoded characters, interpretting
+-- them as the hexadecimal encoding of a 8-bit number. Note that
+-- this rejects a sequence such as @A@, requiring @0A@ instead.
+-- This is insensitive to case.
+hexFixedWord8 :: e -> Parser e s Word8
+{-# inline hexFixedWord8 #-}
+hexFixedWord8 e = Parser
+  (\x s0 -> case runParser (hexFixedWord8# e) x s0 of
+    (# 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 -}
+
+hexFixedWord8# :: e -> Parser e s Word#
+{-# NOINLINE hexFixedWord8# #-}
+hexFixedWord8# e = uneffectfulWord# $ \chunk ->
+  if length chunk >= 2
+    then
+      let !w0@(W# n0) = oneHex $ PM.indexByteArray (array chunk) (offset chunk)
+          !w1@(W# n1) = oneHex $ PM.indexByteArray (array chunk) (offset chunk + 1)
+       in if
+            | w0 .|. w1 /= maxBound ->
+                (#
+                  | (#
+                      (n0 `Exts.timesWord#` 16##)
+                        `Exts.plusWord#` n1
+                      , unI (offset chunk) +# 2#
+                      , unI (length chunk) -# 2#
+                    #)
+                #)
+            | otherwise -> (# e | #)
+    else (# e | #)
+
+{- | Consume a single character that is the lowercase hexadecimal
+encoding of a 4-bit word. Fails if the character is not in the class
+@[a-f0-9]@.
+-}
+hexNibbleLower :: e -> Parser e s Word
+hexNibbleLower e = uneffectful $ \chunk -> case length chunk of
+  0 -> Failure e
+  _ ->
+    let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8
+     in 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 -> Failure e
+  _ ->
+    let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8
+     in 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
+the character if it is not in the class @[a-f0-9]@. The parser
+never fails.
+-}
+tryHexNibbleLower :: Parser e s (Maybe Word)
+tryHexNibbleLower = unfailing $ \chunk -> case length chunk of
+  0 -> InternalStep Nothing (offset chunk) (length chunk)
+  _ ->
+    let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8
+     in if
+          | w >= 48 && w < 58 -> InternalStep (Just (fromIntegral w - 48)) (offset chunk + 1) (length chunk - 1)
+          | w >= 97 && w < 103 -> InternalStep (Just (fromIntegral w - 87)) (offset chunk + 1) (length chunk - 1)
+          | otherwise -> InternalStep Nothing (offset chunk) (length chunk)
+
+{- | Consume a single character that is the case-insensitive hexadecimal
+encoding of a 4-bit word. Returns @Nothing@ without consuming
+the character if it is not in the class @[a-fA-F0-9]@. This parser
+never fails.
+-}
+tryHexNibble :: Parser e s (Maybe Word)
+tryHexNibble = unfailing $ \chunk -> case length chunk of
+  0 -> InternalStep Nothing (offset chunk) (length chunk)
+  _ ->
+    let w = PM.indexByteArray (array chunk) (offset chunk) :: Word8
+     in if
+          | w >= 48 && w < 58 -> InternalStep (Just (fromIntegral w - 48)) (offset chunk + 1) (length chunk - 1)
+          | w >= 65 && w < 71 -> InternalStep (Just (fromIntegral w - 55)) (offset chunk + 1) (length chunk - 1)
+          | w >= 97 && w < 103 -> InternalStep (Just (fromIntegral w - 87)) (offset chunk + 1) (length chunk - 1)
+          | otherwise -> InternalStep Nothing (offset chunk) (length chunk)
+
+-- 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)
+  | w >= 97 && w < 103 = (fromIntegral w - 87)
+  | otherwise = maxBound
+
+oneHexMaybe :: Word8 -> Maybe Word
+{-# INLINE oneHexMaybe #-}
+oneHexMaybe w
+  | w >= 48 && w < 58 = Just (fromIntegral w - 48)
+  | w >= 65 && w < 71 = Just (fromIntegral w - 55)
+  | w >= 97 && w < 103 = Just (fromIntegral w - 87)
+  | otherwise = Nothing
+
+uneffectfulWord# :: (Bytes -> Result# e Word#) -> Parser e s Word#
+{-# INLINE uneffectfulWord# #-}
+uneffectfulWord# f =
+  Parser
+    (\b s0 -> (# s0, (f (boxBytes b)) #))
+
+-- Precondition: the arguments are non-negative. Boolean is
+-- true when overflow happens. Performs: a * 10 + b
+-- 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
+      !cb = int2Word# (gtWord# r1 upper)
+      !cc = int2Word# (ltWord# r1 0##)
+      !c = ca `or#` cb `or#` cc
+   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
+      !cb = int2Word# (ltWord# r1 r0)
+      !c = ca `or#` cb
+   in (case c of 0## -> False; _ -> True, W# r1)
+
+-- | Skip while the predicate is matched. This is always inlined.
+skipWhile :: (Char -> Bool) -> Parser e s ()
+{-# INLINE skipWhile #-}
+skipWhile f = go
+ where
+  go =
+    isEndOfInput >>= \case
+      True -> pure ()
+      False -> do
+        w <- anyUnsafe
+        if f w
+          then go
+          else unconsume 1
+
+-- Interpret the next byte as an Latin1-encoded character.
+-- Does not check to see if any characters are left. This
+-- is not exported.
+anyUnsafe :: Parser e s Char
+{-# INLINE anyUnsafe #-}
+anyUnsafe = uneffectful $ \chunk ->
+  let w = indexCharArray (array chunk) (offset chunk) :: Char
+   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
diff --git a/src/Data/Bytes/Parser/Leb128.hs b/src/Data/Bytes/Parser/Leb128.hs
--- a/src/Data/Bytes/Parser/Leb128.hs
+++ b/src/Data/Bytes/Parser/Leb128.hs
@@ -1,66 +1,73 @@
-{-# language BangPatterns #-}
-{-# language BinaryLiterals #-}
-{-# language TypeApplications #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE BinaryLiterals #-}
+{-# LANGUAGE TypeApplications #-}
 
--- | Parse numbers that have been encoded with <https://en.wikipedia.org/wiki/LEB128 LEB-128>.
--- LEB-128 allows arbitrarily large numbers to be encoded. Parsers in this
--- module will fail if the number they attempt to parse is outside the
--- range of what their target type can handle. The parsers for signed
--- numbers assume that the numbers have been
--- <https://developers.google.com/protocol-buffers/docs/encoding zigzig encoded>.
+{- | Parse numbers that have been encoded with <https://en.wikipedia.org/wiki/LEB128 LEB-128>.
+LEB-128 allows arbitrarily large numbers to be encoded. Parsers in this
+module will fail if the number they attempt to parse is outside the
+range of what their target type can handle. The parsers for signed
+numbers assume that the numbers have been
+<https://developers.google.com/protocol-buffers/docs/encoding zigzig encoded>.
+-}
 module Data.Bytes.Parser.Leb128
   ( -- * Unsigned
     word16
   , word32
   , word64
+
     -- * Signed (Zig-zag)
   , int16
   , int32
   , int64
   ) where
 
-import Data.Bits (testBit,(.&.),unsafeShiftR,xor,complement)
-import Data.Bits (unsafeShiftL,(.|.))
+import Data.Bits (complement, testBit, unsafeShiftL, unsafeShiftR, xor, (.&.), (.|.))
 import Data.Bytes.Parser (Parser)
-import Data.Int (Int16,Int32,Int64)
-import Data.Word (Word8,Word16,Word32,Word64)
+import Data.Int (Int16, Int32, Int64)
+import Data.Word (Word16, Word32, Word64, Word8)
 
 import qualified Data.Bytes.Parser as P
 
--- | Parse a LEB-128-encoded number. If the number is larger
--- than @0xFFFF@, fails with the provided error.
+{- | Parse a LEB-128-encoded number. If the number is larger
+than @0xFFFF@, fails with the provided error.
+-}
 word16 :: e -> Parser e s Word16
 word16 e = do
   w <- stepBoundedWord e 16 0 0
   pure (fromIntegral @Word64 @Word16 w)
 
--- | Parse a LEB-128-encoded number. If the number is larger
--- than @0xFFFFFFFF@, fails with the provided error.
+{- | Parse a LEB-128-encoded number. If the number is larger
+than @0xFFFFFFFF@, fails with the provided error.
+-}
 word32 :: e -> Parser e s Word32
 word32 e = do
   w <- stepBoundedWord e 32 0 0
   pure (fromIntegral @Word64 @Word32 w)
 
--- | Parse a LEB-128-encoded number. If the number is larger
--- than @0xFFFFFFFFFFFFFFFF@, fails with the provided error.
+{- | Parse a LEB-128-encoded number. If the number is larger
+than @0xFFFFFFFFFFFFFFFF@, fails with the provided error.
+-}
 word64 :: e -> Parser e s Word64
 word64 e = stepBoundedWord e 64 0 0
 
--- | Parse a LEB-128-zigzag-encoded signed number. If the encoded
--- number is outside the range @[-32768,32767]@, this fails with
--- the provided error.
+{- | Parse a LEB-128-zigzag-encoded signed number. If the encoded
+number is outside the range @[-32768,32767]@, this fails with
+the provided error.
+-}
 int16 :: e -> Parser e s Int16
 int16 = fmap zigzagDecode16 . word16
 
--- | Parse a LEB-128-zigzag-encoded signed number. If the encoded
--- number is outside the range @[-2147483648,2147483647]@, this
--- fails with the provided error.
+{- | Parse a LEB-128-zigzag-encoded signed number. If the encoded
+number is outside the range @[-2147483648,2147483647]@, this
+fails with the provided error.
+-}
 int32 :: e -> Parser e s Int32
 int32 = fmap zigzagDecode32 . word32
 
--- | Parse a LEB-128-zigzag-encoded signed number. If the encoded
--- number is outside the range @[-9223372036854775808,9223372036854775807]@,
--- this fails with the provided error.
+{- | Parse a LEB-128-zigzag-encoded signed number. If the encoded
+number is outside the range @[-9223372036854775808,9223372036854775807]@,
+this fails with the provided error.
+-}
 int64 :: e -> Parser e s Int64
 int64 = fmap zigzagDecode64 . word64
 
@@ -72,16 +79,19 @@
 stepBoundedWord e !bitLimit !acc0 !accShift = do
   raw <- P.any e
   let number = raw .&. 0x7F
-      acc1 = acc0 .|.
-        unsafeShiftL (fromIntegral @Word8 @Word64 number) accShift
+      acc1 =
+        acc0
+          .|. unsafeShiftL (fromIntegral @Word8 @Word64 number) accShift
       accShift' = accShift + 7
   if accShift' <= bitLimit
-    then if testBit raw 7
-      then stepBoundedWord e bitLimit acc1 accShift'
-      else pure acc1
-    else if fromIntegral @Word8 @Word raw < twoExp (bitLimit - accShift)
-      then pure acc1 -- TODO: no need to mask upper bit in number
-      else P.fail e
+    then
+      if testBit raw 7
+        then stepBoundedWord e bitLimit acc1 accShift'
+        else pure acc1
+    else
+      if fromIntegral @Word8 @Word raw < twoExp (bitLimit - accShift)
+        then pure acc1 -- TODO: no need to mask upper bit in number
+        else P.fail e
 
 twoExp :: Int -> Word
 twoExp x = unsafeShiftL 1 x
diff --git a/src/Data/Bytes/Parser/LittleEndian.hs b/src/Data/Bytes/Parser/LittleEndian.hs
--- a/src/Data/Bytes/Parser/LittleEndian.hs
+++ b/src/Data/Bytes/Parser/LittleEndian.hs
@@ -1,24 +1,19 @@
-{-# language BangPatterns #-}
-{-# language BinaryLiterals #-}
-{-# language DataKinds #-}
-{-# language DeriveFunctor #-}
-{-# language DerivingStrategies #-}
-{-# language GADTSyntax #-}
-{-# language KindSignatures #-}
-{-# language LambdaCase #-}
-{-# language MagicHash #-}
-{-# language MultiWayIf #-}
-{-# language PolyKinds #-}
-{-# language RankNTypes #-}
-{-# language ScopedTypeVariables #-}
-{-# language StandaloneDeriving #-}
-{-# language TypeApplications #-}
-{-# language UnboxedSums #-}
-{-# language UnboxedTuples #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE BinaryLiterals #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE GADTSyntax #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE UnboxedSums #-}
 
 -- | Little-endian fixed-width numbers.
 module Data.Bytes.Parser.LittleEndian
   ( -- * One
+
     -- ** Unsigned
     word8
   , word16
@@ -26,36 +21,40 @@
   , word64
   , word128
   , word256
+
     -- ** Signed
   , int8
   , int16
   , int32
   , int64
+
     -- * Many
+
     -- ** Unsigned
   , word16Array
   , word32Array
   , word64Array
   , word128Array
   , word256Array
+
     -- ** Unsigned
   , int64Array
   ) where
 
-import Prelude hiding (length,any,fail,takeWhile)
+import Prelude hiding (any, fail, length, takeWhile)
 
+#if MIN_VERSION_base(4,18,0)
+#else
 import Control.Applicative (liftA2)
-import Data.Bits ((.|.),unsafeShiftL)
-import Data.Primitive (ByteArray(..),PrimArray(..))
-import Data.Bytes.Types (Bytes(..))
-import Data.Bytes.Parser.Internal (Parser,uneffectful)
-import Data.Bytes.Parser.Internal (Result(..))
-import Data.Bytes.Parser.Internal (swapArray16,swapArray32)
-import Data.Bytes.Parser.Internal (swapArray64,swapArray128,swapArray256)
-import Data.Word (Word8,Word16,Word32,Word64)
-import Data.Int (Int8,Int16,Int32,Int64)
-import Data.WideWord (Word128(Word128),Word256(Word256))
-import GHC.ByteOrder (ByteOrder(LittleEndian,BigEndian),targetByteOrder)
+#endif
+import Data.Bits (unsafeShiftL, (.|.))
+import Data.Bytes.Parser.Internal (Parser, Result (..), swapArray128, swapArray16, swapArray256, swapArray32, swapArray64, uneffectful)
+import Data.Bytes.Types (Bytes (..))
+import Data.Int (Int16, Int32, Int64, Int8)
+import Data.Primitive (ByteArray (..), PrimArray (..))
+import Data.WideWord (Word128 (Word128), Word256 (Word256))
+import Data.Word (Word16, Word32, Word64, Word8)
+import GHC.ByteOrder (ByteOrder (BigEndian, LittleEndian), targetByteOrder)
 
 import qualified Data.Bytes as Bytes
 import qualified Data.Bytes.Parser as P
@@ -65,14 +64,18 @@
 word8 :: e -> Parser e s Word8
 word8 = P.any
 
--- | Array of little-endian unsigned 16-bit words. If the host is
--- little-endian, the implementation is optimized to simply @memcpy@
--- bytes into the result array. The result array always has elements
--- in native-endian byte order.
+{- | Array of little-endian unsigned 16-bit words. If the host is
+little-endian, the implementation is optimized to simply @memcpy@
+bytes into the result array. The result array always has elements
+in native-endian byte order.
+-}
 word16Array ::
-     e -- ^ Error message if not enough bytes are present
-  -> Int -- ^ Number of little-endian 16-bit words to expect
-  -> Parser e s (PrimArray Word16) -- ^ Native-endian elements
+  -- | Error message if not enough bytes are present
+  e ->
+  -- | Number of little-endian 16-bit words to expect
+  Int ->
+  -- | Native-endian elements
+  Parser e s (PrimArray Word16)
 word16Array e !n = case targetByteOrder of
   LittleEndian -> fmap (asWord16s . Bytes.toByteArrayClone) (P.take e (n * 2))
   BigEndian -> do
@@ -82,9 +85,12 @@
 
 -- | Parse an array of little-endian unsigned 32-bit words.
 word32Array ::
-     e -- ^ Error message if not enough bytes are present
-  -> Int -- ^ Number of little-endian 32-bit words to consume
-  -> Parser e s (PrimArray Word32) -- ^ Native-endian elements
+  -- | Error message if not enough bytes are present
+  e ->
+  -- | Number of little-endian 32-bit words to consume
+  Int ->
+  -- | Native-endian elements
+  Parser e s (PrimArray Word32)
 word32Array e !n = case targetByteOrder of
   LittleEndian -> fmap (asWord32s . Bytes.toByteArrayClone) (P.take e (n * 4))
   BigEndian -> do
@@ -94,9 +100,12 @@
 
 -- | Parse an array of little-endian unsigned 64-bit words.
 word64Array ::
-     e -- ^ Error message if not enough bytes are present
-  -> Int -- ^ Number of little-endian 64-bit words to consume
-  -> Parser e s (PrimArray Word64) -- ^ Native-endian elements
+  -- | Error message if not enough bytes are present
+  e ->
+  -- | Number of little-endian 64-bit words to consume
+  Int ->
+  -- | Native-endian elements
+  Parser e s (PrimArray Word64)
 word64Array e !n = case targetByteOrder of
   LittleEndian -> fmap (asWord64s . Bytes.toByteArrayClone) (P.take e (n * 8))
   BigEndian -> do
@@ -106,9 +115,12 @@
 
 -- | Parse an array of little-endian unsigned 128-bit words.
 word128Array ::
-     e -- ^ Error message if not enough bytes are present
-  -> Int -- ^ Number of little-endian 128-bit words to consume
-  -> Parser e s (PrimArray Word128) -- ^ Native-endian elements
+  -- | Error message if not enough bytes are present
+  e ->
+  -- | Number of little-endian 128-bit words to consume
+  Int ->
+  -- | Native-endian elements
+  Parser e s (PrimArray Word128)
 word128Array e !n = case targetByteOrder of
   LittleEndian -> fmap (asWord128s . Bytes.toByteArrayClone) (P.take e (n * 16))
   BigEndian -> do
@@ -118,9 +130,12 @@
 
 -- | Parse an array of little-endian unsigned 256-bit words.
 word256Array ::
-     e -- ^ Error message if not enough bytes are present
-  -> Int -- ^ Number of little-endian 256-bit words to consume
-  -> Parser e s (PrimArray Word256) -- ^ Native-endian elements
+  -- | Error message if not enough bytes are present
+  e ->
+  -- | Number of little-endian 256-bit words to consume
+  Int ->
+  -- | Native-endian elements
+  Parser e s (PrimArray Word256)
 word256Array e !n = case targetByteOrder of
   LittleEndian -> fmap (asWord256s . Bytes.toByteArrayClone) (P.take e (n * 32))
   BigEndian -> do
@@ -130,9 +145,12 @@
 
 -- | Parse an array of little-endian signed 64-bit words.
 int64Array ::
-     e -- ^ Error message if not enough bytes are present
-  -> Int -- ^ Number of little-endian 64-bit words to expect
-  -> Parser e s (PrimArray Int64) -- ^ Native-endian elements
+  -- | Error message if not enough bytes are present
+  e ->
+  -- | Number of little-endian 64-bit words to expect
+  Int ->
+  -- | Native-endian elements
+  Parser e s (PrimArray Int64)
 int64Array e !n = do
   PrimArray x <- word64Array e n
   pure (PrimArray x)
@@ -154,58 +172,64 @@
 
 -- | Unsigned 16-bit word.
 word16 :: e -> Parser e s Word16
-word16 e = uneffectful $ \chunk -> if length chunk >= 2
-  then
-    let wa = PM.indexByteArray (array chunk) (offset chunk) :: Word8
-        wb = PM.indexByteArray (array chunk) (offset chunk + 1) :: Word8
-     in Success
-          (fromIntegral @Word @Word16 (unsafeShiftL (fromIntegral wb) 8 .|. fromIntegral wa))
-          (offset chunk + 2) (length chunk - 2)
-  else Failure e
+word16 e = uneffectful $ \chunk ->
+  if length chunk >= 2
+    then
+      let wa = PM.indexByteArray (array chunk) (offset chunk) :: Word8
+          wb = PM.indexByteArray (array chunk) (offset chunk + 1) :: Word8
+       in Success
+            (fromIntegral @Word @Word16 (unsafeShiftL (fromIntegral wb) 8 .|. fromIntegral wa))
+            (offset chunk + 2)
+            (length chunk - 2)
+    else Failure e
 
 -- | Unsigned 32-bit word.
 word32 :: e -> Parser e s Word32
-word32 e = uneffectful $ \chunk -> if length chunk >= 4
-  then
-    let wa = PM.indexByteArray (array chunk) (offset chunk) :: Word8
-        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 Success
-          (fromIntegral @Word @Word32
-            ( unsafeShiftL (fromIntegral wd) 24 .|.
-              unsafeShiftL (fromIntegral wc) 16 .|.
-              unsafeShiftL (fromIntegral wb) 8 .|.
-              fromIntegral wa
+word32 e = uneffectful $ \chunk ->
+  if length chunk >= 4
+    then
+      let wa = PM.indexByteArray (array chunk) (offset chunk) :: Word8
+          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 Success
+            ( fromIntegral @Word @Word32
+                ( unsafeShiftL (fromIntegral wd) 24
+                    .|. unsafeShiftL (fromIntegral wc) 16
+                    .|. unsafeShiftL (fromIntegral wb) 8
+                    .|. fromIntegral wa
+                )
             )
-          )
-          (offset chunk + 4) (length chunk - 4)
-  else Failure e
+            (offset chunk + 4)
+            (length chunk - 4)
+    else Failure e
 
 -- | Unsigned 64-bit word.
 word64 :: e -> Parser e s Word64
-word64 e = uneffectful $ \chunk -> if length chunk >= 8
-  then
-    let wa = PM.indexByteArray (array chunk) (offset chunk) :: Word8
-        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
-        we = PM.indexByteArray (array chunk) (offset chunk + 4) :: Word8
-        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 Success
-          ( unsafeShiftL (fromIntegral wh) 56 .|.
-            unsafeShiftL (fromIntegral wg) 48 .|.
-            unsafeShiftL (fromIntegral wf) 40 .|.
-            unsafeShiftL (fromIntegral we) 32 .|.
-            unsafeShiftL (fromIntegral wd) 24 .|.
-            unsafeShiftL (fromIntegral wc) 16 .|.
-            unsafeShiftL (fromIntegral wb) 8 .|.
-            fromIntegral wa
-          )
-          (offset chunk + 8) (length chunk - 8)
-  else Failure e
+word64 e = uneffectful $ \chunk ->
+  if length chunk >= 8
+    then
+      let wa = PM.indexByteArray (array chunk) (offset chunk) :: Word8
+          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
+          we = PM.indexByteArray (array chunk) (offset chunk + 4) :: Word8
+          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 Success
+            ( unsafeShiftL (fromIntegral wh) 56
+                .|. unsafeShiftL (fromIntegral wg) 48
+                .|. unsafeShiftL (fromIntegral wf) 40
+                .|. unsafeShiftL (fromIntegral we) 32
+                .|. unsafeShiftL (fromIntegral wd) 24
+                .|. unsafeShiftL (fromIntegral wc) 16
+                .|. unsafeShiftL (fromIntegral wb) 8
+                .|. fromIntegral wa
+            )
+            (offset chunk + 8)
+            (length chunk - 8)
+    else Failure e
 
 -- | Unsigned 256-bit word.
 word256 :: e -> Parser e s Word256
diff --git a/src/Data/Bytes/Parser/Rebindable.hs b/src/Data/Bytes/Parser/Rebindable.hs
--- a/src/Data/Bytes/Parser/Rebindable.hs
+++ b/src/Data/Bytes/Parser/Rebindable.hs
@@ -1,31 +1,30 @@
-{-# language CPP #-}
-{-# language DataKinds #-}
-{-# language FlexibleInstances #-}
-{-# language MagicHash #-}
-{-# language MultiParamTypeClasses #-}
-{-# language PolyKinds #-}
-{-# language RankNTypes #-}
-{-# language ScopedTypeVariables #-}
-{-# language UnboxedSums #-}
-{-# language UnboxedTuples #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE UnboxedTuples #-}
 
--- | Provides levity-polymorphic variants of @>>=@, @>>@, and @pure@
--- used to assemble parsers whose result types are unlifted. This
--- cannot be used with the @RebindableSyntax@ extension because that
--- extension disallows representations other than @LiftedRep@. Consequently,
--- users of this module must manually desugar do notation. See the
--- @url-bytes@ library for an example of this module in action.
---
--- Only resort to the functions in this module after checking that
--- GHC is unable to optimize away @I#@ and friends in your code.
+{- | Provides levity-polymorphic variants of @>>=@, @>>@, and @pure@
+used to assemble parsers whose result types are unlifted. This
+cannot be used with the @RebindableSyntax@ extension because that
+extension disallows representations other than @LiftedRep@. Consequently,
+users of this module must manually desugar do notation. See the
+@url-bytes@ library for an example of this module in action.
+
+Only resort to the functions in this module after checking that
+GHC is unable to optimize away @I#@ and friends in your code.
+-}
 module Data.Bytes.Parser.Rebindable
-  ( Bind(..)
-  , Pure(..)
+  ( Bind (..)
+  , Pure (..)
   ) where
 
+import Data.Bytes.Parser.Internal (Parser (..))
+import GHC.Exts (RuntimeRep (..), TYPE)
 import Prelude ()
-import GHC.Exts (TYPE,RuntimeRep(..))
-import Data.Bytes.Parser.Internal (Parser(..))
 
 #if MIN_VERSION_base(4,16,0)
 import GHC.Exts (LiftedRep)
@@ -34,411 +33,506 @@
 #endif
 
 class Bind (ra :: RuntimeRep) (rb :: RuntimeRep) where
-  (>>=) :: forall e s (a :: TYPE ra) (b :: TYPE rb).
-    Parser e s a -> (a -> Parser e s b) -> Parser e s b
-  (>>) :: forall e s (a :: TYPE ra) (b :: TYPE rb).
-    Parser e s a -> Parser e s b -> Parser e s b
+  (>>=) ::
+    forall e s (a :: TYPE ra) (b :: TYPE rb).
+    Parser e s a ->
+    (a -> Parser e s b) ->
+    Parser e s b
+  (>>) ::
+    forall e s (a :: TYPE ra) (b :: TYPE rb).
+    Parser e s a ->
+    Parser e s b ->
+    Parser e s b
 
 class Pure (ra :: RuntimeRep) where
   pure :: forall e s (a :: TYPE ra). a -> Parser e s a
 
 pureParser :: a -> Parser e s a
-{-# inline pureParser #-}
-pureParser a = Parser
-  (\(# _, b, c #) s -> (# s, (# | (# a, b, c #) #) #))
+{-# INLINE pureParser #-}
+pureParser a =
+  Parser
+    (\(# _, b, c #) s -> (# s, (# | (# a, b, c #) #) #))
 
 bindParser :: Parser e s a -> (a -> Parser e s b) -> Parser e s b
-{-# inline bindParser #-}
-bindParser (Parser f) g = Parser
-  (\x@(# arr, _, _ #) s0 -> case f x s0 of
-    (# s1, r0 #) -> case r0 of
-      (# e | #) -> (# s1, (# e | #) #)
-      (# | (# y, b, c #) #) ->
-        runParser (g y) (# arr, b, c #) s1
-  )
+{-# INLINE bindParser #-}
+bindParser (Parser f) g =
+  Parser
+    ( \x@(# arr, _, _ #) s0 -> case f x s0 of
+        (# s1, r0 #) -> case r0 of
+          (# e | #) -> (# s1, (# e | #) #)
+          (# | (# y, b, c #) #) ->
+            runParser (g y) (# arr, b, c #) s1
+    )
 
 sequenceParser :: Parser e s a -> Parser e s b -> Parser e s b
-{-# inline sequenceParser #-}
-sequenceParser (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
-  )
+{-# INLINE sequenceParser #-}
+sequenceParser (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
+    )
 
-pureIntParser :: forall (a :: TYPE 'IntRep) e s.
-  a -> Parser e s a
-{-# inline pureIntParser #-}
-pureIntParser a = Parser
-  (\(# _, b, c #) s -> (# s, (# | (# a, b, c #) #) #))
+pureIntParser ::
+  forall (a :: TYPE 'IntRep) e s.
+  a ->
+  Parser e s a
+{-# INLINE pureIntParser #-}
+pureIntParser a =
+  Parser
+    (\(# _, b, c #) s -> (# s, (# | (# a, b, c #) #) #))
 
-bindIntParser :: forall (a :: TYPE 'IntRep) e s b.
-  Parser e s a -> (a -> Parser e s b) -> Parser e s b
-{-# inline bindIntParser #-}
-bindIntParser (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
-  )
+bindIntParser ::
+  forall (a :: TYPE 'IntRep) e s b.
+  Parser e s a ->
+  (a -> Parser e s b) ->
+  Parser e s b
+{-# INLINE bindIntParser #-}
+bindIntParser (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
+    )
 
-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
-  )
+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 #-}
-sequenceIntParser (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
-  )
+sequenceIntParser ::
+  forall (a :: TYPE 'IntRep) e s b.
+  Parser e s a ->
+  Parser e s b ->
+  Parser e s b
+{-# INLINE sequenceIntParser #-}
+sequenceIntParser (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
+    )
 
-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
-  )
+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 #-}
-pureIntPairParser a = Parser
-  (\(# _, b, c #) s -> (# s, (# | (# a, b, c #) #) #))
+pureIntPairParser ::
+  forall (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep])) e s.
+  a ->
+  Parser e s a
+{-# INLINE pureIntPairParser #-}
+pureIntPairParser a =
+  Parser
+    (\(# _, b, c #) s -> (# s, (# | (# a, b, c #) #) #))
 
-bindIntPairParser :: forall (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep])) e s b.
-  Parser e s a -> (a -> Parser e s b) -> Parser e s b
-{-# inline bindIntPairParser #-}
-bindIntPairParser (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
-  )
+bindIntPairParser ::
+  forall (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep])) e s b.
+  Parser e s a ->
+  (a -> Parser e s b) ->
+  Parser e s b
+{-# INLINE bindIntPairParser #-}
+bindIntPairParser (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
+    )
 
-pureInt5Parser :: forall (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])) e s.
-  a -> Parser e s a
-{-# inline pureInt5Parser #-}
-pureInt5Parser a = Parser
-  (\(# _, b, c #) s -> (# s, (# | (# a, b, c #) #) #))
+pureInt5Parser ::
+  forall (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])) e s.
+  a ->
+  Parser e s a
+{-# INLINE pureInt5Parser #-}
+pureInt5Parser a =
+  Parser
+    (\(# _, b, c #) s -> (# s, (# | (# a, b, c #) #) #))
 
-bindInt5Parser :: forall (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])) e s b.
-  Parser e s a -> (a -> Parser e s b) -> Parser e s b
-{-# inline bindInt5Parser #-}
-bindInt5Parser (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
-  )
+bindInt5Parser ::
+  forall (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])) e s b.
+  Parser e s a ->
+  (a -> Parser e s b) ->
+  Parser e s b
+{-# INLINE bindInt5Parser #-}
+bindInt5Parser (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
+    )
 
-sequenceInt5Parser :: forall (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])) e s b.
-  Parser e s a -> Parser e s b -> Parser e s b
-{-# inline sequenceInt5Parser #-}
-sequenceInt5Parser (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
-  )
+sequenceInt5Parser ::
+  forall (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])) e s b.
+  Parser e s a ->
+  Parser e s b ->
+  Parser e s b
+{-# INLINE sequenceInt5Parser #-}
+sequenceInt5Parser (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
+    )
 
-sequenceIntPairParser :: forall (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep])) e s b.
-  Parser e s a -> Parser e s b -> Parser e s b
-{-# inline sequenceIntPairParser #-}
-sequenceIntPairParser (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
-  )
+sequenceIntPairParser ::
+  forall (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep])) e s b.
+  Parser e s a ->
+  Parser e s b ->
+  Parser e s b
+{-# INLINE sequenceIntPairParser #-}
+sequenceIntPairParser (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
+    )
 
-bindInt2to5Parser :: forall
-  (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep]))
-  (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep]))
-  e s.
-  Parser e s a -> (a -> Parser e s b) -> Parser e s b
-{-# inline bindInt2to5Parser #-}
-bindInt2to5Parser (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
-  )
+bindInt2to5Parser ::
+  forall
+    (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep]))
+    (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep]))
+    e
+    s.
+  Parser e s a ->
+  (a -> Parser e s b) ->
+  Parser e s b
+{-# INLINE bindInt2to5Parser #-}
+bindInt2to5Parser (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
+    )
 
-sequenceInt2to5Parser :: forall
-  (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep]))
-  (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep]))
-  e s.
-  Parser e s a -> Parser e s b -> Parser e s b
-{-# inline sequenceInt2to5Parser #-}
-sequenceInt2to5Parser (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
-  )
+sequenceInt2to5Parser ::
+  forall
+    (a :: TYPE ('TupleRep '[ 'IntRep, 'IntRep]))
+    (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep]))
+    e
+    s.
+  Parser e s a ->
+  Parser e s b ->
+  Parser e s b
+{-# INLINE sequenceInt2to5Parser #-}
+sequenceInt2to5Parser (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
+    )
 
 instance Bind LiftedRep LiftedRep where
-  {-# inline (>>=) #-}
-  {-# inline (>>) #-}
+  {-# INLINE (>>=) #-}
+  {-# INLINE (>>) #-}
   (>>=) = bindParser
   (>>) = sequenceParser
 
 instance Bind 'WordRep LiftedRep where
-  {-# inline (>>=) #-}
-  {-# inline (>>) #-}
+  {-# INLINE (>>=) #-}
+  {-# INLINE (>>) #-}
   (>>=) = bindWordParser
   (>>) = sequenceWordParser
 
 instance Bind 'IntRep LiftedRep where
-  {-# inline (>>=) #-}
-  {-# inline (>>) #-}
+  {-# INLINE (>>=) #-}
+  {-# INLINE (>>) #-}
   (>>=) = bindIntParser
   (>>) = sequenceIntParser
 
 instance Bind ('TupleRep '[ 'IntRep, 'IntRep]) LiftedRep where
-  {-# inline (>>=) #-}
-  {-# inline (>>) #-}
+  {-# INLINE (>>=) #-}
+  {-# INLINE (>>) #-}
   (>>=) = bindIntPairParser
   (>>) = sequenceIntPairParser
 
-
-instance Bind ('TupleRep '[ 'IntRep, 'IntRep])
-              ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])
+instance
+  Bind
+    ('TupleRep '[ 'IntRep, 'IntRep])
+    ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])
   where
-  {-# inline (>>=) #-}
-  {-# inline (>>) #-}
+  {-# INLINE (>>=) #-}
+  {-# INLINE (>>) #-}
   (>>=) = bindInt2to5Parser
   (>>) = sequenceInt2to5Parser
 
-instance Bind ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])
-              LiftedRep
+instance
+  Bind
+    ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])
+    LiftedRep
   where
-  {-# inline (>>=) #-}
-  {-# inline (>>) #-}
+  {-# INLINE (>>=) #-}
+  {-# INLINE (>>) #-}
   (>>=) = bindInt5Parser
   (>>) = sequenceInt5Parser
 
-
-instance Bind 'IntRep
-              ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])
+instance
+  Bind
+    'IntRep
+    ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])
   where
-  {-# inline (>>=) #-}
-  {-# inline (>>) #-}
+  {-# INLINE (>>=) #-}
+  {-# INLINE (>>) #-}
   (>>=) = bindFromIntToInt5
   (>>) = sequenceIntToInt5
 
 instance Bind LiftedRep ('TupleRep '[ 'IntRep, 'IntRep]) where
-  {-# inline (>>=) #-}
-  {-# inline (>>) #-}
+  {-# INLINE (>>=) #-}
+  {-# INLINE (>>) #-}
   (>>=) = bindFromLiftedToIntPair
   (>>) = sequenceLiftedToIntPair
 
-instance Bind LiftedRep
-              ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])
+instance
+  Bind
+    LiftedRep
+    ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])
   where
-  {-# inline (>>=) #-}
-  {-# inline (>>) #-}
+  {-# INLINE (>>=) #-}
+  {-# INLINE (>>) #-}
   (>>=) = bindFromLiftedToInt5
   (>>) = sequenceLiftedToInt5
 
 instance Bind 'IntRep ('TupleRep '[ 'IntRep, 'IntRep]) where
-  {-# inline (>>=) #-}
-  {-# inline (>>) #-}
+  {-# INLINE (>>=) #-}
+  {-# INLINE (>>) #-}
   (>>=) = bindFromIntToIntPair
   (>>) = sequenceIntToIntPair
 
 instance Bind LiftedRep 'IntRep where
-  {-# inline (>>=) #-}
-  {-# inline (>>) #-}
+  {-# INLINE (>>=) #-}
+  {-# INLINE (>>) #-}
   (>>=) = bindFromLiftedToInt
   (>>) = sequenceLiftedToInt
 
 instance Pure LiftedRep where
-  {-# inline pure #-}
+  {-# INLINE pure #-}
   pure = pureParser
 
 instance Pure 'IntRep where
-  {-# inline pure #-}
+  {-# INLINE pure #-}
   pure = pureIntParser
 
 instance Pure ('TupleRep '[ 'IntRep, 'IntRep]) where
-  {-# inline pure #-}
+  {-# INLINE pure #-}
   pure = pureIntPairParser
 
 instance Pure ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep]) where
-  {-# inline pure #-}
+  {-# INLINE pure #-}
   pure = pureInt5Parser
 
 bindFromIntToIntPair ::
-     forall s e
-       (a :: TYPE 'IntRep)
-       (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep ])).
-     Parser s e a
-  -> (a -> Parser s e b)
-  -> Parser s e b
-{-# inline bindFromIntToIntPair #-}
-bindFromIntToIntPair (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
-  )
+  forall
+    s
+    e
+    (a :: TYPE 'IntRep)
+    (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep])).
+  Parser s e a ->
+  (a -> Parser s e b) ->
+  Parser s e b
+{-# INLINE bindFromIntToIntPair #-}
+bindFromIntToIntPair (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
+    )
 
 sequenceIntToIntPair ::
-     forall s e
-       (a :: TYPE 'IntRep)
-       (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep ])).
-     Parser s e a
-  -> Parser s e b
-  -> Parser s e b
-{-# inline sequenceIntToIntPair #-}
-sequenceIntToIntPair (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
-  )
+  forall
+    s
+    e
+    (a :: TYPE 'IntRep)
+    (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep])).
+  Parser s e a ->
+  Parser s e b ->
+  Parser s e b
+{-# INLINE sequenceIntToIntPair #-}
+sequenceIntToIntPair (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
+    )
 
 bindFromIntToInt5 ::
-     forall s e
-       (a :: TYPE 'IntRep)
-       (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep ])).
-     Parser s e a
-  -> (a -> Parser s e b)
-  -> Parser s e b
-{-# inline bindFromIntToInt5 #-}
-bindFromIntToInt5 (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
-  )
+  forall
+    s
+    e
+    (a :: TYPE 'IntRep)
+    (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])).
+  Parser s e a ->
+  (a -> Parser s e b) ->
+  Parser s e b
+{-# INLINE bindFromIntToInt5 #-}
+bindFromIntToInt5 (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
+    )
 
 sequenceIntToInt5 ::
-     forall s e
-       (a :: TYPE 'IntRep)
-       (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep ])).
-     Parser s e a
-  -> Parser s e b
-  -> Parser s e b
-{-# inline sequenceIntToInt5 #-}
-sequenceIntToInt5 (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
-  )
+  forall
+    s
+    e
+    (a :: TYPE 'IntRep)
+    (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])).
+  Parser s e a ->
+  Parser s e b ->
+  Parser s e b
+{-# INLINE sequenceIntToInt5 #-}
+sequenceIntToInt5 (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
+    )
 
 bindFromLiftedToIntPair ::
-     forall s e
-       (a :: TYPE LiftedRep)
-       (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep ])).
-     Parser s e a
-  -> (a -> Parser s e b)
-  -> Parser s e b
-{-# inline bindFromLiftedToIntPair #-}
-bindFromLiftedToIntPair (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
-  )
+  forall
+    s
+    e
+    (a :: TYPE LiftedRep)
+    (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep])).
+  Parser s e a ->
+  (a -> Parser s e b) ->
+  Parser s e b
+{-# INLINE bindFromLiftedToIntPair #-}
+bindFromLiftedToIntPair (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
+    )
 
 sequenceLiftedToIntPair ::
-     forall s e
-       (a :: TYPE LiftedRep)
-       (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep ])).
-     Parser s e a
-  -> Parser s e b
-  -> Parser s e b
-{-# inline sequenceLiftedToIntPair #-}
-sequenceLiftedToIntPair (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
-  )
-
+  forall
+    s
+    e
+    (a :: TYPE LiftedRep)
+    (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep])).
+  Parser s e a ->
+  Parser s e b ->
+  Parser s e b
+{-# INLINE sequenceLiftedToIntPair #-}
+sequenceLiftedToIntPair (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
+    )
 
 bindFromLiftedToInt5 ::
-     forall s e
-       (a :: TYPE LiftedRep)
-       (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])).
-     Parser s e a
-  -> (a -> Parser s e b)
-  -> Parser s e b
-{-# inline bindFromLiftedToInt5 #-}
-bindFromLiftedToInt5 (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
-  )
+  forall
+    s
+    e
+    (a :: TYPE LiftedRep)
+    (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])).
+  Parser s e a ->
+  (a -> Parser s e b) ->
+  Parser s e b
+{-# INLINE bindFromLiftedToInt5 #-}
+bindFromLiftedToInt5 (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
+    )
 
 sequenceLiftedToInt5 ::
-     forall s e
-       (a :: TYPE LiftedRep)
-       (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep ])).
-     Parser s e a
-  -> Parser s e b
-  -> Parser s e b
-{-# inline sequenceLiftedToInt5 #-}
-sequenceLiftedToInt5 (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
-  )
+  forall
+    s
+    e
+    (a :: TYPE LiftedRep)
+    (b :: TYPE ('TupleRep '[ 'IntRep, 'IntRep, 'IntRep, 'IntRep, 'IntRep])).
+  Parser s e a ->
+  Parser s e b ->
+  Parser s e b
+{-# INLINE sequenceLiftedToInt5 #-}
+sequenceLiftedToInt5 (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
+    )
 
 bindFromLiftedToInt ::
-     forall s e
-       (a :: TYPE LiftedRep)
-       (b :: TYPE 'IntRep).
-     Parser s e a
-  -> (a -> Parser s e b)
-  -> Parser s e b
-{-# inline bindFromLiftedToInt #-}
-bindFromLiftedToInt (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
-  )
+  forall
+    s
+    e
+    (a :: TYPE LiftedRep)
+    (b :: TYPE 'IntRep).
+  Parser s e a ->
+  (a -> Parser s e b) ->
+  Parser s e b
+{-# INLINE bindFromLiftedToInt #-}
+bindFromLiftedToInt (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
+    )
 
 sequenceLiftedToInt ::
-     forall s e
-       (a :: TYPE LiftedRep)
-       (b :: TYPE 'IntRep).
-     Parser s e a
-  -> Parser s e b
-  -> Parser s e b
-{-# inline sequenceLiftedToInt #-}
-sequenceLiftedToInt (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
-  )
+  forall
+    s
+    e
+    (a :: TYPE LiftedRep)
+    (b :: TYPE 'IntRep).
+  Parser s e a ->
+  Parser s e b ->
+  Parser s e b
+{-# INLINE sequenceLiftedToInt #-}
+sequenceLiftedToInt (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
+    )
diff --git a/src/Data/Bytes/Parser/Types.hs b/src/Data/Bytes/Parser/Types.hs
--- a/src/Data/Bytes/Parser/Types.hs
+++ b/src/Data/Bytes/Parser/Types.hs
@@ -1,41 +1,43 @@
-{-# language DeriveFunctor #-}
-{-# language DeriveFoldable #-}
-{-# language DerivingStrategies #-}
+{-# LANGUAGE DeriveFoldable #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE DerivingStrategies #-}
 
 module Data.Bytes.Parser.Types
   ( Parser
-  , Result(..)
-  , Slice(..)
+  , Result (..)
+  , Slice (..)
   ) where
 
-import Data.Bytes.Parser.Internal (Parser(..))
+import Data.Bytes.Parser.Internal (Parser (..))
 
 -- | The result of running a parser.
 data Result e a
-  = Failure e
-    -- ^ An error message indicating what went wrong.
-  | Success {-# UNPACK #-} !(Slice a)
-    -- ^ The parsed value and the number of bytes
+  = -- | An error message indicating what went wrong.
+    Failure e
+  | -- | The parsed value and the number of bytes
     -- remaining in parsed slice.
-  deriving stock (Eq,Show,Foldable,Functor)
+    Success {-# UNPACK #-} !(Slice a)
+  deriving stock (Eq, Show, Foldable, Functor)
 
--- | Slicing metadata (an offset and a length) accompanied
--- by a value. This does not represent a slice into the
--- value. This type is intended to be used as the result
--- of an executed parser. In this context the slicing metadata
--- describe a slice into to the array (or byte array) that
--- from which the value was parsed.
---
--- It is often useful to check the @length@ when a parser
--- succeeds since a non-zero length indicates that there
--- was additional unconsumed input. The @offset@ is only
--- ever needed to construct a new slice (via @Bytes@ or
--- @SmallVector@) from the remaining input.
+{- | Slicing metadata (an offset and a length) accompanied
+by a value. This does not represent a slice into the
+value. This type is intended to be used as the result
+of an executed parser. In this context the slicing metadata
+describe a slice into to the array (or byte array) that
+from which the value was parsed.
+
+It is often useful to check the @length@ when a parser
+succeeds since a non-zero length indicates that there
+was additional unconsumed input. The @offset@ is only
+ever needed to construct a new slice (via @Bytes@ or
+@SmallVector@) from the remaining input.
+-}
 data Slice a = Slice
   { offset :: {-# UNPACK #-} !Int
-    -- ^ Offset into the array.
+  -- ^ Offset into the array.
   , length :: {-# UNPACK #-} !Int
-    -- ^ Length of the slice.
+  -- ^ Length of the slice.
   , value :: a
-    -- ^ The structured data that was successfully parsed.
-  } deriving stock (Eq,Show,Foldable,Functor)
+  -- ^ The structured data that was successfully parsed.
+  }
+  deriving stock (Eq, Show, Foldable, Functor)
diff --git a/src/Data/Bytes/Parser/Unsafe.hs b/src/Data/Bytes/Parser/Unsafe.hs
--- a/src/Data/Bytes/Parser/Unsafe.hs
+++ b/src/Data/Bytes/Parser/Unsafe.hs
@@ -1,28 +1,22 @@
-{-# language BangPatterns #-}
-{-# language BinaryLiterals #-}
-{-# language DataKinds #-}
-{-# language DeriveFunctor #-}
-{-# language DerivingStrategies #-}
-{-# language DuplicateRecordFields #-}
-{-# language GADTSyntax #-}
-{-# language KindSignatures #-}
-{-# language LambdaCase #-}
-{-# language MagicHash #-}
-{-# language MultiWayIf #-}
-{-# language NamedFieldPuns #-}
-{-# language PolyKinds #-}
-{-# language RankNTypes #-}
-{-# language ScopedTypeVariables #-}
-{-# language StandaloneDeriving #-}
-{-# language TypeApplications #-}
-{-# language UnboxedSums #-}
-{-# language UnboxedTuples #-}
+{-# LANGUAGE BinaryLiterals #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE GADTSyntax #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE UnboxedTuples #-}
 
--- | Everything in this module is unsafe and can lead to
--- nondeterministic output or segfaults if used incorrectly.
+{- | Everything in this module is unsafe and can lead to
+nondeterministic output or segfaults if used incorrectly.
+-}
 module Data.Bytes.Parser.Unsafe
   ( -- * Types
-    Parser(..)
+    Parser (..)
+
     -- * Functions
   , cursor
   , cursor#
@@ -34,41 +28,43 @@
 
 import Prelude hiding (length)
 
-import Data.Bytes.Parser.Internal (Parser(..),uneffectful,uneffectfulInt#)
-import Data.Bytes.Parser.Internal (Result(..))
-import Data.Bytes.Types (Bytes(..))
+import Data.Bytes.Parser.Internal (Parser (..), Result (..), uneffectful, uneffectfulInt#)
+import Data.Bytes.Types (Bytes (..))
 import Data.Primitive (ByteArray)
-import GHC.Exts (Int#,Int(I#))
-
+import GHC.Exts (Int (I#), Int#)
 
--- | 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.
+{- | 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} ->
+cursor = uneffectful $ \Bytes {offset, length} ->
   Success offset offset length
 
 -- | Variant of 'cursor' with unboxed result.
 cursor# :: Parser e s Int#
-cursor# = uneffectfulInt# $ \Bytes{offset=I# off,length=I# len} -> (# | (# off, off, len #) #)
+cursor# = uneffectfulInt# $ \Bytes {offset = I# off, length = I# len} -> (# | (# off, off, len #) #)
 
--- | Return the byte array being parsed. This includes bytes
--- that preceed the current offset and may include bytes that
--- go beyond the length. This is somewhat dangerous, so only
--- use this is you know what you're doing.
+{- | Return the byte array being parsed. This includes bytes
+that preceed the current offset and may include bytes that
+go beyond the length. This is somewhat dangerous, so only
+use this is you know what you're doing.
+-}
 expose :: Parser e s ByteArray
-expose = uneffectful $ \Bytes{length,offset,array} ->
+expose = uneffectful $ \Bytes {length, offset, array} ->
   Success array offset length
 
--- | Move the cursor back by @n@ bytes. Precondition: you
--- must have previously consumed at least @n@ bytes.
+{- | 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} ->
+unconsume n = uneffectful $ \Bytes {length, offset} ->
   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'.
+{- | 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}) ->
+jump ix = uneffectful $ \(Bytes {length, offset}) ->
   Success () ix (length + (offset - ix))
diff --git a/src/Data/Bytes/Parser/Utf8.hs b/src/Data/Bytes/Parser/Utf8.hs
--- a/src/Data/Bytes/Parser/Utf8.hs
+++ b/src/Data/Bytes/Parser/Utf8.hs
@@ -1,37 +1,33 @@
-{-# language BangPatterns #-}
-{-# language BinaryLiterals #-}
-{-# language DataKinds #-}
-{-# language DeriveFunctor #-}
-{-# language DerivingStrategies #-}
-{-# language GADTSyntax #-}
-{-# language KindSignatures #-}
-{-# language LambdaCase #-}
-{-# language MagicHash #-}
-{-# language MultiWayIf #-}
-{-# language PolyKinds #-}
-{-# language RankNTypes #-}
-{-# language ScopedTypeVariables #-}
-{-# language StandaloneDeriving #-}
-{-# language TypeApplications #-}
-{-# language UnboxedSums #-}
-{-# language UnboxedTuples #-}
-{-# language CPP #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE BinaryLiterals #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE GADTSyntax #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE MultiWayIf #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE UnboxedTuples #-}
 
--- | Parse input as UTF-8-encoded text. Parsers in this module will
--- fail if they encounter a byte above @0x7F@.
+{- | Parse input as UTF-8-encoded text. Parsers in this module will
+fail if they encounter a byte above @0x7F@.
+-}
 module Data.Bytes.Parser.Utf8
   ( -- * Get Character
     any#
   , shortText
   ) where
 
-import Prelude hiding (length,any,fail,takeWhile)
+import Prelude hiding (any, fail, length, takeWhile)
 
-import Data.Bits ((.&.),(.|.),unsafeShiftL,xor)
-import Data.Bytes.Parser.Internal (Parser(..))
+import Data.Bits (unsafeShiftL, xor, (.&.), (.|.))
+import Data.Bytes.Parser.Internal (Parser (..))
 import Data.Text.Short (ShortText)
-import GHC.Exts (Int(I#),Char(C#),Int#,Char#,(-#),(+#),(>#),chr#)
-import GHC.Word (Word8(W8#))
+import GHC.Exts (Char (C#), Char#, Int (I#), Int#, chr#, (+#), (-#), (>#))
+import GHC.Word (Word8 (W8#))
 
 import qualified Data.ByteString.Short.Internal as BSS
 import qualified Data.Bytes.Parser as Parser
@@ -39,6 +35,7 @@
 import qualified Data.Text.Short as TS
 import qualified GHC.Exts as Exts
 
+{- FOURMOLU_DISABLE -}
 -- | Interpret the next one to four bytes as a UTF-8-encoded character.
 -- Fails if the decoded codepoint is in the range U+D800 through U+DFFF.
 any# :: e -> Parser e s Char#
@@ -81,39 +78,46 @@
              | otherwise -> (# s0, (# e | #) #)
     _ -> (# s0, (# e | #) #)
   )
+{- FOURMOLU_ENABLE -}
 
 codepointFromFourBytes :: Word8 -> Word8 -> Word8 -> Word8 -> Char
-codepointFromFourBytes w1 w2 w3 w4 = C#
-  ( chr#
-    ( unI $ fromIntegral
-      ( unsafeShiftL (word8ToWord w1 .&. 0b00001111) 18 .|.
-        unsafeShiftL (word8ToWord w2 .&. 0b00111111) 12 .|.
-        unsafeShiftL (word8ToWord w3 .&. 0b00111111) 6 .|.
-        (word8ToWord w4 .&. 0b00111111)
-      )
+codepointFromFourBytes w1 w2 w3 w4 =
+  C#
+    ( chr#
+        ( unI $
+            fromIntegral
+              ( unsafeShiftL (word8ToWord w1 .&. 0b00001111) 18
+                  .|. unsafeShiftL (word8ToWord w2 .&. 0b00111111) 12
+                  .|. unsafeShiftL (word8ToWord w3 .&. 0b00111111) 6
+                  .|. (word8ToWord w4 .&. 0b00111111)
+              )
+        )
     )
-  )
 
 codepointFromThreeBytes :: Word8 -> Word8 -> Word8 -> Char
-codepointFromThreeBytes w1 w2 w3 = C#
-  ( chr#
-    ( unI $ fromIntegral
-      ( unsafeShiftL (word8ToWord w1 .&. 0b00001111) 12 .|.
-        unsafeShiftL (word8ToWord w2 .&. 0b00111111) 6 .|.
-        (word8ToWord w3 .&. 0b00111111)
-      )
+codepointFromThreeBytes w1 w2 w3 =
+  C#
+    ( chr#
+        ( unI $
+            fromIntegral
+              ( unsafeShiftL (word8ToWord w1 .&. 0b00001111) 12
+                  .|. unsafeShiftL (word8ToWord w2 .&. 0b00111111) 6
+                  .|. (word8ToWord w3 .&. 0b00111111)
+              )
+        )
     )
-  )
 
 codepointFromTwoBytes :: Word8 -> Word8 -> Char
-codepointFromTwoBytes w1 w2 = C#
-  ( chr#
-    ( unI $ fromIntegral @Word @Int
-      ( unsafeShiftL (word8ToWord w1 .&. 0b00011111) 6 .|.
-        (word8ToWord w2 .&. 0b00111111)
-      )
+codepointFromTwoBytes w1 w2 =
+  C#
+    ( chr#
+        ( unI $
+            fromIntegral @Word @Int
+              ( unsafeShiftL (word8ToWord w1 .&. 0b00011111) 6
+                  .|. (word8ToWord w2 .&. 0b00111111)
+              )
+        )
     )
-  )
 
 oneByteChar :: Word8 -> Bool
 oneByteChar !w = w .&. 0b10000000 == 0
@@ -136,13 +140,16 @@
 unI :: Int -> Int#
 unI (I# w) = w
 
--- | Consume input that matches the argument. Fails if the
--- input does not match.
+{- | Consume input that matches the argument. Fails if the
+input does not match.
+-}
 shortText :: e -> ShortText -> Parser e s ()
-shortText e !t = Parser.byteArray e
-  (shortByteStringToByteArray (TS.toShortByteString t))
+shortText e !t =
+  Parser.byteArray
+    e
+    (shortByteStringToByteArray (TS.toShortByteString t))
 
 shortByteStringToByteArray ::
-     BSS.ShortByteString
-  -> PM.ByteArray
+  BSS.ShortByteString ->
+  PM.ByteArray
 shortByteStringToByteArray (BSS.SBS x) = PM.ByteArray x
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -1,31 +1,32 @@
-{-# language BangPatterns #-}
-{-# language DataKinds #-}
-{-# language MagicHash #-}
-{-# language MultiWayIf #-}
-{-# language NumDecimals #-}
-{-# language OverloadedStrings #-}
-{-# language ScopedTypeVariables #-}
-{-# language TypeApplications #-}
-
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# 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))
-import Data.Bytes.Types (Bytes(Bytes))
+import Data.Bytes.Parser (Slice (Slice))
+import Data.Bytes.Types (Bytes (Bytes))
 import Data.Char (ord)
 import Data.Coerce (coerce)
-import Data.Int (Int16,Int32)
-import Data.Primitive (ByteArray(..),PrimArray(..))
+import Data.Int (Int16, Int32)
+import Data.Primitive (ByteArray (..), PrimArray (..))
 import Data.Text.Short (ShortText)
-import Data.WideWord (Word128(Word128))
-import Data.Word (Word8,Word64,Word16,Word32)
+import Data.WideWord (Word128 (Word128))
+import Data.Word (Word16, Word32, Word64, Word8)
 import Numeric.Natural (Natural)
-import System.ByteOrder (Fixed(..),ByteOrder(BigEndian,LittleEndian))
-import Test.Tasty (defaultMain,testGroup,TestTree)
-import Test.Tasty.HUnit ((@=?),testCase)
-import Test.Tasty.QuickCheck ((===),testProperty)
+import System.ByteOrder (ByteOrder (BigEndian, LittleEndian), Fixed (..))
+import Test.Tasty (TestTree, defaultMain, testGroup)
+import Test.Tasty.HUnit (testCase, (@=?))
+import Test.Tasty.QuickCheck (testProperty, (===))
 
 import qualified Data.Bits as Bits
 import qualified Data.Bytes as Bytes
@@ -45,404 +46,413 @@
 main = defaultMain tests
 
 tests :: TestTree
-tests = testGroup "Parser"
-  [ testProperty "decStandardInt" $ \i ->
-      withSz (show i) $ \str len ->
-        P.parseBytes (Latin.decStandardInt ()) str
-        ===
-        P.Success (Slice len 0 i)
-  , testProperty "big-endian-word16-array" $ \(xs :: [Word16]) ->
-      let src = Exts.fromList (coerce xs :: [Fixed 'BigEndian Word16])
-          res = Exts.fromList xs :: PrimArray Word16
-          sz = length xs * 2
-          bs = Bytes (Exts.fromList [0x42 :: Word8] <> untype src) 1 sz
-       in
-      P.Success (Slice (sz + 1) 0 res)
-      ===
-      P.parseBytes (BigEndian.word16Array () (length xs)) bs
-  , testProperty "big-endian-word32-array" $ \(xs :: [Word32]) ->
-      let src = Exts.fromList (coerce xs :: [Fixed 'BigEndian Word32])
-          res = Exts.fromList xs :: PrimArray Word32
-          sz = length xs * 4
-          bs = Bytes (Exts.fromList [0x42 :: Word8] <> untype src) 1 sz
-       in
-      P.Success (Slice (sz + 1) 0 res)
-      ===
-      P.parseBytes (BigEndian.word32Array () (length xs)) bs
-  , testProperty "little-endian-word32-array" $ \(xs :: [Word32]) ->
-      let src = Exts.fromList (coerce xs :: [Fixed 'LittleEndian Word32])
-          res = Exts.fromList xs :: PrimArray Word32
-          sz = length xs * 4
-          bs = Bytes (Exts.fromList [0x42 :: Word8] <> untype src) 1 sz
-       in
-      P.Success (Slice (sz + 1) 0 res)
-      ===
-      P.parseBytes (LittleEndian.word32Array () (length xs)) bs
-  , testProperty "big-endian-word64-array" $ \(xs :: [Word64]) ->
-      let src = Exts.fromList (coerce xs :: [Fixed 'BigEndian Word64])
-          res = Exts.fromList xs :: PrimArray Word64
-          sz = length xs * 8
-          bs = Bytes (Exts.fromList [0x42 :: Word8] <> untype src) 1 sz
-       in
-      P.Success (Slice (sz + 1) 0 res)
-      ===
-      P.parseBytes (BigEndian.word64Array () (length xs)) bs
-  , testProperty "little-endian-word64-array" $ \(xs :: [Word64]) ->
-      let src = Exts.fromList (coerce xs :: [Fixed 'LittleEndian Word64])
-          res = Exts.fromList xs :: PrimArray Word64
-          sz = length xs * 8
-          bs = Bytes (Exts.fromList [0x42 :: Word8] <> untype src) 1 sz
-       in
-      P.Success (Slice (sz + 1) 0 res)
-      ===
-      P.parseBytes (LittleEndian.word64Array () (length xs)) bs
-  , testProperty "little-endian-word128-array" $ \(xs :: [Word128]) ->
-      let src = Exts.fromList xs
-          sz = length xs * 16
-          bs = Bytes (Exts.fromList [0x42 :: Word8] <> untype src) 1 sz
-       in
-      P.parseBytes (replicateM (length xs) (LittleEndian.word128 ())) bs
-      ===
-      P.parseBytes (fmap Exts.toList (LittleEndian.word128Array () (length xs))) bs
-  , testProperty "big-endian-word128-array" $ \(xs :: [Word128]) ->
-      let src = Exts.fromList xs
-          sz = length xs * 16
-          bs = Bytes (Exts.fromList [0x42 :: Word8] <> untype src) 1 sz
-       in
-      P.parseBytes (replicateM (length xs) (BigEndian.word128 ())) bs
-      ===
-      P.parseBytes (fmap Exts.toList (BigEndian.word128Array () (length xs))) bs
-  , testProperty "cstring" $ \(xs :: [Word8]) ->
-      let ys = Exts.fromList xs
-          bs = Bytes.singleton 0x31 <> ys
-       in
-      P.parseBytes (P.cstring () (Exts.Ptr "1"# ) *> P.bytes () ys *> pure 42) bs
-      ===
-      (P.Success (Slice (Bytes.length ys + 1) 0 42) :: P.Result () Integer)
-  , testCase "big-endian-word256" $
-      P.parseBytesMaybe (BigEndian.word256Array () 1) (Exts.fromList [
-        0x12, 0x34, 0x56, 0x78, 0x90,
-        0x12, 0x34, 0x56, 0x78, 0x90,
-        0x12, 0x34, 0x56, 0x78, 0x90,
-        0x12,
-        0x12, 0x34, 0x56, 0x78, 0x90,
-        0x12, 0x34, 0x56, 0x78, 0x90,
-        0x12, 0x34, 0x56, 0x78, 0x90,
-        0x12
-      ])
-      @=?
-      Just (Exts.fromList [0x1234567890123456789012345678901212345678901234567890123456789012])
-  , testProperty "big-endian-word64" bigEndianWord64
-  , testProperty "big-endian-word32" bigEndianWord32
-  , testProperty "little-endian-word32" littleEndianWord32
-  , testCase "delimit" $
-      P.Success (Slice 13 0 (167,14625))
-      @=?
-      P.parseBytes
-        (do len <- Latin.decUnsignedInt ()
-            Latin.char () ','
-            r <- P.delimit () () len $ (,)
-              <$> Latin.decUnsignedInt ()
-              <*  Latin.char () '*'
-              <*> Latin.decUnsignedInt ()
-            Latin.char () '0'
-            pure r
-        ) (bytes "9,167*146250")
-  , testGroup "decUnsignedInt"
-    [ testCase "A" $
-        P.Failure ()
-        @=?
-        P.parseBytes (Latin.decUnsignedInt ())
-          (bytes "742493495120739103935542")
-    , testCase "B" $
-        P.Success (Slice 8 3 4654667)
-        @=?
-        P.parseBytes (Latin.decUnsignedInt ())
-          (bytes "4654667,55")
-    , testCase "C" $
-        P.Failure ()
-        @=?
-        P.parseBytes (Latin.decUnsignedInt ())
-          (bytes ('1' : show (maxBound :: Int)))
-    , testCase "D" $
-        P.Failure ()
-        @=?
-        P.parseBytes (Latin.decUnsignedInt ())
-          (bytes "2481030337885070917891")
-    , testCase "E" $
-        P.Failure ()
-        @=?
-        P.parseBytes (Latin.decUnsignedInt ())
-          (bytes (show (fromIntegral @Int @Word maxBound + 1)))
-    , testCase "F" $ withSz (show (maxBound :: Int)) $ \str len ->
-        P.Success (Slice len 0 maxBound)
-        @=?
-        P.parseBytes (Latin.decUnsignedInt ()) str
-    , testProperty "property" $ \(QC.NonNegative i) ->
-        withSz (show i) $ \str len ->
-          P.parseBytes (Latin.decUnsignedInt ()) str
-          ===
-          P.Success (Slice len 0 i)
-    ]
-  , testGroup "hexNibbleLower"
-    [ testCase "A" $
-        P.parseBytes (Latin.hexNibbleLower ()) (bytes "Ab") @=? P.Failure ()
-    , testCase "B" $
-        P.parseBytes (Latin.hexNibbleLower ()) (bytes "bA") @=? P.Success (Slice 2 1 0xb)
-    , testCase "C" $
-        P.parseBytes (Latin.hexNibbleLower ()) (bytes "") @=? P.Failure ()
-    ]
-  , testGroup "tryHexNibbleLower"
-    [ testCase "A" $
-        P.Success @() (Slice 1 2 Nothing)
-        @=?
-        P.parseBytes Latin.tryHexNibbleLower (bytes "Ab")
-    , testCase "B" $
-        P.Success @() (Slice 2 1 (Just 0xb))
-        @=?
-        P.parseBytes Latin.tryHexNibbleLower (bytes "bA")
-    , testCase "C" $
-        P.Success @() (Slice 1 0 Nothing)
-        @=?
-        P.parseBytes Latin.tryHexNibbleLower (bytes "")
-    ]
-  , testGroup "decPositiveInteger"
-    [ testCase "A" $
-        P.parseBytes (Latin.decUnsignedInteger ())
-          (bytes "5469999463123462573426452736423546373235260")
-        @=?
-        P.Success
-          (Slice 44 0 5469999463123462573426452736423546373235260)
-    , testProperty "property" $ \(LargeInteger i) ->
+tests =
+  testGroup
+    "Parser"
+    [ testProperty "decStandardInt" $ \i ->
         withSz (show i) $ \str len ->
-          i >= 0
-          QC.==>
-          P.parseBytes (Latin.decUnsignedInteger ()) str
-          ===
-          P.Success (Slice len 0 i)
-    ]
-  , testGroup "decTrailingInteger"
-    [ testProperty "property" $ \(LargeInteger i) ->
-        withSz (show i) $ \str sz ->
-          i >= 0
-          QC.==>
-          P.parseBytes (Latin.decTrailingInteger 2) str
-          ===
-          (P.Success (Slice sz 0 (read ('2' : show i) :: Integer)) :: P.Result () Integer)
-    ]
-  , testGroup "decSignedInteger"
-    [ testCase "A" $
-        P.parseBytes (Latin.decSignedInteger ())
-          (bytes "-54699994631234625734264527364235463732352601")
-        @=?
-        P.Success
-          ( Slice 46 0
-            (-54699994631234625734264527364235463732352601)
+          P.parseBytes (Latin.decStandardInt ()) str
+            === P.Success (Slice len 0 i)
+    , testProperty "big-endian-word16-array" $ \(xs :: [Word16]) ->
+        let src = Exts.fromList (coerce xs :: [Fixed 'BigEndian Word16])
+            res = Exts.fromList xs :: PrimArray Word16
+            sz = length xs * 2
+            bs = Bytes (Exts.fromList [0x42 :: Word8] <> untype src) 1 sz
+         in P.Success (Slice (sz + 1) 0 res)
+              === P.parseBytes (BigEndian.word16Array () (length xs)) bs
+    , testProperty "big-endian-word32-array" $ \(xs :: [Word32]) ->
+        let src = Exts.fromList (coerce xs :: [Fixed 'BigEndian Word32])
+            res = Exts.fromList xs :: PrimArray Word32
+            sz = length xs * 4
+            bs = Bytes (Exts.fromList [0x42 :: Word8] <> untype src) 1 sz
+         in P.Success (Slice (sz + 1) 0 res)
+              === P.parseBytes (BigEndian.word32Array () (length xs)) bs
+    , testProperty "little-endian-word32-array" $ \(xs :: [Word32]) ->
+        let src = Exts.fromList (coerce xs :: [Fixed 'LittleEndian Word32])
+            res = Exts.fromList xs :: PrimArray Word32
+            sz = length xs * 4
+            bs = Bytes (Exts.fromList [0x42 :: Word8] <> untype src) 1 sz
+         in P.Success (Slice (sz + 1) 0 res)
+              === P.parseBytes (LittleEndian.word32Array () (length xs)) bs
+    , testProperty "big-endian-word64-array" $ \(xs :: [Word64]) ->
+        let src = Exts.fromList (coerce xs :: [Fixed 'BigEndian Word64])
+            res = Exts.fromList xs :: PrimArray Word64
+            sz = length xs * 8
+            bs = Bytes (Exts.fromList [0x42 :: Word8] <> untype src) 1 sz
+         in P.Success (Slice (sz + 1) 0 res)
+              === P.parseBytes (BigEndian.word64Array () (length xs)) bs
+    , testProperty "little-endian-word64-array" $ \(xs :: [Word64]) ->
+        let src = Exts.fromList (coerce xs :: [Fixed 'LittleEndian Word64])
+            res = Exts.fromList xs :: PrimArray Word64
+            sz = length xs * 8
+            bs = Bytes (Exts.fromList [0x42 :: Word8] <> untype src) 1 sz
+         in P.Success (Slice (sz + 1) 0 res)
+              === P.parseBytes (LittleEndian.word64Array () (length xs)) bs
+    , testProperty "little-endian-word128-array" $ \(xs :: [Word128]) ->
+        let src = Exts.fromList xs
+            sz = length xs * 16
+            bs = Bytes (Exts.fromList [0x42 :: Word8] <> untype src) 1 sz
+         in P.parseBytes (replicateM (length xs) (LittleEndian.word128 ())) bs
+              === P.parseBytes (fmap Exts.toList (LittleEndian.word128Array () (length xs))) bs
+    , testProperty "big-endian-word128-array" $ \(xs :: [Word128]) ->
+        let src = Exts.fromList xs
+            sz = length xs * 16
+            bs = Bytes (Exts.fromList [0x42 :: Word8] <> untype src) 1 sz
+         in P.parseBytes (replicateM (length xs) (BigEndian.word128 ())) bs
+              === P.parseBytes (fmap Exts.toList (BigEndian.word128Array () (length xs))) bs
+    , testProperty "cstring" $ \(xs :: [Word8]) ->
+        let ys = Exts.fromList xs
+            bs = Bytes.singleton 0x31 <> ys
+         in P.parseBytes (P.cstring () (Exts.Ptr "1"#) *> P.bytes () ys *> pure 42) bs
+              === (P.Success (Slice (Bytes.length ys + 1) 0 42) :: P.Result () Integer)
+    , testCase "big-endian-word256" $
+        P.parseBytesMaybe
+          (BigEndian.word256Array () 1)
+          ( Exts.fromList
+              [ 0x12
+              , 0x34
+              , 0x56
+              , 0x78
+              , 0x90
+              , 0x12
+              , 0x34
+              , 0x56
+              , 0x78
+              , 0x90
+              , 0x12
+              , 0x34
+              , 0x56
+              , 0x78
+              , 0x90
+              , 0x12
+              , 0x12
+              , 0x34
+              , 0x56
+              , 0x78
+              , 0x90
+              , 0x12
+              , 0x34
+              , 0x56
+              , 0x78
+              , 0x90
+              , 0x12
+              , 0x34
+              , 0x56
+              , 0x78
+              , 0x90
+              , 0x12
+              ]
           )
-    , testCase "B" $ 
-        P.Success (Slice 25 0 (3,(-206173954435705292503)))
-        @=?
-        P.parseBytes
-          ( pure (,)
-            <*> Latin.decSignedInteger ()
-            <*  Latin.char () 'e'
-            <*> Latin.decSignedInteger ()
-          ) (bytes "3e-206173954435705292503")
-    , testProperty "property" $ \(LargeInteger i) ->
-        withSz (show i) $ \str len ->
-          P.parseBytes (Latin.decSignedInteger ()) str
-          ===
-          P.Success (Slice len 0 i)
-    ]
-  , testGroup "decSignedInt"
-    [ testProperty "A" $ \i -> withSz (show i) $ \str len ->
-        P.parseBytes (Latin.decSignedInt ()) str
-        ===
-        P.Success (Slice len 0 i)
-    , testProperty "B" $ \i ->
-        let s = (if i >= 0 then "+" else "") ++ show i in
-        withSz s $ \str len ->
-          P.parseBytes (Latin.decSignedInt ()) str
-          ===
-          P.Success (Slice len 0 i)
-    , testCase "C" $
-        P.Failure ()
-        @=?
-        P.parseBytes (Latin.decSignedInt ())
-          (bytes ('1' : show (maxBound :: Int)))
-    , testCase "D" $
-        P.Failure ()
-        @=?
-        P.parseBytes (Latin.decSignedInt ())
-          (bytes ('-' : '3' : show (maxBound :: Int)))
-    , testCase "E" $
-        P.Failure ()
-        @=?
-        P.parseBytes (Latin.decSignedInt ())
-          (bytes "2481030337885070917891")
-    , testCase "F" $
-        P.Failure ()
-        @=?
-        P.parseBytes (Latin.decSignedInt ())
-          (bytes "-4305030950553840988981")
-    , testCase "G" $ withSz (show (minBound :: Int)) $ \str len ->
-        P.Success (Slice len 0 minBound)
-        @=?
-        P.parseBytes (Latin.decSignedInt ()) str
-    , testCase "H" $ withSz (show (maxBound :: Int)) $ \str len ->
-        P.Success (Slice len 0 maxBound)
-        @=?
-        P.parseBytes (Latin.decSignedInt ()) str
-    , testCase "I" $
-        P.Failure ()
-        @=?
-        P.parseBytes (Latin.decSignedInt ())
-          (bytes (show (fromIntegral @Int @Word maxBound + 1)))
-    , testCase "J" $
-        -- This is one number lower than the minimum bound for
-        -- a signed 64-bit number, but this test will pass on
-        -- 32-bit architectures as well.
-        P.Failure ()
-        @=?
-        P.parseBytes (Latin.decSignedInt ())
-          (bytes "-9223372036854775809")
-    ]
-  , testGroup "decWord64"
-    [ testCase "A" $
-        P.Failure ()
-        @=?
-        P.parseBytes (Latin.decWord64 ())
-          (bytes "2481030337885070917891")
-    ]
-  , testCase "decWord-composition" $
-      P.Success (Slice 6 0 (42,8))
-      @=?
-      P.parseBytes
-        ( pure (,)
-        <*> Ascii.decWord ()
-        <*  Ascii.char () '.'
-        <*> Ascii.decWord ()
-        <*  Ascii.char () '.'
-        ) (bytes "42.8.")
-  , testCase "decWord-replicate" $
-      P.Success (Slice 7 0 (Exts.fromList [42,93] :: PrimArray Word))
-      @=?
-      P.parseBytes
-        (P.replicate 2 (Ascii.decWord () <* Ascii.char () '.'))
-        (bytes "42.93.")
-  , testCase "ascii-takeShortWhile" $
-      P.Success (Slice 11 0 (Exts.fromList ["the","world"] :: PM.Array ShortText))
-      @=?
-      P.parseBytes
-        (P.replicate 2 (Ascii.takeShortWhile (/=',') <* Ascii.char () ','))
-        (bytes "the,world,")
-  , testGroup "hexFixedWord8"
-    [ testCase "A" $
-        P.parseBytes (Latin.hexFixedWord8 ()) (bytes "A") @=? P.Failure ()
-    , testCase "B" $
-        P.parseBytes (Latin.hexFixedWord8 ()) (bytes "0A") @=? P.Success (Slice 3 0 0x0A)
-    , testCase "C" $
-        P.parseBytes (Latin.hexFixedWord8 ()) (bytes "") @=? P.Failure ()
-    , testCase "D" $
-        P.parseBytes (Latin.hexFixedWord8 ()) (bytes "A!") @=? P.Failure ()
-    ]
-  , testGroup "hexFixedWord16"
-    [ testCase "A" $
-        P.parseBytes (Latin.hexFixedWord16 ()) (bytes "A") @=? P.Failure ()
-    , testCase "B" $
-        P.parseBytes (Latin.hexFixedWord16 ()) (bytes "0A0A") @=? P.Success (Slice 5 0 0x0A0A)
-    , testCase "C" $
-        P.parseBytes (Latin.hexFixedWord16 ()) (bytes "") @=? P.Failure ()
-    , testCase "D" $
-        P.parseBytes (Latin.hexFixedWord16 ()) (bytes "A!A!") @=? P.Failure ()
-    ]
-  , testGroup "hexFixedWord32"
-    [ testCase "A" $
-        P.parseBytes (Latin.hexFixedWord32 ()) (bytes "A") @=? P.Failure ()
-    , testCase "B" $
-        P.parseBytes (Latin.hexFixedWord32 ()) (bytes "0A0A0A0A") @=? P.Success (Slice 9 0 0x0A0A0A0A)
-    , testCase "C" $
-        P.parseBytes (Latin.hexFixedWord32 ()) (bytes "") @=? P.Failure ()
-    , testCase "D" $
-        P.parseBytes (Latin.hexFixedWord32 ()) (bytes "A!A0A0A0") @=? P.Failure ()
-    ]
-  , testGroup "hexFixedWord64"
-    [ testCase "A" $
-        P.parseBytes (Latin.hexFixedWord64 ()) (bytes "ABCD01235678BCDE")
-        @=? P.Success
-        (Slice 17 0 0xABCD01235678BCDE)
-    ]
-  , testGroup "base128-w32"
-    [ testCase "A" $
-        P.Success (Slice 2 0 0x7E)
-        @=?
-        P.parseBytes (Base128.word32 ()) (bytes "\x7E")
-    , testCase "B" $
-        P.Success (Slice 5 0 0x200000)
-        @=?
-        P.parseBytes (Base128.word32 ()) (bytes "\x81\x80\x80\x00")
-    , testCase "C" $
-        P.Success (Slice 4 0 1656614)
-        @=?
-        P.parseBytes (Base128.word32 ()) (bytes "\xE5\x8E\x26")
-    -- , testProperty "iso" $ \w -> -- TODO
-    --     P.parseBytesMaybe (Base.word32 ()) (encodeBase128 (fromIntegral w))
-    --     ===
-    --     Just w
-    ]
-  , testGroup "leb128-w32"
-    [ testCase "A" $
-        P.Success (Slice 2 0 0x7E)
-        @=?
-        P.parseBytes (Leb128.word32 ()) (bytes "\x7E")
-    , testCase "B" $
-        P.Success (Slice 5 0 0x200000)
-        @=?
-        P.parseBytes (Leb128.word32 ()) (bytes "\x80\x80\x80\x01")
-    , testCase "C" $
-        P.Success (Slice 4 0 624485)
-        @=?
-        P.parseBytes (Leb128.word32 ()) (bytes "\xE5\x8E\x26")
-    , testProperty "iso" $ \w -> 
-        P.parseBytesMaybe (Leb128.word32 ()) (encodeLeb128 (fromIntegral w))
-        ===
-        Just w
-    ]
-  , testGroup "leb128-w16"
-    [ testCase "A" $
-        P.Failure ()
-        @=?
-        P.parseBytes (Leb128.word16 ()) (bytes "\x80\x80\x04")
-    , testCase "B" $
-        P.Success (Slice 4 0 0xFFFF)
-        @=?
-        P.parseBytes (Leb128.word16 ()) (bytes "\xFF\xFF\x03")
-    , testProperty "iso" $ \w -> 
-        P.parseBytesMaybe (Leb128.word16 ()) (encodeLeb128 (fromIntegral w))
-        ===
-        Just w
-    ]
-  , testGroup "leb128-i16"
-    [ testProperty "iso" $ \(w :: Int16) -> 
-        P.parseBytesMaybe (Leb128.int16 ())
-          (encodeLeb128 (fromIntegral @Word16 @Natural (zigzag16 w)))
-        ===
-        Just w
-    ]
-  , testGroup "leb128-i32"
-    [ testProperty "iso" $ \(w :: Int32) -> 
-        P.parseBytesMaybe (Leb128.int32 ())
-          (encodeLeb128 (fromIntegral @Word32 @Natural (zigzag32 w)))
-        ===
-        Just w
-    ]
-  , testGroup "satisfy"
-    [ testCase "A" $
-        P.Success (Slice 2 0 0x20)
-        @=?
-        P.parseBytes (P.satisfy () (== 0x20)) (bytes "\x20")
+          @=? Just (Exts.fromList [0x1234567890123456789012345678901212345678901234567890123456789012])
+    , testProperty "big-endian-word64" bigEndianWord64
+    , testProperty "big-endian-word32" bigEndianWord32
+    , testProperty "little-endian-word32" littleEndianWord32
+    , testCase "delimit" $
+        P.Success (Slice 13 0 (167, 14625))
+          @=? P.parseBytes
+            ( do
+                len <- Latin.decUnsignedInt ()
+                Latin.char () ','
+                r <-
+                  P.delimit () () len $
+                    (,)
+                      <$> Latin.decUnsignedInt ()
+                      <* Latin.char () '*'
+                      <*> Latin.decUnsignedInt ()
+                Latin.char () '0'
+                pure r
+            )
+            (bytes "9,167*146250")
+    , testGroup
+        "decUnsignedInt"
+        [ testCase "A" $
+            P.Failure ()
+              @=? P.parseBytes
+                (Latin.decUnsignedInt ())
+                (bytes "742493495120739103935542")
+        , testCase "B" $
+            P.Success (Slice 8 3 4654667)
+              @=? P.parseBytes
+                (Latin.decUnsignedInt ())
+                (bytes "4654667,55")
+        , testCase "C" $
+            P.Failure ()
+              @=? P.parseBytes
+                (Latin.decUnsignedInt ())
+                (bytes ('1' : show (maxBound :: Int)))
+        , testCase "D" $
+            P.Failure ()
+              @=? P.parseBytes
+                (Latin.decUnsignedInt ())
+                (bytes "2481030337885070917891")
+        , testCase "E" $
+            P.Failure ()
+              @=? P.parseBytes
+                (Latin.decUnsignedInt ())
+                (bytes (show (fromIntegral @Int @Word maxBound + 1)))
+        , testCase "F" $ withSz (show (maxBound :: Int)) $ \str len ->
+            P.Success (Slice len 0 maxBound)
+              @=? P.parseBytes (Latin.decUnsignedInt ()) str
+        , testProperty "property" $ \(QC.NonNegative i) ->
+            withSz (show i) $ \str len ->
+              P.parseBytes (Latin.decUnsignedInt ()) str
+                === P.Success (Slice len 0 i)
+        ]
+    , testGroup
+        "hexNibbleLower"
+        [ testCase "A" $
+            P.parseBytes (Latin.hexNibbleLower ()) (bytes "Ab") @=? P.Failure ()
+        , testCase "B" $
+            P.parseBytes (Latin.hexNibbleLower ()) (bytes "bA") @=? P.Success (Slice 2 1 0xb)
+        , testCase "C" $
+            P.parseBytes (Latin.hexNibbleLower ()) (bytes "") @=? P.Failure ()
+        ]
+    , testGroup
+        "tryHexNibbleLower"
+        [ testCase "A" $
+            P.Success @() (Slice 1 2 Nothing)
+              @=? P.parseBytes Latin.tryHexNibbleLower (bytes "Ab")
+        , testCase "B" $
+            P.Success @() (Slice 2 1 (Just 0xb))
+              @=? P.parseBytes Latin.tryHexNibbleLower (bytes "bA")
+        , testCase "C" $
+            P.Success @() (Slice 1 0 Nothing)
+              @=? P.parseBytes Latin.tryHexNibbleLower (bytes "")
+        ]
+    , testGroup
+        "decPositiveInteger"
+        [ testCase "A" $
+            P.parseBytes
+              (Latin.decUnsignedInteger ())
+              (bytes "5469999463123462573426452736423546373235260")
+              @=? P.Success
+                (Slice 44 0 5469999463123462573426452736423546373235260)
+        , testProperty "property" $ \(LargeInteger i) ->
+            withSz (show i) $ \str len ->
+              i
+                >= 0
+                  QC.==> P.parseBytes (Latin.decUnsignedInteger ()) str
+                  === P.Success (Slice len 0 i)
+        ]
+    , testGroup
+        "decTrailingInteger"
+        [ testProperty "property" $ \(LargeInteger i) ->
+            withSz (show i) $ \str sz ->
+              i
+                >= 0
+                  QC.==> P.parseBytes (Latin.decTrailingInteger 2) str
+                  === (P.Success (Slice sz 0 (read ('2' : show i) :: Integer)) :: P.Result () Integer)
+        ]
+    , testGroup
+        "decSignedInteger"
+        [ testCase "A" $
+            P.parseBytes
+              (Latin.decSignedInteger ())
+              (bytes "-54699994631234625734264527364235463732352601")
+              @=? P.Success
+                ( Slice
+                    46
+                    0
+                    (-54699994631234625734264527364235463732352601)
+                )
+        , testCase "B" $
+            P.Success (Slice 25 0 (3, (-206173954435705292503)))
+              @=? P.parseBytes
+                ( pure (,)
+                    <*> Latin.decSignedInteger ()
+                    <* Latin.char () 'e'
+                    <*> Latin.decSignedInteger ()
+                )
+                (bytes "3e-206173954435705292503")
+        , testProperty "property" $ \(LargeInteger i) ->
+            withSz (show i) $ \str len ->
+              P.parseBytes (Latin.decSignedInteger ()) str
+                === P.Success (Slice len 0 i)
+        ]
+    , testGroup
+        "decSignedInt"
+        [ testProperty "A" $ \i -> withSz (show i) $ \str len ->
+            P.parseBytes (Latin.decSignedInt ()) str
+              === P.Success (Slice len 0 i)
+        , testProperty "B" $ \i ->
+            let s = (if i >= 0 then "+" else "") ++ show i
+             in withSz s $ \str len ->
+                  P.parseBytes (Latin.decSignedInt ()) str
+                    === P.Success (Slice len 0 i)
+        , testCase "C" $
+            P.Failure ()
+              @=? P.parseBytes
+                (Latin.decSignedInt ())
+                (bytes ('1' : show (maxBound :: Int)))
+        , testCase "D" $
+            P.Failure ()
+              @=? P.parseBytes
+                (Latin.decSignedInt ())
+                (bytes ('-' : '3' : show (maxBound :: Int)))
+        , testCase "E" $
+            P.Failure ()
+              @=? P.parseBytes
+                (Latin.decSignedInt ())
+                (bytes "2481030337885070917891")
+        , testCase "F" $
+            P.Failure ()
+              @=? P.parseBytes
+                (Latin.decSignedInt ())
+                (bytes "-4305030950553840988981")
+        , testCase "G" $ withSz (show (minBound :: Int)) $ \str len ->
+            P.Success (Slice len 0 minBound)
+              @=? P.parseBytes (Latin.decSignedInt ()) str
+        , testCase "H" $ withSz (show (maxBound :: Int)) $ \str len ->
+            P.Success (Slice len 0 maxBound)
+              @=? P.parseBytes (Latin.decSignedInt ()) str
+        , testCase "I" $
+            P.Failure ()
+              @=? P.parseBytes
+                (Latin.decSignedInt ())
+                (bytes (show (fromIntegral @Int @Word maxBound + 1)))
+        , testCase "J" $
+            -- This is one number lower than the minimum bound for
+            -- a signed 64-bit number, but this test will pass on
+            -- 32-bit architectures as well.
+            P.Failure ()
+              @=? P.parseBytes
+                (Latin.decSignedInt ())
+                (bytes "-9223372036854775809")
+        ]
+    , testGroup
+        "decWord64"
+        [ testCase "A" $
+            P.Failure ()
+              @=? P.parseBytes
+                (Latin.decWord64 ())
+                (bytes "2481030337885070917891")
+        ]
+    , testCase "decWord-composition" $
+        P.Success (Slice 6 0 (42, 8))
+          @=? P.parseBytes
+            ( pure (,)
+                <*> Ascii.decWord ()
+                <* Ascii.char () '.'
+                <*> Ascii.decWord ()
+                <* Ascii.char () '.'
+            )
+            (bytes "42.8.")
+    , testCase "decWord-replicate" $
+        P.Success (Slice 7 0 (Exts.fromList [42, 93] :: PrimArray Word))
+          @=? P.parseBytes
+            (P.replicate 2 (Ascii.decWord () <* Ascii.char () '.'))
+            (bytes "42.93.")
+    , testCase "ascii-takeShortWhile" $
+        P.Success (Slice 11 0 (Exts.fromList ["the", "world"] :: PM.Array ShortText))
+          @=? P.parseBytes
+            (P.replicate 2 (Ascii.takeShortWhile (/= ',') <* Ascii.char () ','))
+            (bytes "the,world,")
+    , testGroup
+        "hexFixedWord8"
+        [ testCase "A" $
+            P.parseBytes (Latin.hexFixedWord8 ()) (bytes "A") @=? P.Failure ()
+        , testCase "B" $
+            P.parseBytes (Latin.hexFixedWord8 ()) (bytes "0A") @=? P.Success (Slice 3 0 0x0A)
+        , testCase "C" $
+            P.parseBytes (Latin.hexFixedWord8 ()) (bytes "") @=? P.Failure ()
+        , testCase "D" $
+            P.parseBytes (Latin.hexFixedWord8 ()) (bytes "A!") @=? P.Failure ()
+        ]
+    , testGroup
+        "hexFixedWord16"
+        [ testCase "A" $
+            P.parseBytes (Latin.hexFixedWord16 ()) (bytes "A") @=? P.Failure ()
+        , testCase "B" $
+            P.parseBytes (Latin.hexFixedWord16 ()) (bytes "0A0A") @=? P.Success (Slice 5 0 0x0A0A)
+        , testCase "C" $
+            P.parseBytes (Latin.hexFixedWord16 ()) (bytes "") @=? P.Failure ()
+        , testCase "D" $
+            P.parseBytes (Latin.hexFixedWord16 ()) (bytes "A!A!") @=? P.Failure ()
+        ]
+    , testGroup
+        "hexFixedWord32"
+        [ testCase "A" $
+            P.parseBytes (Latin.hexFixedWord32 ()) (bytes "A") @=? P.Failure ()
+        , testCase "B" $
+            P.parseBytes (Latin.hexFixedWord32 ()) (bytes "0A0A0A0A") @=? P.Success (Slice 9 0 0x0A0A0A0A)
+        , testCase "C" $
+            P.parseBytes (Latin.hexFixedWord32 ()) (bytes "") @=? P.Failure ()
+        , testCase "D" $
+            P.parseBytes (Latin.hexFixedWord32 ()) (bytes "A!A0A0A0") @=? P.Failure ()
+        ]
+    , testGroup
+        "hexFixedWord64"
+        [ testCase "A" $
+            P.parseBytes (Latin.hexFixedWord64 ()) (bytes "ABCD01235678BCDE")
+              @=? P.Success
+                (Slice 17 0 0xABCD01235678BCDE)
+        ]
+    , testGroup
+        "base128-w32"
+        [ testCase "A" $
+            P.Success (Slice 2 0 0x7E)
+              @=? P.parseBytes (Base128.word32 ()) (bytes "\x7E")
+        , testCase "B" $
+            P.Success (Slice 5 0 0x200000)
+              @=? P.parseBytes (Base128.word32 ()) (bytes "\x81\x80\x80\x00")
+        , testCase "C" $
+            P.Success (Slice 4 0 1656614)
+              @=? P.parseBytes (Base128.word32 ()) (bytes "\xE5\x8E\x26")
+              -- , testProperty "iso" $ \w -> -- TODO
+              --     P.parseBytesMaybe (Base.word32 ()) (encodeBase128 (fromIntegral w))
+              --     ===
+              --     Just w
+        ]
+    , testGroup
+        "leb128-w32"
+        [ testCase "A" $
+            P.Success (Slice 2 0 0x7E)
+              @=? P.parseBytes (Leb128.word32 ()) (bytes "\x7E")
+        , testCase "B" $
+            P.Success (Slice 5 0 0x200000)
+              @=? P.parseBytes (Leb128.word32 ()) (bytes "\x80\x80\x80\x01")
+        , testCase "C" $
+            P.Success (Slice 4 0 624485)
+              @=? P.parseBytes (Leb128.word32 ()) (bytes "\xE5\x8E\x26")
+        , testProperty "iso" $ \w ->
+            P.parseBytesMaybe (Leb128.word32 ()) (encodeLeb128 (fromIntegral w))
+              === Just w
+        ]
+    , testGroup
+        "leb128-w16"
+        [ testCase "A" $
+            P.Failure ()
+              @=? P.parseBytes (Leb128.word16 ()) (bytes "\x80\x80\x04")
+        , testCase "B" $
+            P.Success (Slice 4 0 0xFFFF)
+              @=? P.parseBytes (Leb128.word16 ()) (bytes "\xFF\xFF\x03")
+        , testProperty "iso" $ \w ->
+            P.parseBytesMaybe (Leb128.word16 ()) (encodeLeb128 (fromIntegral w))
+              === Just w
+        ]
+    , testGroup
+        "leb128-i16"
+        [ testProperty "iso" $ \(w :: Int16) ->
+            P.parseBytesMaybe
+              (Leb128.int16 ())
+              (encodeLeb128 (fromIntegral @Word16 @Natural (zigzag16 w)))
+              === Just w
+        ]
+    , testGroup
+        "leb128-i32"
+        [ testProperty "iso" $ \(w :: Int32) ->
+            P.parseBytesMaybe
+              (Leb128.int32 ())
+              (encodeLeb128 (fromIntegral @Word32 @Natural (zigzag32 w)))
+              === Just w
+        ]
+    , testGroup
+        "satisfy"
+        [ testCase "A" $
+            P.Success (Slice 2 0 0x20)
+              @=? P.parseBytes (P.satisfy () (== 0x20)) (bytes "\x20")
+        ]
     ]
-  ]
 
 bytes :: String -> Bytes
 bytes s = let b = pack ('x' : s) in Bytes b 1 (PM.sizeofByteArray b - 1)
@@ -451,9 +461,15 @@
 pack = Exts.fromList . map (fromIntegral @Int @Word8 . ord)
 
 bigEndianWord64 ::
-     Word8 -> Word8 -> Word8 -> Word8
-  -> Word8 -> Word8 -> Word8 -> Word8
-  -> QC.Property
+  Word8 ->
+  Word8 ->
+  Word8 ->
+  Word8 ->
+  Word8 ->
+  Word8 ->
+  Word8 ->
+  Word8 ->
+  QC.Property
 bigEndianWord64 a b c d e f g h =
   let arr = runST $ do
         m <- PM.newByteArray 11
@@ -469,22 +485,25 @@
         PM.writeByteArray m 9 (h :: Word8)
         PM.writeByteArray m 10 (0xEE :: Word8)
         PM.unsafeFreezeByteArray m
-      expected = (0 :: Word64)
-        + fromIntegral a * 256 ^ (7 :: Integer)
-        + fromIntegral b * 256 ^ (6 :: Integer)
-        + fromIntegral c * 256 ^ (5 :: Integer)
-        + fromIntegral d * 256 ^ (4 :: Integer)
-        + fromIntegral e * 256 ^ (3 :: Integer)
-        + fromIntegral f * 256 ^ (2 :: Integer)
-        + fromIntegral g * 256 ^ (1 :: Integer)
-        + fromIntegral h * 256 ^ (0 :: Integer)
+      expected =
+        (0 :: Word64)
+          + fromIntegral a * 256 ^ (7 :: Integer)
+          + fromIntegral b * 256 ^ (6 :: Integer)
+          + fromIntegral c * 256 ^ (5 :: Integer)
+          + fromIntegral d * 256 ^ (4 :: Integer)
+          + fromIntegral e * 256 ^ (3 :: Integer)
+          + fromIntegral f * 256 ^ (2 :: Integer)
+          + fromIntegral g * 256 ^ (1 :: Integer)
+          + fromIntegral h * 256 ^ (0 :: Integer)
    in P.parseBytes (BigEndian.word64 ()) (Bytes arr 2 9)
-      ===
-      P.Success (Slice 10 1 expected)
+        === P.Success (Slice 10 1 expected)
 
 bigEndianWord32 ::
-     Word8 -> Word8 -> Word8 -> Word8
-  -> QC.Property
+  Word8 ->
+  Word8 ->
+  Word8 ->
+  Word8 ->
+  QC.Property
 bigEndianWord32 a b c d =
   let arr = runST $ do
         m <- PM.newByteArray 7
@@ -496,18 +515,21 @@
         PM.writeByteArray m 5 (d :: Word8)
         PM.writeByteArray m 6 (0xEE :: Word8)
         PM.unsafeFreezeByteArray m
-      expected = (0 :: Word32)
-        + fromIntegral a * 256 ^ (3 :: Integer)
-        + fromIntegral b * 256 ^ (2 :: Integer)
-        + fromIntegral c * 256 ^ (1 :: Integer)
-        + fromIntegral d * 256 ^ (0 :: Integer)
+      expected =
+        (0 :: Word32)
+          + fromIntegral a * 256 ^ (3 :: Integer)
+          + fromIntegral b * 256 ^ (2 :: Integer)
+          + fromIntegral c * 256 ^ (1 :: Integer)
+          + fromIntegral d * 256 ^ (0 :: Integer)
    in P.parseBytes (BigEndian.word32 ()) (Bytes arr 2 5)
-      ===
-      P.Success (Slice 6 1 expected)
+        === P.Success (Slice 6 1 expected)
 
 littleEndianWord32 ::
-     Word8 -> Word8 -> Word8 -> Word8
-  -> QC.Property
+  Word8 ->
+  Word8 ->
+  Word8 ->
+  Word8 ->
+  QC.Property
 littleEndianWord32 a b c d =
   let arr = runST $ do
         m <- PM.newByteArray 7
@@ -519,33 +541,34 @@
         PM.writeByteArray m 5 (d :: Word8)
         PM.writeByteArray m 6 (0xEE :: Word8)
         PM.unsafeFreezeByteArray m
-      expected = (0 :: Word32)
-        + fromIntegral a * 256 ^ (0 :: Integer)
-        + fromIntegral b * 256 ^ (1 :: Integer)
-        + fromIntegral c * 256 ^ (2 :: Integer)
-        + fromIntegral d * 256 ^ (3 :: Integer)
+      expected =
+        (0 :: Word32)
+          + fromIntegral a * 256 ^ (0 :: Integer)
+          + fromIntegral b * 256 ^ (1 :: Integer)
+          + fromIntegral c * 256 ^ (2 :: Integer)
+          + fromIntegral d * 256 ^ (3 :: Integer)
    in P.parseBytes (LittleEndian.word32 ()) (Bytes arr 2 5)
-      ===
-      P.Success (Slice 6 1 expected)
+        === P.Success (Slice 6 1 expected)
 
 -- The Arbitrary instance for Integer that comes with
 -- QuickCheck only generates small numbers.
 newtype LargeInteger = LargeInteger Integer
-  deriving (Eq,Show)
+  deriving (Eq, Show)
 
 instance QC.Arbitrary Word128 where
   arbitrary = liftA2 Word128 QC.arbitrary QC.arbitrary
 
 instance QC.Arbitrary LargeInteger where
   arbitrary = do
-      n <- QC.choose (1, 27)
-      sign <- QC.arbitrary
-      r <- (if sign then negate else id) . foldr f 0
+    n <- QC.choose (1, 27)
+    sign <- QC.arbitrary
+    r <-
+      (if sign then negate else id) . foldr f 0
         <$> replicateM n QC.arbitrary
-      pure (LargeInteger r)
-    where
-      f :: Word8 -> Integer -> Integer
-      f w acc = (acc `Bits.shiftL` 8) + fromIntegral w
+    pure (LargeInteger r)
+   where
+    f :: Word8 -> Integer -> Integer
+    f w acc = (acc `Bits.shiftL` 8) + fromIntegral w
 
 -- We add an extra 1 since bytes gives us a slice that
 -- starts at that offset.
@@ -556,15 +579,17 @@
 untype (PrimArray x) = ByteArray x
 
 encodeLeb128 :: Natural -> Bytes
-encodeLeb128 x = Bytes.unsafeDrop 1 (Exts.fromList (0xFF : go [] x)) where
+encodeLeb128 x = Bytes.unsafeDrop 1 (Exts.fromList (0xFF : go [] x))
+ where
   go !xs !n =
-    let (q,r) = quotRem n 128
+    let (q, r) = quotRem n 128
         r' = fromIntegral @Natural @Word8 r
-        w = if q == 0
-          then r'
-          else Bits.setBit r' 7
+        w =
+          if q == 0
+            then r'
+            else Bits.setBit r' 7
         xs' = w : xs
-     in if q == 0 
+     in if q == 0
           then List.reverse xs'
           else go xs' q
 
