{-# LANGUAGE CPP #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE UndecidableInstances #-} module RFC.String ( module RFC.String , module Data.Text.Conversions ) where import ClassyPrelude hiding (fail) import Control.Monad.Fail (MonadFail, fail) import qualified Data.ByteString as SB import qualified Data.ByteString.Lazy as LB import Data.String (String) import qualified Data.Text as ST import Data.Text.Conversions import qualified Data.Text.Lazy as LT import qualified Data.Text.Lazy.Builder as LTBuilder import Network.URI (URI (..), parseURIReference, uriToString) #ifndef GHCJS_BROWSER import Servant.Docs #endif type LazyText = LT.Text type StrictText = ST.Text type LazyByteString = LB.ByteString type StrictByteString = SB.ByteString type ConvertibleString = ConvertibleStrings type ConvertibleToSBS a = ConvertibleStrings a StrictByteString type ConvertibleFromSBS a = ConvertibleStrings StrictByteString a type ConvertibleToString a = ConvertibleStrings a String type ConvertibleFromString a = ConvertibleStrings String a toStrictText :: (ToText a) => a -> StrictText toStrictText = toText {-# SPECIALIZE INLINE toStrictText :: String -> StrictText #-} {-# SPECIALIZE INLINE toStrictText :: LazyText -> StrictText #-} {-# SPECIALIZE INLINE toStrictText :: StrictText -> StrictText #-} toLazyText :: (ToText a) => a -> LazyText toLazyText = LT.fromStrict . toText {-# INLINE toLazyText #-} {-# SPECIALIZE INLINE toLazyText :: String -> LazyText #-} {-# SPECIALIZE INLINE toLazyText :: StrictText -> LazyText #-} {-# SPECIALIZE INLINE toLazyText :: LazyText -> LazyText #-} asUTF8 :: (ToText a, FromText (UTF8 b)) => a -> b asUTF8 it = unUTF8 $ fromText $ toText it {-# INLINE asUTF8 #-} {-# SPECIALIZE INLINE asUTF8 :: String-> LazyByteString #-} {-# SPECIALIZE INLINE asUTF8 :: StrictText -> LazyByteString #-} {-# SPECIALIZE INLINE asUTF8 :: LazyText -> LazyByteString #-} {-# SPECIALIZE INLINE asUTF8 :: String-> StrictByteString #-} {-# SPECIALIZE INLINE asUTF8 :: StrictText -> StrictByteString #-} {-# SPECIALIZE INLINE asUTF8 :: LazyText -> StrictByteString #-} toUTF8 :: (DecodeText f (UTF8 a), FromText b) => a -> f b toUTF8 it = decodeConvertText (UTF8 it) {-# INLINE toUTF8 #-} {-# SPECIALIZE INLINE toUTF8 :: LazyByteString -> Maybe String #-} {-# SPECIALIZE INLINE toUTF8 :: LazyByteString -> Maybe StrictText #-} {-# SPECIALIZE INLINE toUTF8 :: LazyByteString -> Maybe LazyText #-} {-# SPECIALIZE INLINE toUTF8 :: StrictByteString -> Maybe String #-} {-# SPECIALIZE INLINE toUTF8 :: StrictByteString -> Maybe StrictText #-} {-# SPECIALIZE INLINE toUTF8 :: StrictByteString -> Maybe LazyText #-} instance {-# OVERLAPPABLE #-} (Show a, DecodeText Maybe a, MonadFail m) => DecodeText m a where {-# SPECIALIZE instance DecodeText IO (UTF8 LazyByteString) #-} {-# SPECIALIZE instance DecodeText IO (UTF8 StrictByteString) #-} {-# SPECIALIZE instance DecodeText [] (UTF8 LazyByteString) #-} {-# SPECIALIZE instance DecodeText [] (UTF8 StrictByteString) #-} {-# SPECIALIZE instance DecodeText Maybe (UTF8 LazyByteString) #-} {-# SPECIALIZE instance DecodeText Maybe (UTF8 StrictByteString) #-} decodeText a = case decodeText a of [] -> fail $ "Could not decode text: " ++ (show a) x:_ -> return x emptyString :: (FromText a) => a emptyString = fromText $ toText "" {-# INLINE emptyString #-} {-# SPECIALIZE INLINE emptyString :: String #-} {-# SPECIALIZE INLINE emptyString :: LazyText #-} {-# SPECIALIZE INLINE emptyString :: StrictText #-} emptyUTF8 :: (FromText (UTF8 a)) => a emptyUTF8 = unUTF8 $ fromText $ toText "" {-# INLINE emptyUTF8 #-} instance {-# OVERLAPPING #-} ToText Char where toText c = toText [c] {-# INLINE toText #-} instance {-# OVERLAPPABLE #-} (FromText a) => FromText (UTF8 a) where {-# SPECIALISE instance FromText (UTF8 StrictText) #-} {-# SPECIALISE instance FromText (UTF8 LazyText) #-} {-# SPECIALISE instance FromText (UTF8 String) #-} fromText = UTF8 . fromText {-# INLINE fromText #-} instance {-# OVERLAPPABLE #-} (ToText a) => ToText (UTF8 a) where {-# SPECIALISE instance ToText (UTF8 StrictText) #-} {-# SPECIALISE instance ToText (UTF8 LazyText) #-} {-# SPECIALISE instance ToText (UTF8 String) #-} toText = toText . unUTF8 {-# INLINE toText #-} instance {-# OVERLAPPING #-} ToText URI where toText uri = toText $ uriToString id uri "" {-# INLINE toText #-} instance {-# OVERLAPS #-} (MonadFail f) => FromText (f URI) where {-# SPECIALIZE instance FromText (Maybe URI) #-} {-# SPECIALIZE instance FromText (IO URI) #-} fromText txt = case parseURIReference (fromText txt) of Nothing -> fail $ "Could not parse URI: " ++ (cs txt) Just uri -> return uri {-# INLINE fromText #-} class ConvertibleStrings a b where cs :: a -> b instance {-# OVERLAPPING #-} ConvertibleStrings LazyByteString StrictByteString where cs = LB.toStrict {-# INLINE cs #-} instance {-# OVERLAPPING #-} ConvertibleStrings StrictByteString LazyByteString where cs = LB.fromStrict {-# INLINE cs #-} instance {-# OVERLAPPABLE #-} (DecodeText f a, FromText b) => ConvertibleStrings a (f b) where cs = decodeConvertText {-# INLINE cs #-} instance {-# OVERLAPS #-} (ToText (UTF8 a), FromText b) => ConvertibleStrings a (UTF8 b) where cs a = UTF8 $ fromText $ toText $ UTF8 a {-# INLINE cs #-} instance {-# OVERLAPS #-} (ToText a, FromText (UTF8 b)) => ConvertibleStrings (UTF8 a) b where {-# SPECIALISE instance ConvertibleStrings (UTF8 StrictText) LazyByteString #-} {-# SPECIALISE instance ConvertibleStrings (UTF8 LazyText) LazyByteString #-} {-# SPECIALISE instance ConvertibleStrings (UTF8 String) LazyByteString #-} {-# SPECIALISE instance ConvertibleStrings (UTF8 StrictText) StrictByteString #-} {-# SPECIALISE instance ConvertibleStrings (UTF8 LazyText) StrictByteString #-} {-# SPECIALISE instance ConvertibleStrings (UTF8 String) StrictByteString #-} cs (UTF8 it) = unUTF8 $ fromText $ toText it {-# INLINE cs #-} instance {-# OVERLAPS #-} (ToText a, FromText b) => ConvertibleStrings a b where {-# SPECIALIZE instance ConvertibleStrings String LazyText #-} {-# SPECIALIZE instance ConvertibleStrings String StrictText #-} {-# SPECIALIZE instance ConvertibleStrings LazyText String #-} {-# SPECIALIZE instance ConvertibleStrings LazyText StrictText #-} {-# SPECIALIZE instance ConvertibleStrings StrictText LazyText #-} {-# SPECIALIZE instance ConvertibleStrings StrictText (Maybe (Base64 StrictByteString)) #-} {-# SPECIALIZE instance ConvertibleStrings LazyText (Maybe (Base64 StrictByteString)) #-} {-# SPECIALIZE instance ConvertibleStrings String (Maybe (Base64 StrictByteString)) #-} {-# SPECIALIZE instance ConvertibleStrings StrictText (Maybe (Base16 StrictByteString)) #-} {-# SPECIALIZE instance ConvertibleStrings LazyText (Maybe (Base16 StrictByteString)) #-} {-# SPECIALIZE instance ConvertibleStrings String (Maybe (Base16 StrictByteString)) #-} {-# SPECIALIZE instance ConvertibleStrings (Base16 StrictByteString) String #-} {-# SPECIALIZE instance ConvertibleStrings (Base16 StrictByteString) StrictText #-} {-# SPECIALIZE instance ConvertibleStrings (Base16 StrictByteString) LazyText #-} {-# SPECIALIZE instance ConvertibleStrings (Base64 StrictByteString) String #-} {-# SPECIALIZE instance ConvertibleStrings (Base64 StrictByteString) StrictText #-} {-# SPECIALIZE instance ConvertibleStrings (Base64 StrictByteString) LazyText #-} {-# SPECIALIZE instance ConvertibleStrings (Base16 LazyByteString) String #-} {-# SPECIALIZE instance ConvertibleStrings (Base16 LazyByteString) StrictText #-} {-# SPECIALIZE instance ConvertibleStrings (Base16 LazyByteString) LazyText #-} {-# SPECIALIZE instance ConvertibleStrings (Base64 LazyByteString) String #-} {-# SPECIALIZE instance ConvertibleStrings (Base64 LazyByteString) StrictText #-} {-# SPECIALIZE instance ConvertibleStrings (Base64 LazyByteString) LazyText #-} {-# SPECIALIZE instance ConvertibleStrings StrictText (Maybe (Base64 LazyByteString)) #-} {-# SPECIALIZE instance ConvertibleStrings LazyText (Maybe (Base64 LazyByteString)) #-} {-# SPECIALIZE instance ConvertibleStrings String (Maybe (Base64 LazyByteString)) #-} {-# SPECIALIZE instance ConvertibleStrings StrictText (Maybe (Base16 LazyByteString)) #-} {-# SPECIALIZE instance ConvertibleStrings LazyText (Maybe (Base16 LazyByteString)) #-} {-# SPECIALIZE instance ConvertibleStrings String (Maybe (Base16 LazyByteString)) #-} {-# SPECIALISE instance ConvertibleStrings StrictText (UTF8 LazyByteString) #-} {-# SPECIALISE instance ConvertibleStrings LazyText (UTF8 LazyByteString) #-} {-# SPECIALISE instance ConvertibleStrings String (UTF8 LazyByteString) #-} {-# SPECIALISE instance ConvertibleStrings StrictText (UTF8 StrictByteString) #-} {-# SPECIALISE instance ConvertibleStrings LazyText (UTF8 StrictByteString) #-} {-# SPECIALISE instance ConvertibleStrings String (UTF8 StrictByteString) #-} cs :: a -> b cs = fromText . toText {-# INLINE cs #-} instance {-# OVERLAPPING #-} ConvertibleStrings StrictText String where cs :: StrictText -> String cs = ST.unpack {-# INLINE cs #-} instance {-# OVERLAPS #-} ConvertibleStrings a a where cs :: a -> a cs = id {-# INLINE cs #-} #ifndef GHCJS_BROWSER instance ToSample StrictText where toSamples _ = singleSample $ cs "This is random text" instance ToSample LazyText where toSamples _ = singleSample $ cs "This is random text" #endif type LazyTextBuilder = LTBuilder.Builder instance {-# OVERLAPPING #-} ToText LazyTextBuilder where toText = cs . LTBuilder.toLazyText {-# INLINE toText #-}