------------------------------------------------------------------------------
-- | Defines the 'Charset' accept header with an 'Accept' instance for use in
-- language negotiation.
module Network.HTTP.Media.Charset.Internal
    ( Charset (..)
    ) where

import qualified Data.ByteString.Char8           as BS
import qualified Data.CaseInsensitive            as CI

import           Control.Monad                   (guard)
import           Data.ByteString                 (ByteString)
import           Data.CaseInsensitive            (CI, original)
import           Data.Maybe                      (fromMaybe)
import           Data.String                     (IsString (..))

import           Network.HTTP.Media.Accept       (Accept (..))
import           Network.HTTP.Media.RenderHeader (RenderHeader (..))
import           Network.HTTP.Media.Utils        (isValidToken)


------------------------------------------------------------------------------
-- | Suitable for HTTP charset as defined in
-- <https://tools.ietf.org/html/rfc7231#section-5.3.3 RFC7231>.
--
-- Specifically:
--
-- > charset = token / "*"
newtype Charset = Charset (CI ByteString)
    deriving (Charset -> Charset -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Charset -> Charset -> Bool
$c/= :: Charset -> Charset -> Bool
== :: Charset -> Charset -> Bool
$c== :: Charset -> Charset -> Bool
Eq, Eq Charset
Charset -> Charset -> Bool
Charset -> Charset -> Ordering
Charset -> Charset -> Charset
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Charset -> Charset -> Charset
$cmin :: Charset -> Charset -> Charset
max :: Charset -> Charset -> Charset
$cmax :: Charset -> Charset -> Charset
>= :: Charset -> Charset -> Bool
$c>= :: Charset -> Charset -> Bool
> :: Charset -> Charset -> Bool
$c> :: Charset -> Charset -> Bool
<= :: Charset -> Charset -> Bool
$c<= :: Charset -> Charset -> Bool
< :: Charset -> Charset -> Bool
$c< :: Charset -> Charset -> Bool
compare :: Charset -> Charset -> Ordering
$ccompare :: Charset -> Charset -> Ordering
Ord)

instance Show Charset where
    show :: Charset -> String
show = ByteString -> String
BS.unpack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall h. RenderHeader h => h -> ByteString
renderHeader

instance IsString Charset where
    fromString :: String -> Charset
fromString String
str = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a. a -> Maybe a -> a
fromMaybe (forall a. Accept a => ByteString -> Maybe a
parseAccept forall a b. (a -> b) -> a -> b
$ String -> ByteString
BS.pack String
str) forall a b. (a -> b) -> a -> b
$
        forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ String
"Invalid encoding literal " forall a. [a] -> [a] -> [a]
++ String
str

instance Accept Charset where
    parseAccept :: ByteString -> Maybe Charset
parseAccept ByteString
bs = do
        forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ ByteString -> Bool
isValidToken ByteString
bs
        forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ CI ByteString -> Charset
Charset (forall s. FoldCase s => s -> CI s
CI.mk ByteString
bs)

    matches :: Charset -> Charset -> Bool
matches Charset
_ (Charset CI ByteString
"*") = Bool
True
    matches Charset
a Charset
b             = Charset
a forall a. Eq a => a -> a -> Bool
== Charset
b

    moreSpecificThan :: Charset -> Charset -> Bool
moreSpecificThan Charset
_ (Charset CI ByteString
"*") = Bool
True
    moreSpecificThan Charset
_ Charset
_             = Bool
False

instance RenderHeader Charset where
    renderHeader :: Charset -> ByteString
renderHeader (Charset CI ByteString
e) = forall s. CI s -> s
original CI ByteString
e