    {-# LANGUAGE MultiParamTypeClasses,
    			 TypeSynonymInstances,
    			 FlexibleInstances,
    			 FunctionalDependencies #-}
    -- |
    -- Module       : Test.Hspec.Attoparsec.Source
    -- Copyright    : (c) 2014 Alp Mestanogullari
    -- License      : BSD3
    -- Maintainer   : alpmestan@gmail.com
    -- Stability    : experimental
    --
    -- A 'Source' class that ties parser types and input types to
    -- give you a uniform interface for testing your parsers,
    -- without caring about the input type.
    module Test.Hspec.Attoparsec.Source where

    import qualified Data.Attoparsec.ByteString as AB
    import qualified Data.ByteString as B

    import qualified Data.Attoparsec.ByteString.Lazy as ALB
    import qualified Data.ByteString.Lazy as LB

    import qualified Data.Attoparsec.Text as AT
    import qualified Data.Text as T

    import qualified Data.Attoparsec.Text.Lazy as ALT
    import qualified Data.Text.Lazy as LT

    import qualified Data.Attoparsec.Types as Atto

    import Data.String (IsString)

    -- | A class where each instance will just teach
    --   how to get an Either or the specific result
    --   type associated to the parser for the given
    --   input type.
    class (Eq string, Show string, IsString string)
       => Source parser string string' result | string -> parser, string -> result, string -> string' where
    	-- | Feed some input to a parser and extract the result
    	--   as either a failure 'String' or an actually parsed value.
    	--   Can be read as /fed to/.
    	--
    	-- > -- "<a ...>" fed to an HTML parser
    	-- > "<a href=\"/foo\">Go to foo</a>" ~> htmlParser :: Either String a
    	(~>) :: string -> parser string' a -> Either String a

    	-- | Feed some input to a parser and extract it as the
    	--   appropriate result type from that module.
    	--
    	--   This is not currently useful in the library per se,
    	--   but is used in test-suites directly where we generally only deal
    	--   with one concrete set of parser, input and result types.
    	--   This lets us inspect the result in any way we want, e.g
    	--   in conjunction with @shouldSatisfy@ or a custom hspec combinator.
    	(~?>) :: string -> parser string' a -> result a

    instance Source Atto.Parser B.ByteString B.ByteString AB.Result where
    	ByteString
    t ~> :: forall a. ByteString -> Parser ByteString a -> Either String a
    ~> Parser ByteString a
    p = Parser ByteString a -> ByteString -> Either String a
    forall a. Parser a -> ByteString -> Either String a
    AB.parseOnly Parser ByteString a
    p ByteString
    t

    	ByteString
    t ~?> :: forall a. ByteString -> Parser ByteString a -> Result a
    ~?> Parser ByteString a
    p = Parser ByteString a -> ByteString -> Result a
    forall a. Parser a -> ByteString -> Result a
    AB.parse Parser ByteString a
    p ByteString
    t

    instance Source Atto.Parser LB.ByteString B.ByteString ALB.Result where
    	ByteString
    t ~> :: forall a. ByteString -> Parser ByteString a -> Either String a
    ~> Parser ByteString a
    p = Result a -> Either String a
    forall r. Result r -> Either String r
    ALB.eitherResult (Result a -> Either String a) -> Result a -> Either String a
    forall a b. (a -> b) -> a -> b
    $ ByteString
    t ByteString -> Parser ByteString a -> Result a
    forall a. ByteString -> Parser ByteString a -> Result a
    forall (parser :: * -> * -> *) string string' (result :: * -> *) a.
    Source parser string string' result =>
    string -> parser string' a -> result a
    ~?> Parser ByteString a
    p

    	ByteString
    t ~?> :: forall a. ByteString -> Parser ByteString a -> Result a
    ~?> Parser ByteString a
    p = Parser ByteString a -> ByteString -> Result a
    forall a. Parser a -> ByteString -> Result a
    ALB.parse Parser ByteString a
    p ByteString
    t

    instance Source Atto.Parser T.Text T.Text AT.Result where
    	Text
    t ~> :: forall a. Text -> Parser Text a -> Either String a
    ~> Parser Text a
    p = Parser Text a -> Text -> Either String a
    forall a. Parser a -> Text -> Either String a
    AT.parseOnly Parser Text a
    p Text
    t

    	Text
    t ~?> :: forall a. Text -> Parser Text a -> Result a
    ~?> Parser Text a
    p = Parser Text a -> Text -> Result a
    forall a. Parser a -> Text -> Result a
    AT.parse Parser Text a
    p Text
    t

    instance Source Atto.Parser LT.Text T.Text ALT.Result where
    	Text
    t ~> :: forall a. Text -> Parser Text a -> Either String a
    ~> Parser Text a
    p = Result a -> Either String a
    forall r. Result r -> Either String r
    ALT.eitherResult (Result a -> Either String a) -> Result a -> Either String a
    forall a b. (a -> b) -> a -> b
    $ Text
    t Text -> Parser Text a -> Result a
    forall a. Text -> Parser Text a -> Result a
    forall (parser :: * -> * -> *) string string' (result :: * -> *) a.
    Source parser string string' result =>
    string -> parser string' a -> result a
    ~?> Parser Text a
    p

    	Text
    t ~?> :: forall a. Text -> Parser Text a -> Result a
    ~?> Parser Text a
    p = Parser Text a -> Text -> Result a
    forall a. Parser a -> Text -> Result a
    ALT.parse Parser Text a
    p Text
    t

    -- | Class for generically inspecting unconsumed input
    class Leftover r s | r -> s where
    	-- | Get the unconsumed input from the result of a parser
    	--
    	--   Returns 'Nothing' if the unconsumed input is ""
    	leftover :: r a -> Maybe s

    instance Leftover AB.Result B.ByteString where
    	leftover :: forall a. Result a -> Maybe ByteString
    leftover (AB.Done ByteString
    t a
    _) = ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just ByteString
    t
    	leftover IResult ByteString a
    _             = Maybe ByteString
    forall a. Maybe a
    Nothing

    instance Leftover ALB.Result LB.ByteString where
    	leftover :: forall a. Result a -> Maybe ByteString
    leftover (ALB.Done ByteString
    t a
    _) = ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just ByteString
    t
    	leftover Result a
    _              = Maybe ByteString
    forall a. Maybe a
    Nothing

    instance Leftover AT.Result T.Text where
    	leftover :: forall a. Result a -> Maybe Text
    leftover (AT.Done Text
    t a
    _) = Text -> Maybe Text
    forall a. a -> Maybe a
    Just Text
    t
    	leftover IResult Text a
    _            = Maybe Text
    forall a. Maybe a
    Nothing

    instance Leftover ALT.Result LT.Text where
    	leftover :: forall a. Result a -> Maybe Text
    leftover (ALT.Done Text
    t a
    _) = Text -> Maybe Text
    forall a. a -> Maybe a
    Just Text
    t
    	leftover Result a
    _              = Maybe Text
    forall a. Maybe a
    Nothing