    -- |
    -- Module         : Data.ByteString.Search.Substitution
    -- Copyright      : Daniel Fischer
    -- Licence        : BSD3
    -- Maintainer     : Daniel Fischer <daniel.is.fischer@googlemail.com>
    -- Stability      : Provisional
    -- Portability    : portable
    --
    -- Class for values to be substituted into strict and lazy 'S.ByteString's
    -- by the @replace@ functions defined in this package.
    --
    module Data.ByteString.Search.Substitution ( Substitution(..)) where

    import qualified Data.ByteString as S
    import qualified Data.ByteString.Lazy as L
    import qualified Data.ByteString.Lazy.Internal as LI

    -- | Type class of meaningful substitutions for replace functions
    --   on ByteStrings. Instances for strict and lazy ByteStrings are
    --   provided here.
    class Substitution a where
        -- | @'substitution'@ transforms a value to a substitution function.
        substitution :: a -> ([S.ByteString] -> [S.ByteString])
        -- | @'prependCycle' sub lazyBS@ shall prepend infinitely many copies
        --   of @sub@ to @lazyBS@ without entering an infinite loop in case
        --   of an empty @sub@, so e.g.
        --
        -- @
        --   'prependCycle' \"\" \"ab\" == \"ab\"
        -- @
        --
        -- shall (quickly) evaluate to 'True'.
        -- For non-empty @sub@, the cycle shall be constructed efficiently.
        prependCycle :: a -> (L.ByteString -> L.ByteString)

    instance Substitution S.ByteString where
        {-# INLINE substitution #-}
        substitution :: ByteString -> [ByteString] -> [ByteString]
    substitution ByteString
    sub = if ByteString -> Bool
    S.null ByteString
    sub then [ByteString] -> [ByteString]
    forall a. a -> a
    id else (ByteString
    sub ByteString -> [ByteString] -> [ByteString]
    forall a. a -> [a] -> [a]
    :)
        {-# INLINE prependCycle #-}
        prependCycle :: ByteString -> ByteString -> ByteString
    prependCycle ByteString
    sub
            | ByteString -> Bool
    S.null ByteString
    sub    = ByteString -> ByteString
    forall a. a -> a
    id
            | Bool
    otherwise     = let c :: ByteString
    c = ByteString -> ByteString -> ByteString
    LI.Chunk ByteString
    sub ByteString
    c in ByteString -> ByteString -> ByteString
    forall a b. a -> b -> a
    const ByteString
    c

    instance Substitution L.ByteString where
        {-# INLINE substitution #-}
        substitution :: ByteString -> [ByteString] -> [ByteString]
    substitution ByteString
    LI.Empty = [ByteString] -> [ByteString]
    forall a. a -> a
    id
        substitution (LI.Chunk ByteString
    c ByteString
    t) = (ByteString
    c ByteString -> [ByteString] -> [ByteString]
    forall a. a -> [a] -> [a]
    :) ([ByteString] -> [ByteString])
    -> ([ByteString] -> [ByteString]) -> [ByteString] -> [ByteString]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ([ByteString] -> ByteString -> [ByteString])
    -> ByteString -> [ByteString] -> [ByteString]
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip ((ByteString -> [ByteString] -> [ByteString])
    -> [ByteString] -> ByteString -> [ByteString]
    forall a. (ByteString -> a -> a) -> a -> ByteString -> a
    LI.foldrChunks (:)) ByteString
    t
        {-# INLINE prependCycle #-}
        prependCycle :: ByteString -> ByteString -> ByteString
    prependCycle ByteString
    sub
            | ByteString -> Bool
    L.null ByteString
    sub    = ByteString -> ByteString
    forall a. a -> a
    id
        prependCycle ByteString
    sub = let cyc :: ByteString
    cyc = (ByteString -> ByteString -> ByteString)
    -> ByteString -> ByteString -> ByteString
    forall a. (ByteString -> a -> a) -> a -> ByteString -> a
    LI.foldrChunks ByteString -> ByteString -> ByteString
    LI.Chunk ByteString
    cyc ByteString
    sub in ByteString -> ByteString -> ByteString
    forall a b. a -> b -> a
    const ByteString
    cyc