module Network.HTTP.Media.Language.Internal
( Language (..)
) 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.Char (isAlpha, isAlphaNum)
import Data.List (isPrefixOf)
import Data.Maybe (fromMaybe)
import Data.String (IsString (..))
import Network.HTTP.Media.Accept (Accept (..))
import Network.HTTP.Media.RenderHeader (RenderHeader (..))
newtype Language = Language [CI ByteString]
deriving (Eq, Ord)
instance Show Language where
show = BS.unpack . renderHeader
instance IsString Language where
fromString "*" = Language []
fromString str = flip fromMaybe (parseAccept $ BS.pack str) $
error $ "Invalid language literal " ++ str
instance Accept Language where
parseAccept "*" = Just $ Language []
parseAccept bs = do
let pieces = BS.split '-' bs
guard $ not (null pieces)
Language <$> mapM check pieces
where
check part = do
let len = BS.length part
guard $ len >= 1 && len <= 8 &&
isAlpha (BS.head part) &&
BS.all isAlphaNum (BS.tail part)
return (CI.mk part)
matches (Language a) (Language b) = b `isPrefixOf` a
moreSpecificThan (Language a) (Language b) =
b `isPrefixOf` a && length a > length b
instance RenderHeader Language where
renderHeader (Language []) = "*"
renderHeader (Language l) = BS.intercalate "-" (map original l)