content: -- | Folds for byte streams
  
  module Control.Foldl.ByteString (
      -- * Folding
        fold
      , foldM
  
      -- * Folds
      , head
      , last
      , null
      , length
      , any
      , all
      , maximum
      , minimum
      , elem
      , notElem
      , find
      , index
      , elemIndex
      , findIndex
      , count
      , lazy
  
      -- * Re-exports
      -- $reexports
      , module Control.Foldl
      , module Data.ByteString
      , module Data.Word
      ) where
  
  import Control.Foldl (Fold, FoldM)
  import Control.Foldl.Internal (Maybe'(..), strict, Either'(..), hush)
  import Data.ByteString (ByteString)
  import Data.Word (Word8)
  import Prelude hiding (
      head, last, null, length, any, all, maximum, minimum, elem, notElem )
  
  import qualified Control.Foldl
  import qualified Control.Foldl.Internal
  import qualified Data.ByteString
  import qualified Data.ByteString.Lazy.Internal
  import qualified Data.ByteString.Unsafe
  import qualified Data.ByteString.Lazy
  
  -- | Apply a strict left 'Fold' to a lazy bytestring
  fold :: Fold ByteString a -> Data.ByteString.Lazy.ByteString -> a
  fold (Control.Foldl.Fold step begin done) as =
      done (Data.ByteString.Lazy.Internal.foldlChunks step begin as)
  {-# INLINABLE fold #-}
  
  -- | Apply a strict monadic left 'FoldM' to a lazy bytestring
  foldM
      :: Monad m => FoldM m ByteString a -> Data.ByteString.Lazy.ByteString -> m a
  foldM (Control.Foldl.FoldM step begin done) as = do
      x <- Data.ByteString.Lazy.Internal.foldlChunks step' begin as
      done x
    where
      step' mx bs = do
        x <- mx
        x `seq` step x bs
  {-# INLINABLE foldM #-}
  
  {-| Get the first byte of a byte stream or return 'Nothing' if the stream is
      empty
  -}
  head :: Fold ByteString (Maybe Word8)
  head = Control.Foldl.Fold step Nothing' Control.Foldl.Internal.lazy
    where
      step mw8 bs =
          if Data.ByteString.null bs
          then mw8
          else case mw8 of
              Just' _  -> mw8
              Nothing' -> Just' (Data.ByteString.Unsafe.unsafeHead bs)
  {-# INLINABLE head #-}
  
  {-| Get the last byte of a byte stream or return 'Nothing' if the byte stream is
      empty
  -}
  last :: Fold ByteString (Maybe Word8)
  last = Control.Foldl.Fold step Nothing' Control.Foldl.Internal.lazy
    where
      step mw8 bs =
          if Data.ByteString.null bs
          then mw8
          else Just' (Data.ByteString.last bs)
          -- TODO: Use `unsafeLast` when Debian Stable Haskell Platform has it
  {-# INLINABLE last #-}
  
  -- | Returns 'True' if the byte stream is empty, 'False' otherwise
  null :: Fold ByteString Bool
  null = Control.Foldl.Fold step True id
    where
      step isNull bs = isNull && Data.ByteString.null bs
  {-# INLINABLE null #-}
  
  -- | Return the length of the byte stream in bytes
  length :: Num n => Fold ByteString n
  length = Control.Foldl.Fold step 0 id
    where
      step n bs = n + fromIntegral (Data.ByteString.length bs)
  {-# INLINABLE length #-}
  
  {-| @(all predicate)@ returns 'True' if all bytes satisfy the predicate, 'False'
      otherwise
  -}
  all :: (Word8 -> Bool) -> Fold ByteString Bool
  all predicate =
      Control.Foldl.Fold (\b bs -> b && Data.ByteString.all predicate bs) True id
  {-# INLINABLE all #-}
  
  {-| @(any predicate)@ returns 'True' if any byte satisfies the predicate,
      'False' otherwise
  -}
  any :: (Word8 -> Bool) -> Fold ByteString Bool
  any predicate =
      Control.Foldl.Fold (\b bs -> b || Data.ByteString.any predicate bs) False id
  {-# INLINABLE any #-}
  
  -- | Computes the maximum byte
  maximum :: Fold ByteString (Maybe Word8)
  maximum = Control.Foldl.Fold step Nothing' Control.Foldl.Internal.lazy
    where
      step mw8 bs =
          if Data.ByteString.null bs
          then mw8
          else Just' (case mw8 of
              Nothing' -> Data.ByteString.maximum bs
              Just' w8 -> max w8 (Data.ByteString.maximum bs) )
  {-# INLINABLE maximum #-}
  
  -- | Computes the minimum byte
  minimum :: Fold ByteString (Maybe Word8)
  minimum = Control.Foldl.Fold step Nothing' Control.Foldl.Internal.lazy
    where
      step mw8 bs =
          if Data.ByteString.null bs
          then mw8
          else Just' (case mw8 of
              Nothing' -> Data.ByteString.minimum bs
              Just' w8 -> min w8 (Data.ByteString.minimum bs) )
  {-# INLINABLE minimum #-}
  
  {-| @(elem w8)@ returns 'True' if the byte stream has a byte equal to @w8@,
      'False' otherwise
  -}
  elem :: Word8 -> Fold ByteString Bool
  elem w8 = any (w8 ==)
  {-# INLINABLE elem #-}
  
  {-| @(notElem w8)@ returns 'False' if the byte stream has a byte equal to @w8@,
      'True' otherwise
  -}
  notElem :: Word8 -> Fold ByteString Bool
  notElem w8 = all (w8 /=)
  {-# INLINABLE notElem #-}
  
  {-| @(find predicate)@ returns the first byte that satisfies the predicate or
      'Nothing' if no byte satisfies the predicate
  -}
  find :: (Word8 -> Bool) -> Fold ByteString (Maybe Word8)
  find predicate = Control.Foldl.Fold step Nothing' Control.Foldl.Internal.lazy
    where
      step mw8 bs = case mw8 of
          Nothing' -> strict (Data.ByteString.find predicate bs)
          Just' _  -> mw8
  {-# INLINABLE find #-}
  
  {-| @(index n)@ returns the @n@th byte of the byte stream, or 'Nothing' if the
      stream has an insufficient number of bytes
  -}
  index :: Integral n => n -> Fold ByteString (Maybe Word8)
  index i = Control.Foldl.Fold step (Left' (fromIntegral i)) hush
    where
      step x bs = case x of
          Left' remainder ->
              let len = Data.ByteString.length bs
              in  if remainder < len
                  then Right' (Data.ByteString.Unsafe.unsafeIndex bs remainder)
                  else Left'  (remainder - len)
          _               -> x
  {-# INLINABLE index #-}
  
  {-| @(elemIndex w8)@ returns the index of the first byte that equals @w8@, or
      'Nothing' if no byte matches
  -}
  elemIndex :: Num n => Word8 -> Fold ByteString (Maybe n)
  elemIndex w8 = findIndex (w8 ==)
  {-# INLINABLE elemIndex #-}
  
  {-| @(findIndex predicate)@ returns the index of the first byte that satisfies
      the predicate, or 'Nothing' if no byte satisfies the predicate
  -}
  findIndex :: Num n => (Word8 -> Bool) -> Fold ByteString (Maybe n)
  findIndex predicate = Control.Foldl.Fold step (Left' 0) hush
    where
      step x bs = case x of
          Left' m -> case Data.ByteString.findIndex predicate bs of
              Nothing -> Left'  (m + fromIntegral (Data.ByteString.length bs))
              Just n  -> Right' (m + fromIntegral n)
          _       -> x
  {-# INLINABLE findIndex #-}
  
  -- | @count w8@ returns the number of times @w8@ appears
  count :: Num n => Word8 -> Fold ByteString n
  count w8 = Control.Foldl.Fold step 0 id
    where
      step n bs = n + fromIntegral (Data.ByteString.count w8 bs)
  {-# INLINABLE count #-}
  
  -- | Combine all the strict `ByteString` chunks to build a lazy `ByteString`
  lazy :: Fold ByteString Data.ByteString.Lazy.ByteString
  lazy = fmap Data.ByteString.Lazy.fromChunks Control.Foldl.list
  {-# INLINABLE lazy #-}
  
  -- | 
  
  {- $reexports
  
      "Control.Foldl" re-exports the 'Fold' type
  
      @Data.ByteString@ re-exports the 'ByteString' type
  
      @Data.Word@ re-exports the 'Word8' type
  -}
  