{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}

-- | /WARNING/: This module is /not/ intended for use outside the TagSoup library.
--
--   This module provides an abstraction for String's as used inside TagSoup. It allows
--   TagSoup to work with String (list of Char), ByteString.Char8, ByteString.Lazy.Char8,
--   Data.Text and Data.Text.Lazy.
module Text.StringLike (StringLike(..), fromString, castString) where

import Data.String
import Data.Typeable

import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy.Char8 as LBS
import qualified Data.Text as T
import qualified Data.Text.Lazy as LT


-- | A class to generalise TagSoup parsing over many types of string-like types.
--   Examples are given for the String type.
class (Typeable a, Eq a, IsString a) => StringLike a where
    -- | > empty = ""
    empty :: a
    -- | > cons = (:)
    cons :: Char -> a -> a
    -- | > uncons []     = Nothing
    --   > uncons (x:xs) = Just (x, xs)
    uncons :: a -> Maybe (Char, a)

    -- | > toString = id
    toString :: a -> String
    -- | > fromChar = return
    fromChar :: Char -> a
    -- | > strConcat = concat
    strConcat :: [a] -> a
    -- | > strNull = null
    strNull :: a -> Bool
    -- | > append = (++)
    append :: a -> a -> a
    -- | > strMap = map
    strMap :: (Char -> Char) -> a -> a


-- | Convert a String from one type to another.
castString :: (StringLike a, StringLike b) => a -> b
castString :: forall a b. (StringLike a, StringLike b) => a -> b
castString = String -> b
forall a. IsString a => String -> a
fromString (String -> b) -> (a -> String) -> a -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. StringLike a => a -> String
toString


instance StringLike String where
    uncons :: String -> Maybe (Char, String)
uncons [] = Maybe (Char, String)
forall a. Maybe a
Nothing
    uncons (Char
x:String
xs) = (Char, String) -> Maybe (Char, String)
forall a. a -> Maybe a
Just (Char
x, String
xs)
    toString :: String -> String
toString = String -> String
forall a. a -> a
id
    fromChar :: Char -> String
fromChar = (Char -> String -> String
forall a. a -> [a] -> [a]
:[])
    strConcat :: [String] -> String
strConcat = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
    empty :: String
empty = []
    strNull :: String -> Bool
strNull = String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null
    cons :: Char -> String -> String
cons Char
c = (Char
cChar -> String -> String
forall a. a -> [a] -> [a]
:)
    append :: String -> String -> String
append = String -> String -> String
forall a. [a] -> [a] -> [a]
(++)
    strMap :: (Char -> Char) -> String -> String
strMap = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap

instance StringLike BS.ByteString where
    uncons :: ByteString -> Maybe (Char, ByteString)
uncons = ByteString -> Maybe (Char, ByteString)
BS.uncons
    toString :: ByteString -> String
toString = ByteString -> String
BS.unpack
    fromChar :: Char -> ByteString
fromChar = Char -> ByteString
BS.singleton
    strConcat :: [ByteString] -> ByteString
strConcat = [ByteString] -> ByteString
BS.concat
    empty :: ByteString
empty = ByteString
BS.empty
    strNull :: ByteString -> Bool
strNull = ByteString -> Bool
BS.null
    cons :: Char -> ByteString -> ByteString
cons = Char -> ByteString -> ByteString
BS.cons
    append :: ByteString -> ByteString -> ByteString
append = ByteString -> ByteString -> ByteString
BS.append
    strMap :: (Char -> Char) -> ByteString -> ByteString
strMap = (Char -> Char) -> ByteString -> ByteString
BS.map

instance StringLike LBS.ByteString where
    uncons :: ByteString -> Maybe (Char, ByteString)
uncons = ByteString -> Maybe (Char, ByteString)
LBS.uncons
    toString :: ByteString -> String
toString = ByteString -> String
LBS.unpack
    fromChar :: Char -> ByteString
fromChar = Char -> ByteString
LBS.singleton
    strConcat :: [ByteString] -> ByteString
strConcat = [ByteString] -> ByteString
LBS.concat
    empty :: ByteString
empty = ByteString
LBS.empty
    strNull :: ByteString -> Bool
strNull = ByteString -> Bool
LBS.null
    cons :: Char -> ByteString -> ByteString
cons = Char -> ByteString -> ByteString
LBS.cons
    append :: ByteString -> ByteString -> ByteString
append = ByteString -> ByteString -> ByteString
LBS.append
    strMap :: (Char -> Char) -> ByteString -> ByteString
strMap = (Char -> Char) -> ByteString -> ByteString
LBS.map

instance StringLike T.Text where
    uncons :: Text -> Maybe (Char, Text)
uncons = Text -> Maybe (Char, Text)
T.uncons
    toString :: Text -> String
toString = Text -> String
T.unpack
    fromChar :: Char -> Text
fromChar = Char -> Text
T.singleton
    strConcat :: [Text] -> Text
strConcat = [Text] -> Text
T.concat
    empty :: Text
empty = Text
T.empty
    strNull :: Text -> Bool
strNull = Text -> Bool
T.null
    cons :: Char -> Text -> Text
cons = Char -> Text -> Text
T.cons
    append :: Text -> Text -> Text
append = Text -> Text -> Text
T.append
    strMap :: (Char -> Char) -> Text -> Text
strMap = (Char -> Char) -> Text -> Text
T.map

instance StringLike LT.Text where
    uncons :: Text -> Maybe (Char, Text)
uncons = Text -> Maybe (Char, Text)
LT.uncons
    toString :: Text -> String
toString = Text -> String
LT.unpack
    fromChar :: Char -> Text
fromChar = Char -> Text
LT.singleton
    strConcat :: [Text] -> Text
strConcat = [Text] -> Text
LT.concat
    empty :: Text
empty = Text
LT.empty
    strNull :: Text -> Bool
strNull = Text -> Bool
LT.null
    cons :: Char -> Text -> Text
cons = Char -> Text -> Text
LT.cons
    append :: Text -> Text -> Text
append = Text -> Text -> Text
LT.append
    strMap :: (Char -> Char) -> Text -> Text
strMap = (Char -> Char) -> Text -> Text
LT.map