+{-# LANGUAGE
+ DeriveDataTypeable
+ , FlexibleInstances
+ , MultiParamTypeClasses
+ , OverloadedStrings
+ , RecordWildCards
+ , TemplateHaskell
+ , TypeSynonymInstances
+ , UnicodeSyntax
+ , ViewPatterns
+ #-}
+-- |Parsing and printing MIME Media Types
+-- (<http://tools.ietf.org/html/rfc2046>).
module Network.HTTP.Lucu.MIMEType
( MIMEType(..)
- , (+/+) -- String -> String -> MIMEType
- , (+:+) -- MIMEType -> (String, String) -> MIMEType
- , (+=+) -- String -> String -> (String, String)
- , mimeTypeP -- Parser MIMEType
- , mimeTypeListP -- Parser [MIMEType]
+ , mimeType
)
where
-
-import Network.HTTP.Lucu.Parser
-import Network.HTTP.Lucu.Parser.Http
-import Network.HTTP.Lucu.Utils
-
-
-data MIMEType = MIMEType {
- mtMajor :: String
- , mtMinor :: String
- , mtParams :: [ (String, String) ]
- } deriving (Eq)
-
-
-instance Show MIMEType where
- show (MIMEType maj min params)
- = maj ++ "/" ++ min ++
- if null params then
- ""
- else
- "; " ++ joinWith "; " (map showPair params)
- where
- showPair :: (String, String) -> String
- showPair (name, value)
- = name ++ "=" ++ if any (not . isToken) value then
- quoteStr value
- else
- value
-
-
-infix 9 +/+, +=+
-infixl 8 +:+
-
-
-(+/+) :: String -> String -> MIMEType
-maj +/+ min
- = MIMEType maj min []
-
-
-(+:+) :: MIMEType -> (String, String) -> MIMEType
-mt@(MIMEType _ _ params) +:+ pair
- = mt {
- mtParams = mtParams mt ++ [pair]
+import Control.Applicative
+import Control.Monad.Unicode
+import Data.Ascii (Ascii, AsciiBuilder, CIAscii)
+import Data.Attempt
+import Data.Attoparsec.Char8
+import Data.Convertible.Base
+import Data.Convertible.Instances.Ascii ()
+import Data.Convertible.Utils
+import Data.Default
+import Data.Monoid.Unicode
+import Data.Typeable
+import Language.Haskell.TH.Syntax
+import Language.Haskell.TH.Quote
+import Network.HTTP.Lucu.MIMEParams
+import Network.HTTP.Lucu.OrphanInstances ()
+import Network.HTTP.Lucu.Parser
+import Network.HTTP.Lucu.Parser.Http
+import Network.HTTP.Lucu.Utils
+import Prelude.Unicode
+
+-- |A media type, subtype, and parameters.
+data MIMEType
+ = MIMEType {
+ mtMedia ∷ !CIAscii
+ , mtSub ∷ !CIAscii
+ , mtParams ∷ !MIMEParams
}
-
-
-(+=+) :: String -> String -> (String, String)
-name +=+ value = (name, value)
-
-
-
-mimeTypeP :: Parser MIMEType
-mimeTypeP = allowEOF $
- do maj <- token
- char '/'
- min <- token
- params <- many paramP
- return $ MIMEType maj min params
+ deriving (Eq, Show, Read, Typeable)
+
+instance Lift MIMEType where
+ lift (MIMEType {..})
+ = [| MIMEType {
+ mtMedia = $(lift mtMedia )
+ , mtSub = $(lift mtSub )
+ , mtParams = $(lift mtParams)
+ }
+ |]
+
+instance ConvertSuccess MIMEType Ascii where
+ {-# INLINE convertSuccess #-}
+ convertSuccess = convertSuccessVia ((⊥) ∷ AsciiBuilder)
+
+instance ConvertSuccess MIMEType AsciiBuilder where
+ {-# INLINEABLE convertSuccess #-}
+ convertSuccess (MIMEType {..})
+ = cs mtMedia ⊕
+ cs ("/" ∷ Ascii) ⊕
+ cs mtSub ⊕
+ cs mtParams
+
+deriveAttempts [ ([t| MIMEType |], [t| Ascii |])
+ , ([t| MIMEType |], [t| AsciiBuilder |])
+ ]
+
+-- |Parse 'MIMEType' from an 'Ascii'. For MIME type literals, consider
+-- using 'mimeType' quasi-quoter.
+instance ConvertAttempt Ascii MIMEType where
+ {-# INLINEABLE convertAttempt #-}
+ convertAttempt str
+ = case parseOnly (finishOff def) (cs str) of
+ Right t → return t
+ Left err → fail ("Unparsable MIME Type: " ⧺ cs str ⧺ ": " ⧺ err)
+
+instance Default (Parser MIMEType) where
+ {-# INLINEABLE def #-}
+ def = do media ← cs <$> token
+ _ ← char '/'
+ sub ← cs <$> token
+ params ← def
+ return $ MIMEType media sub params
+
+instance Default (Parser [MIMEType]) where
+ {-# INLINE def #-}
+ def = listOf def
+
+-- |'QuasiQuoter' for 'MIMEType' literals.
+--
+-- @
+-- textPlain :: 'MIMEType'
+-- textPlain = ['mimeType'| text/plain; charset=\"UTF-8\" |]
+-- @
+mimeType ∷ QuasiQuoter
+mimeType = QuasiQuoter {
+ quoteExp = (lift =≪) ∘ (parseType =≪) ∘ toAscii
+ , quotePat = const unsupported
+ , quoteType = const unsupported
+ , quoteDec = const unsupported
+ }
where
- paramP :: Parser (String, String)
- paramP = do many lws
- char ';'
- many lws
- name <- token
- char '='
- value <- token <|> quotedStr
- return (name, value)
-
-mimeTypeListP :: Parser [MIMEType]
-mimeTypeListP = allowEOF $ listOf mimeTypeP
+ parseType ∷ Monad m ⇒ Ascii → m MIMEType
+ parseType a
+ = case ca a of
+ Success t → return t
+ Failure e → fail (show e)
+
+ toAscii ∷ Monad m ⇒ String → m Ascii
+ toAscii (trim → s)
+ = case ca s of
+ Success a → return a
+ Failure e → fail (show e)
+
+ unsupported ∷ Monad m ⇒ m α
+ unsupported = fail "Unsupported usage of mimeType quasi-quoter."