packages feed

bytesmith 0.3.1.0 → 0.3.2.0

raw patch · 3 files changed

+113/−3 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.Bytes.Parser: parseBytesEither :: forall e a. (forall s. Parser e s a) -> Bytes -> Either e a
+ Data.Bytes.Parser: parseBytesMaybe :: forall e a. (forall s. Parser e s a) -> Bytes -> Maybe a
+ Data.Bytes.Parser: peek :: Parser e s (Maybe Word8)
+ Data.Bytes.Parser: peek' :: e -> Parser e s Word8
+ Data.Bytes.Parser: satisfy :: e -> (Word8 -> Bool) -> Parser e s Word8
+ Data.Bytes.Parser: satisfyWith :: e -> (Word8 -> a) -> (a -> Bool) -> Parser e s a
+ Data.Bytes.Parser: scan :: state -> (state -> Word8 -> Maybe state) -> Parser e s state

Files

CHANGELOG.md view
@@ -1,5 +1,11 @@ # Revision history for bytesmith +## 0.3.2.0 -- 2019-??-??++* Add `parseBytesEither` and `parseBytesMaybe`.+* Add common idioms from other parser libaries. This includes: `satisfy`,+  `satisfyWith`, `scan`, `peek`, and `peek'`.+ ## 0.3.1.0 -- 2019-11-12  * Add big-endian and little-endian parsers for `Word128`.
bytesmith.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: bytesmith-version: 0.3.1.0+version: 0.3.2.0 synopsis: Nonresumable byte parser description:   Parse bytes as fast as possible. This is a nonresumable parser@@ -31,7 +31,7 @@   build-depends:     , base >=4.12 && <5     , bytestring >=0.10.8 && <0.11-    , byteslice >=0.1.3 && <0.2+    , byteslice >=0.1.3 && <0.3     , contiguous >= 0.4 && < 0.6     , primitive >=0.7 && <0.8     , text-short >=0.1.3 && <0.2
src/Data/Bytes/Parser.hs view
@@ -26,9 +26,12 @@   , Result(..)   , Slice(..)     -- * Run Parsers+    -- ** Result   , parseByteArray   , parseBytes   , parseBytesEffectfully+  , parseBytesEither+  , parseBytesMaybe     -- * One Byte   , any     -- * Many Bytes@@ -41,10 +44,17 @@     -- * Match   , byteArray   , bytes+  , satisfy+  , satisfyWith     -- * End of Input   , endOfInput   , isEndOfInput   , remaining+    -- * Scanning+  , scan+    -- * Lookahead+  , peek+  , peek'     -- * Control Flow   , fail   , orElse@@ -99,7 +109,7 @@ import qualified Data.Primitive as PM import qualified Data.Primitive.Contiguous as C --- | Parse a slice of a byte array. This can succeed even if the+-- | 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 parseBytes p !b = runResultST action@@ -108,6 +118,38 @@   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.+parseBytesMaybe :: forall e a. (forall s. Parser e s a) -> Bytes -> Maybe a+parseBytesMaybe p !b = runMaybeST action+  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.+parseBytesEither :: forall e a. (forall s. Parser e s a) -> Bytes -> Either e a+parseBytesEither p !b = runEitherST action+  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+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+runEitherST f = case (runRW# (\s0 -> case f s0 of { (# _, r #) -> r })) of+  (# e | #) -> Left e+  (# | (# x, _, _ #) #) -> Right x+ -- This is used internally to help reduce boxing when a parser -- gets run. Due to the late inlining of runRW#, this variant -- of runST still cause the result value to be boxed. However,@@ -172,6 +214,49 @@      in InternalSuccess w (offset chunk + 1) (length chunk - 1)   else InternalFailure 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.+peek :: Parser e s (Maybe Word8)+peek = uneffectful $ \chunk ->+  let v = if length chunk > 0+        then Just (B.unsafeIndex chunk 1)+        else Nothing+  in InternalSuccess v (offset chunk) (length chunk)++-- | Match any byte, to perform lookahead. Does not consume any+--   input, but will fail if end of input has been reached.+peek' :: e -> Parser e s Word8+peek' e = uneffectful $ \chunk -> if length chunk > 0+  then InternalSuccess (B.unsafeIndex chunk 1) (offset chunk) (length chunk)+  else InternalFailure 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.+scan :: state -> (state -> Word8 -> Maybe state) -> Parser e s state+scan s0 t = do+  let go s = do+        mw <- peek+        case mw of+          Nothing -> pure s+          Just w -> case t s w of+            Just s' -> go s'+            Nothing -> pure s+  go s0+ -- Interpret the next byte as an ASCII-encoded character. -- Does not check to see if any characters are left. This -- is not exported.@@ -246,6 +331,25 @@         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.+satisfy :: e -> (Word8 -> Bool) -> Parser e s Word8+satisfy e p = satisfyWith e id p+{-# 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.+satisfyWith :: e -> (Word8 -> a) -> (a -> Bool) -> Parser e s a+satisfyWith e f p = uneffectful $ \chunk -> if length chunk > 1+  then case B.unsafeIndex chunk 1 of+    w ->+      let v = f w+      in if p v+        then InternalSuccess v (offset chunk + 1) (length chunk - 1)+        else InternalFailure e+  else InternalFailure e  -- | Fails if there is still more input remaining. endOfInput :: e -> Parser e s ()