    {-# LANGUAGE FlexibleInstances    #-}
    {-# LANGUAGE TypeSynonymInstances #-}
    {-# LANGUAGE OverloadedStrings    #-}
    {-# LANGUAGE ViewPatterns         #-}

    {-# OPTIONS_GHC -fno-warn-orphans #-}

    -- ------------------------------------------------------------

    {- |
       Copyright  : Copyright (C) 2014- Uwe Schmidt
       License    : MIT

       Maintainer : Uwe Schmidt <uwe@fh-wedel.de>
       Stability  : stable
    -}

    -- ------------------------------------------------------------

    module Text.Regex.XMLSchema.Generic.StringLike
    where

    import Data.Maybe
    import Data.String      (IsString(..))

    import qualified Data.Text                  as T
    import qualified Data.Text.Lazy             as TL
    import qualified Data.ByteString.Char8      as B
    import qualified Data.ByteString.Lazy.Char8 as BL

    -- ------------------------------------------------------------

    -- | /WARNING/: This StringLike class is /not/ intended for use outside this regex library.
    -- It provides an abstraction for String's as used inside this library.
    -- It allows the library to work with String (list of Char),
    -- ByteString.Char8, ByteString.Lazy.Char8,
    -- Data.Text and Data.Text.Lazy.
    --
    -- The class is similar to the StringLike class in the tagsoup package

    class (Eq a, IsString a, Show a) => StringLike a where
      emptyS     :: a
      uncons     :: a -> Maybe (Char, a)
      nullS      :: a -> Bool
      headS      :: a -> Char
      takeS      :: Int -> a -> a
      dropS      :: Int -> a -> a
      appendS    :: a -> a -> a
      concatS    :: [a] -> a
      toString   :: a -> String

      nullS      = Maybe (Char, a) -> Bool
    forall a. Maybe a -> Bool
    isNothing (Maybe (Char, a) -> Bool) -> (a -> Maybe (Char, a)) -> a -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> Maybe (Char, a)
    forall a. StringLike a => a -> Maybe (Char, a)
    uncons
      headS (a -> Maybe (Char, a)
    forall a. StringLike a => a -> Maybe (Char, a)
    uncons -> Just (Char
    c, a
    _))
                 = Char
    c
      headS a
    _    = [Char] -> Char
    forall a. HasCallStack => [Char] -> a
    error [Char]
    "headS: empty StringLike"
      concatS    = (a -> a -> a) -> a -> [a] -> a
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl a -> a -> a
    forall a. StringLike a => a -> a -> a
    appendS a
    forall a. StringLike a => a
    emptyS

      {-# INLINE nullS   #-}
      {-# INLINE headS   #-}
      {-# INLINE concatS #-}

    -- ------------------------------------------------------------

    instance StringLike String where
      emptyS :: [Char]
    emptyS           = []
      uncons :: [Char] -> Maybe (Char, [Char])
    uncons (Char
    x : [Char]
    xs) = (Char, [Char]) -> Maybe (Char, [Char])
    forall a. a -> Maybe a
    Just (Char
    x, [Char]
    xs)
      uncons [Char]
    ""       = Maybe (Char, [Char])
    forall a. Maybe a
    Nothing
      nullS :: [Char] -> Bool
    nullS           = [Char] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null
      headS :: [Char] -> Char
    headS           = [Char] -> Char
    forall a. HasCallStack => [a] -> a
    head
      takeS :: Int -> [Char] -> [Char]
    takeS           = Int -> [Char] -> [Char]
    forall a. Int -> [a] -> [a]
    take
      dropS :: Int -> [Char] -> [Char]
    dropS           = Int -> [Char] -> [Char]
    forall a. Int -> [a] -> [a]
    drop
      appendS :: [Char] -> [Char] -> [Char]
    appendS         = [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    (++)
      concatS :: [[Char]] -> [Char]
    concatS         = [[Char]] -> [Char]
    forall (t :: * -> *) a. Foldable t => t [a] -> [a]
    concat
      toString :: [Char] -> [Char]
    toString        = [Char] -> [Char]
    forall a. a -> a
    id

      {-# INLINE emptyS     #-}
      {-# INLINE uncons     #-}
      {-# INLINE nullS      #-}
      {-# INLINE takeS      #-}
      {-# INLINE dropS      #-}
      {-# INLINE appendS    #-}
      {-# INLINE concatS    #-}
      {-# INLINE toString   #-}

    -- ------------------------------------------------------------

    instance StringLike T.Text where
      emptyS :: Text
    emptyS     = Text
    T.empty
      uncons :: Text -> Maybe (Char, Text)
    uncons     = Text -> Maybe (Char, Text)
    T.uncons
      nullS :: Text -> Bool
    nullS      = Text -> Bool
    T.null
      headS :: Text -> Char
    headS      = HasCallStack => Text -> Char
    Text -> Char
    T.head
      takeS :: Int -> Text -> Text
    takeS      = Int -> Text -> Text
    T.take
      dropS :: Int -> Text -> Text
    dropS      = Int -> Text -> Text
    T.drop
      appendS :: Text -> Text -> Text
    appendS    = Text -> Text -> Text
    T.append
      concatS :: [Text] -> Text
    concatS    = [Text] -> Text
    T.concat
      toString :: Text -> [Char]
    toString   = Text -> [Char]
    T.unpack

      {-# INLINE emptyS     #-}
      {-# INLINE uncons     #-}
      {-# INLINE nullS      #-}
      {-# INLINE takeS      #-}
      {-# INLINE dropS      #-}
      {-# INLINE appendS    #-}
      {-# INLINE concatS    #-}
      {-# INLINE toString   #-}

    -- ------------------------------------------------------------

    instance StringLike TL.Text where
      emptyS :: Text
    emptyS     = Text
    TL.empty
      uncons :: Text -> Maybe (Char, Text)
    uncons     = Text -> Maybe (Char, Text)
    TL.uncons
      nullS :: Text -> Bool
    nullS      = Text -> Bool
    TL.null
      headS :: Text -> Char
    headS      = HasCallStack => Text -> Char
    Text -> Char
    TL.head
      takeS :: Int -> Text -> Text
    takeS      = Int64 -> Text -> Text
    TL.take (Int64 -> Text -> Text) -> (Int -> Int64) -> Int -> Text -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> Int64
    forall a. Enum a => Int -> a
    toEnum
      dropS :: Int -> Text -> Text
    dropS      = Int64 -> Text -> Text
    TL.drop (Int64 -> Text -> Text) -> (Int -> Int64) -> Int -> Text -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> Int64
    forall a. Enum a => Int -> a
    toEnum
      appendS :: Text -> Text -> Text
    appendS    = Text -> Text -> Text
    TL.append
      concatS :: [Text] -> Text
    concatS    = [Text] -> Text
    TL.concat
      toString :: Text -> [Char]
    toString   = Text -> [Char]
    TL.unpack

      {-# INLINE emptyS     #-}
      {-# INLINE uncons     #-}
      {-# INLINE nullS      #-}
      {-# INLINE takeS      #-}
      {-# INLINE dropS      #-}
      {-# INLINE appendS    #-}
      {-# INLINE concatS    #-}
      {-# INLINE toString   #-}

    -- ------------------------------------------------------------

    instance StringLike B.ByteString where
      emptyS :: ByteString
    emptyS     = ByteString
    B.empty
      uncons :: ByteString -> Maybe (Char, ByteString)
    uncons     = ByteString -> Maybe (Char, ByteString)
    B.uncons
      nullS :: ByteString -> Bool
    nullS      = ByteString -> Bool
    B.null
      headS :: ByteString -> Char
    headS      = ByteString -> Char
    B.head
      takeS :: Int -> ByteString -> ByteString
    takeS      = Int -> ByteString -> ByteString
    B.take
      dropS :: Int -> ByteString -> ByteString
    dropS      = Int -> ByteString -> ByteString
    B.drop
      appendS :: ByteString -> ByteString -> ByteString
    appendS    = ByteString -> ByteString -> ByteString
    B.append
      concatS :: [ByteString] -> ByteString
    concatS    = [ByteString] -> ByteString
    B.concat
      toString :: ByteString -> [Char]
    toString   = ByteString -> [Char]
    B.unpack

      {-# INLINE emptyS     #-}
      {-# INLINE uncons     #-}
      {-# INLINE nullS      #-}
      {-# INLINE takeS      #-}
      {-# INLINE dropS      #-}
      {-# INLINE appendS    #-}
      {-# INLINE concatS    #-}
      {-# INLINE toString   #-}

    -- ------------------------------------------------------------

    instance StringLike BL.ByteString where
      emptyS :: ByteString
    emptyS     = ByteString
    BL.empty
      uncons :: ByteString -> Maybe (Char, ByteString)
    uncons     = ByteString -> Maybe (Char, ByteString)
    BL.uncons
      nullS :: ByteString -> Bool
    nullS      = ByteString -> Bool
    BL.null
      headS :: ByteString -> Char
    headS      = ByteString -> Char
    BL.head
      takeS :: Int -> ByteString -> ByteString
    takeS      = Int64 -> ByteString -> ByteString
    BL.take (Int64 -> ByteString -> ByteString)
    -> (Int -> Int64) -> Int -> ByteString -> ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> Int64
    forall a. Enum a => Int -> a
    toEnum
      dropS :: Int -> ByteString -> ByteString
    dropS      = Int64 -> ByteString -> ByteString
    BL.drop (Int64 -> ByteString -> ByteString)
    -> (Int -> Int64) -> Int -> ByteString -> ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> Int64
    forall a. Enum a => Int -> a
    toEnum
      appendS :: ByteString -> ByteString -> ByteString
    appendS    = ByteString -> ByteString -> ByteString
    BL.append
      concatS :: [ByteString] -> ByteString
    concatS    = [ByteString] -> ByteString
    BL.concat
      toString :: ByteString -> [Char]
    toString   = ByteString -> [Char]
    BL.unpack

      {-# INLINE emptyS     #-}
      {-# INLINE uncons     #-}
      {-# INLINE nullS      #-}
      {-# INLINE takeS      #-}
      {-# INLINE dropS      #-}
      {-# INLINE appendS    #-}
      {-# INLINE concatS    #-}
      {-# INLINE toString   #-}

    -- ------------------------------------------------------------