-- | 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 :: Fold ByteString a -> ByteString -> a
fold (Control.Foldl.Fold x -> ByteString -> x
step x
begin x -> a
done) ByteString
as =
    x -> a
done ((x -> ByteString -> x) -> x -> ByteString -> x
forall a. (a -> ByteString -> a) -> a -> ByteString -> a
Data.ByteString.Lazy.Internal.foldlChunks x -> ByteString -> x
step x
begin ByteString
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 :: FoldM m ByteString a -> ByteString -> m a
foldM (Control.Foldl.FoldM x -> ByteString -> m x
step m x
begin x -> m a
done) ByteString
as = do
    x
x <- (m x -> ByteString -> m x) -> m x -> ByteString -> m x
forall a. (a -> ByteString -> a) -> a -> ByteString -> a
Data.ByteString.Lazy.Internal.foldlChunks m x -> ByteString -> m x
step' m x
begin ByteString
as
    x -> m a
done x
x
  where
    step' :: m x -> ByteString -> m x
step' m x
mx ByteString
bs = do
      x
x <- m x
mx
      x
x x -> m x -> m x
`seq` x -> ByteString -> m x
step x
x ByteString
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 :: Fold ByteString (Maybe Word8)
head = (Maybe' Word8 -> ByteString -> Maybe' Word8)
-> Maybe' Word8
-> (Maybe' Word8 -> Maybe Word8)
-> Fold ByteString (Maybe Word8)
forall a b x. (x -> a -> x) -> x -> (x -> b) -> Fold a b
Control.Foldl.Fold Maybe' Word8 -> ByteString -> Maybe' Word8
step Maybe' Word8
forall a. Maybe' a
Nothing' Maybe' Word8 -> Maybe Word8
forall a. Maybe' a -> Maybe a
Control.Foldl.Internal.lazy
  where
    step :: Maybe' Word8 -> ByteString -> Maybe' Word8
step Maybe' Word8
mw8 ByteString
bs =
        if ByteString -> Bool
Data.ByteString.null ByteString
bs
        then Maybe' Word8
mw8
        else case Maybe' Word8
mw8 of
            Just' Word8
_  -> Maybe' Word8
mw8
            Maybe' Word8
Nothing' -> Word8 -> Maybe' Word8
forall a. a -> Maybe' a
Just' (ByteString -> Word8
Data.ByteString.Unsafe.unsafeHead ByteString
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 :: Fold ByteString (Maybe Word8)
last = (Maybe' Word8 -> ByteString -> Maybe' Word8)
-> Maybe' Word8
-> (Maybe' Word8 -> Maybe Word8)
-> Fold ByteString (Maybe Word8)
forall a b x. (x -> a -> x) -> x -> (x -> b) -> Fold a b
Control.Foldl.Fold Maybe' Word8 -> ByteString -> Maybe' Word8
step Maybe' Word8
forall a. Maybe' a
Nothing' Maybe' Word8 -> Maybe Word8
forall a. Maybe' a -> Maybe a
Control.Foldl.Internal.lazy
  where
    step :: Maybe' Word8 -> ByteString -> Maybe' Word8
step Maybe' Word8
mw8 ByteString
bs =
        if ByteString -> Bool
Data.ByteString.null ByteString
bs
        then Maybe' Word8
mw8
        else Word8 -> Maybe' Word8
forall a. a -> Maybe' a
Just' (ByteString -> Word8
Data.ByteString.last ByteString
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 :: Fold ByteString Bool
null = (Bool -> ByteString -> Bool)
-> Bool -> (Bool -> Bool) -> Fold ByteString Bool
forall a b x. (x -> a -> x) -> x -> (x -> b) -> Fold a b
Control.Foldl.Fold Bool -> ByteString -> Bool
step Bool
True Bool -> Bool
forall a. a -> a
id
  where
    step :: Bool -> ByteString -> Bool
step Bool
isNull ByteString
bs = Bool
isNull Bool -> Bool -> Bool
&& ByteString -> Bool
Data.ByteString.null ByteString
bs
{-# INLINABLE null #-}

-- | Return the length of the byte stream in bytes
length :: Num n => Fold ByteString n
length :: Fold ByteString n
length = (n -> ByteString -> n) -> n -> (n -> n) -> Fold ByteString n
forall a b x. (x -> a -> x) -> x -> (x -> b) -> Fold a b
Control.Foldl.Fold n -> ByteString -> n
forall a. Num a => a -> ByteString -> a
step n
0 n -> n
forall a. a -> a
id
  where
    step :: a -> ByteString -> a
step a
n ByteString
bs = a
n a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int
Data.ByteString.length ByteString
bs)
{-# INLINABLE length #-}

{-| @(all predicate)@ returns 'True' if all bytes satisfy the predicate, 'False'
    otherwise
-}
all :: (Word8 -> Bool) -> Fold ByteString Bool
all :: (Word8 -> Bool) -> Fold ByteString Bool
all Word8 -> Bool
predicate =
    (Bool -> ByteString -> Bool)
-> Bool -> (Bool -> Bool) -> Fold ByteString Bool
forall a b x. (x -> a -> x) -> x -> (x -> b) -> Fold a b
Control.Foldl.Fold (\Bool
b ByteString
bs -> Bool
b Bool -> Bool -> Bool
&& (Word8 -> Bool) -> ByteString -> Bool
Data.ByteString.all Word8 -> Bool
predicate ByteString
bs) Bool
True Bool -> Bool
forall a. a -> a
id
{-# INLINABLE all #-}

{-| @(any predicate)@ returns 'True' if any byte satisfies the predicate,
    'False' otherwise
-}
any :: (Word8 -> Bool) -> Fold ByteString Bool
any :: (Word8 -> Bool) -> Fold ByteString Bool
any Word8 -> Bool
predicate =
    (Bool -> ByteString -> Bool)
-> Bool -> (Bool -> Bool) -> Fold ByteString Bool
forall a b x. (x -> a -> x) -> x -> (x -> b) -> Fold a b
Control.Foldl.Fold (\Bool
b ByteString
bs -> Bool
b Bool -> Bool -> Bool
|| (Word8 -> Bool) -> ByteString -> Bool
Data.ByteString.any Word8 -> Bool
predicate ByteString
bs) Bool
False Bool -> Bool
forall a. a -> a
id
{-# INLINABLE any #-}

-- | Computes the maximum byte
maximum :: Fold ByteString (Maybe Word8)
maximum :: Fold ByteString (Maybe Word8)
maximum = (Maybe' Word8 -> ByteString -> Maybe' Word8)
-> Maybe' Word8
-> (Maybe' Word8 -> Maybe Word8)
-> Fold ByteString (Maybe Word8)
forall a b x. (x -> a -> x) -> x -> (x -> b) -> Fold a b
Control.Foldl.Fold Maybe' Word8 -> ByteString -> Maybe' Word8
step Maybe' Word8
forall a. Maybe' a
Nothing' Maybe' Word8 -> Maybe Word8
forall a. Maybe' a -> Maybe a
Control.Foldl.Internal.lazy
  where
    step :: Maybe' Word8 -> ByteString -> Maybe' Word8
step Maybe' Word8
mw8 ByteString
bs =
        if ByteString -> Bool
Data.ByteString.null ByteString
bs
        then Maybe' Word8
mw8
        else Word8 -> Maybe' Word8
forall a. a -> Maybe' a
Just' (case Maybe' Word8
mw8 of
            Maybe' Word8
Nothing' -> ByteString -> Word8
Data.ByteString.maximum ByteString
bs
            Just' Word8
w8 -> Word8 -> Word8 -> Word8
forall a. Ord a => a -> a -> a
max Word8
w8 (ByteString -> Word8
Data.ByteString.maximum ByteString
bs) )
{-# INLINABLE maximum #-}

-- | Computes the minimum byte
minimum :: Fold ByteString (Maybe Word8)
minimum :: Fold ByteString (Maybe Word8)
minimum = (Maybe' Word8 -> ByteString -> Maybe' Word8)
-> Maybe' Word8
-> (Maybe' Word8 -> Maybe Word8)
-> Fold ByteString (Maybe Word8)
forall a b x. (x -> a -> x) -> x -> (x -> b) -> Fold a b
Control.Foldl.Fold Maybe' Word8 -> ByteString -> Maybe' Word8
step Maybe' Word8
forall a. Maybe' a
Nothing' Maybe' Word8 -> Maybe Word8
forall a. Maybe' a -> Maybe a
Control.Foldl.Internal.lazy
  where
    step :: Maybe' Word8 -> ByteString -> Maybe' Word8
step Maybe' Word8
mw8 ByteString
bs =
        if ByteString -> Bool
Data.ByteString.null ByteString
bs
        then Maybe' Word8
mw8
        else Word8 -> Maybe' Word8
forall a. a -> Maybe' a
Just' (case Maybe' Word8
mw8 of
            Maybe' Word8
Nothing' -> ByteString -> Word8
Data.ByteString.minimum ByteString
bs
            Just' Word8
w8 -> Word8 -> Word8 -> Word8
forall a. Ord a => a -> a -> a
min Word8
w8 (ByteString -> Word8
Data.ByteString.minimum ByteString
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 :: Word8 -> Fold ByteString Bool
elem Word8
w8 = (Word8 -> Bool) -> Fold ByteString Bool
any (Word8
w8 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
==)
{-# INLINABLE elem #-}

{-| @(notElem w8)@ returns 'False' if the byte stream has a byte equal to @w8@,
    'True' otherwise
-}
notElem :: Word8 -> Fold ByteString Bool
notElem :: Word8 -> Fold ByteString Bool
notElem Word8
w8 = (Word8 -> Bool) -> Fold ByteString Bool
all (Word8
w8 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/=)
{-# 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 :: (Word8 -> Bool) -> Fold ByteString (Maybe Word8)
find Word8 -> Bool
predicate = (Maybe' Word8 -> ByteString -> Maybe' Word8)
-> Maybe' Word8
-> (Maybe' Word8 -> Maybe Word8)
-> Fold ByteString (Maybe Word8)
forall a b x. (x -> a -> x) -> x -> (x -> b) -> Fold a b
Control.Foldl.Fold Maybe' Word8 -> ByteString -> Maybe' Word8
step Maybe' Word8
forall a. Maybe' a
Nothing' Maybe' Word8 -> Maybe Word8
forall a. Maybe' a -> Maybe a
Control.Foldl.Internal.lazy
  where
    step :: Maybe' Word8 -> ByteString -> Maybe' Word8
step Maybe' Word8
mw8 ByteString
bs = case Maybe' Word8
mw8 of
        Maybe' Word8
Nothing' -> Maybe Word8 -> Maybe' Word8
forall a. Maybe a -> Maybe' a
strict ((Word8 -> Bool) -> ByteString -> Maybe Word8
Data.ByteString.find Word8 -> Bool
predicate ByteString
bs)
        Just' Word8
_  -> Maybe' Word8
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 :: n -> Fold ByteString (Maybe Word8)
index n
i = (Either' Int Word8 -> ByteString -> Either' Int Word8)
-> Either' Int Word8
-> (Either' Int Word8 -> Maybe Word8)
-> Fold ByteString (Maybe Word8)
forall a b x. (x -> a -> x) -> x -> (x -> b) -> Fold a b
Control.Foldl.Fold Either' Int Word8 -> ByteString -> Either' Int Word8
step (Int -> Either' Int Word8
forall a b. a -> Either' a b
Left' (n -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral n
i)) Either' Int Word8 -> Maybe Word8
forall a b. Either' a b -> Maybe b
hush
  where
    step :: Either' Int Word8 -> ByteString -> Either' Int Word8
step Either' Int Word8
x ByteString
bs = case Either' Int Word8
x of
        Left' Int
remainder ->
            let len :: Int
len = ByteString -> Int
Data.ByteString.length ByteString
bs
            in  if Int
remainder Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
len
                then Word8 -> Either' Int Word8
forall a b. b -> Either' a b
Right' (ByteString -> Int -> Word8
Data.ByteString.Unsafe.unsafeIndex ByteString
bs Int
remainder)
                else Int -> Either' Int Word8
forall a b. a -> Either' a b
Left'  (Int
remainder Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
len)
        Either' Int Word8
_               -> Either' Int Word8
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 :: Word8 -> Fold ByteString (Maybe n)
elemIndex Word8
w8 = (Word8 -> Bool) -> Fold ByteString (Maybe n)
forall n. Num n => (Word8 -> Bool) -> Fold ByteString (Maybe n)
findIndex (Word8
w8 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
==)
{-# 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 :: (Word8 -> Bool) -> Fold ByteString (Maybe n)
findIndex Word8 -> Bool
predicate = (Either' n n -> ByteString -> Either' n n)
-> Either' n n
-> (Either' n n -> Maybe n)
-> Fold ByteString (Maybe n)
forall a b x. (x -> a -> x) -> x -> (x -> b) -> Fold a b
Control.Foldl.Fold Either' n n -> ByteString -> Either' n n
forall b. Num b => Either' b b -> ByteString -> Either' b b
step (n -> Either' n n
forall a b. a -> Either' a b
Left' n
0) Either' n n -> Maybe n
forall a b. Either' a b -> Maybe b
hush
  where
    step :: Either' b b -> ByteString -> Either' b b
step Either' b b
x ByteString
bs = case Either' b b
x of
        Left' b
m -> case (Word8 -> Bool) -> ByteString -> Maybe Int
Data.ByteString.findIndex Word8 -> Bool
predicate ByteString
bs of
            Maybe Int
Nothing -> b -> Either' b b
forall a b. a -> Either' a b
Left'  (b
m b -> b -> b
forall a. Num a => a -> a -> a
+ Int -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int
Data.ByteString.length ByteString
bs))
            Just Int
n  -> b -> Either' b b
forall a b. b -> Either' a b
Right' (b
m b -> b -> b
forall a. Num a => a -> a -> a
+ Int -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n)
        Either' b b
_       -> Either' b b
x
{-# INLINABLE findIndex #-}

-- | @count w8@ returns the number of times @w8@ appears
count :: Num n => Word8 -> Fold ByteString n
count :: Word8 -> Fold ByteString n
count Word8
w8 = (n -> ByteString -> n) -> n -> (n -> n) -> Fold ByteString n
forall a b x. (x -> a -> x) -> x -> (x -> b) -> Fold a b
Control.Foldl.Fold n -> ByteString -> n
forall a. Num a => a -> ByteString -> a
step n
0 n -> n
forall a. a -> a
id
  where
    step :: a -> ByteString -> a
step a
n ByteString
bs = a
n a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8 -> ByteString -> Int
Data.ByteString.count Word8
w8 ByteString
bs)
{-# INLINABLE count #-}

-- | Combine all the strict `ByteString` chunks to build a lazy `ByteString`
lazy :: Fold ByteString Data.ByteString.Lazy.ByteString
lazy :: Fold ByteString ByteString
lazy = ([ByteString] -> ByteString)
-> Fold ByteString [ByteString] -> Fold ByteString ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [ByteString] -> ByteString
Data.ByteString.Lazy.fromChunks Fold ByteString [ByteString]
forall a. Fold a [a]
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
-}