{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE Safe #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE UndecidableInstances #-}
module Relude.String.Conversion
(
LText
, LByteString
, ConvertUtf8 (..)
, ToText (..)
, ToLText (..)
, ToString (..)
, LazyStrict (..)
, fromLazy
, fromStrict
, readEither
, show
) where
import GHC.TypeLits (ErrorMessage (..), Symbol, TypeError)
import Prelude (error)
import Relude.Base (Constraint, Type)
import Relude.Function (id, (.))
import Relude.Functor (first, (<$>))
import Relude.Monad.Reexport (Either)
import Relude.String.Reexport (ByteString, IsString, Read, ShortByteString, String, Text, fromShort,
fromString, toShort)
import qualified Data.ByteString.Lazy as LB
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import qualified Data.Text.Encoding.Error as T
import qualified Data.Text.Lazy as LT
import qualified Data.Text.Lazy.Encoding as LT
import qualified GHC.Show as Show (Show (show))
import qualified Text.Read (readEither)
type LText = LT.Text
type LByteString = LB.ByteString
class ConvertUtf8 a b where
encodeUtf8 :: a -> b
decodeUtf8 :: b -> a
decodeUtf8Strict :: b -> Either T.UnicodeException a
instance ConvertUtf8 String ByteString where
encodeUtf8 :: String -> ByteString
encodeUtf8 :: String -> ByteString
encodeUtf8 = Text -> ByteString
T.encodeUtf8 (Text -> ByteString) -> (String -> Text) -> String -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack
{-# INLINE encodeUtf8 #-}
decodeUtf8 :: ByteString -> String
decodeUtf8 :: ByteString -> String
decodeUtf8 = Text -> String
T.unpack (Text -> String) -> (ByteString -> Text) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
T.decodeUtf8
{-# INLINE decodeUtf8 #-}
decodeUtf8Strict :: ByteString -> Either T.UnicodeException String
decodeUtf8Strict :: ByteString -> Either UnicodeException String
decodeUtf8Strict = (Text -> String
T.unpack (Text -> String)
-> Either UnicodeException Text -> Either UnicodeException String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (Either UnicodeException Text -> Either UnicodeException String)
-> (ByteString -> Either UnicodeException Text)
-> ByteString
-> Either UnicodeException String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either UnicodeException Text
forall a b. ConvertUtf8 a b => b -> Either UnicodeException a
decodeUtf8Strict
{-# INLINE decodeUtf8Strict #-}
instance ConvertUtf8 Text ByteString where
encodeUtf8 :: Text -> ByteString
encodeUtf8 :: Text -> ByteString
encodeUtf8 = Text -> ByteString
T.encodeUtf8
{-# INLINE encodeUtf8 #-}
decodeUtf8 :: ByteString -> Text
decodeUtf8 :: ByteString -> Text
decodeUtf8 = OnDecodeError -> ByteString -> Text
T.decodeUtf8With OnDecodeError
T.lenientDecode
{-# INLINE decodeUtf8 #-}
decodeUtf8Strict :: ByteString -> Either T.UnicodeException Text
decodeUtf8Strict :: ByteString -> Either UnicodeException Text
decodeUtf8Strict = ByteString -> Either UnicodeException Text
T.decodeUtf8'
{-# INLINE decodeUtf8Strict #-}
instance ConvertUtf8 LText ByteString where
encodeUtf8 :: LText -> ByteString
encodeUtf8 :: LText -> ByteString
encodeUtf8 = ByteString -> ByteString
LB.toStrict (ByteString -> ByteString)
-> (LText -> ByteString) -> LText -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LText -> ByteString
forall a b. ConvertUtf8 a b => a -> b
encodeUtf8
{-# INLINE encodeUtf8 #-}
decodeUtf8 :: ByteString -> LText
decodeUtf8 :: ByteString -> LText
decodeUtf8 = OnDecodeError -> ByteString -> LText
LT.decodeUtf8With OnDecodeError
T.lenientDecode (ByteString -> LText)
-> (ByteString -> ByteString) -> ByteString -> LText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
LB.fromStrict
{-# INLINE decodeUtf8 #-}
decodeUtf8Strict :: ByteString -> Either T.UnicodeException LText
decodeUtf8Strict :: ByteString -> Either UnicodeException LText
decodeUtf8Strict = ByteString -> Either UnicodeException LText
forall a b. ConvertUtf8 a b => b -> Either UnicodeException a
decodeUtf8Strict (ByteString -> Either UnicodeException LText)
-> (ByteString -> ByteString)
-> ByteString
-> Either UnicodeException LText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
LB.fromStrict
{-# INLINE decodeUtf8Strict #-}
instance ConvertUtf8 String LByteString where
encodeUtf8 :: String -> LByteString
encodeUtf8 :: String -> ByteString
encodeUtf8 = LText -> ByteString
LT.encodeUtf8 (LText -> ByteString) -> (String -> LText) -> String -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> LText
LT.pack
{-# INLINE encodeUtf8 #-}
decodeUtf8 :: LByteString -> String
decodeUtf8 :: ByteString -> String
decodeUtf8 = LText -> String
LT.unpack (LText -> String) -> (ByteString -> LText) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> LText
LT.decodeUtf8
{-# INLINE decodeUtf8 #-}
decodeUtf8Strict :: LByteString -> Either T.UnicodeException String
decodeUtf8Strict :: ByteString -> Either UnicodeException String
decodeUtf8Strict = (Text -> String
T.unpack (Text -> String)
-> Either UnicodeException Text -> Either UnicodeException String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (Either UnicodeException Text -> Either UnicodeException String)
-> (ByteString -> Either UnicodeException Text)
-> ByteString
-> Either UnicodeException String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either UnicodeException Text
forall a b. ConvertUtf8 a b => b -> Either UnicodeException a
decodeUtf8Strict
{-# INLINE decodeUtf8Strict #-}
instance ConvertUtf8 Text LByteString where
encodeUtf8 :: Text -> LByteString
encodeUtf8 :: Text -> ByteString
encodeUtf8 = ByteString -> ByteString
LB.fromStrict (ByteString -> ByteString)
-> (Text -> ByteString) -> Text -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
T.encodeUtf8
{-# INLINE encodeUtf8 #-}
decodeUtf8 :: LByteString -> Text
decodeUtf8 :: ByteString -> Text
decodeUtf8 = OnDecodeError -> ByteString -> Text
T.decodeUtf8With OnDecodeError
T.lenientDecode (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
LB.toStrict
{-# INLINE decodeUtf8 #-}
decodeUtf8Strict :: LByteString -> Either T.UnicodeException Text
decodeUtf8Strict :: ByteString -> Either UnicodeException Text
decodeUtf8Strict = ByteString -> Either UnicodeException Text
T.decodeUtf8' (ByteString -> Either UnicodeException Text)
-> (ByteString -> ByteString)
-> ByteString
-> Either UnicodeException Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
LB.toStrict
{-# INLINE decodeUtf8Strict #-}
instance ConvertUtf8 LText LByteString where
encodeUtf8 :: LText -> LByteString
encodeUtf8 :: LText -> ByteString
encodeUtf8 = LText -> ByteString
LT.encodeUtf8
{-# INLINE encodeUtf8 #-}
decodeUtf8 :: LByteString -> LText
decodeUtf8 :: ByteString -> LText
decodeUtf8 = OnDecodeError -> ByteString -> LText
LT.decodeUtf8With OnDecodeError
T.lenientDecode
{-# INLINE decodeUtf8 #-}
decodeUtf8Strict :: LByteString -> Either T.UnicodeException LText
decodeUtf8Strict :: ByteString -> Either UnicodeException LText
decodeUtf8Strict = ByteString -> Either UnicodeException LText
LT.decodeUtf8'
{-# INLINE decodeUtf8Strict #-}
instance ConvertUtf8 String ShortByteString where
encodeUtf8 :: String -> ShortByteString
encodeUtf8 :: String -> ShortByteString
encodeUtf8 = ByteString -> ShortByteString
toShort (ByteString -> ShortByteString)
-> (String -> ByteString) -> String -> ShortByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
forall a b. ConvertUtf8 a b => a -> b
encodeUtf8
{-# INLINE encodeUtf8 #-}
decodeUtf8 :: ShortByteString -> String
decodeUtf8 :: ShortByteString -> String
decodeUtf8 = ByteString -> String
forall a b. ConvertUtf8 a b => b -> a
decodeUtf8 (ByteString -> String)
-> (ShortByteString -> ByteString) -> ShortByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortByteString -> ByteString
fromShort
{-# INLINE decodeUtf8 #-}
decodeUtf8Strict :: ShortByteString -> Either T.UnicodeException String
decodeUtf8Strict :: ShortByteString -> Either UnicodeException String
decodeUtf8Strict = ByteString -> Either UnicodeException String
forall a b. ConvertUtf8 a b => b -> Either UnicodeException a
decodeUtf8Strict (ByteString -> Either UnicodeException String)
-> (ShortByteString -> ByteString)
-> ShortByteString
-> Either UnicodeException String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortByteString -> ByteString
fromShort
{-# INLINE decodeUtf8Strict #-}
instance ConvertUtf8 Text ShortByteString where
encodeUtf8 :: Text -> ShortByteString
encodeUtf8 :: Text -> ShortByteString
encodeUtf8 = ByteString -> ShortByteString
toShort (ByteString -> ShortByteString)
-> (Text -> ByteString) -> Text -> ShortByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
forall a b. ConvertUtf8 a b => a -> b
encodeUtf8
{-# INLINE encodeUtf8 #-}
decodeUtf8 :: ShortByteString -> Text
decodeUtf8 :: ShortByteString -> Text
decodeUtf8 = ByteString -> Text
forall a b. ConvertUtf8 a b => b -> a
decodeUtf8 (ByteString -> Text)
-> (ShortByteString -> ByteString) -> ShortByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortByteString -> ByteString
fromShort
{-# INLINE decodeUtf8 #-}
decodeUtf8Strict :: ShortByteString -> Either T.UnicodeException Text
decodeUtf8Strict :: ShortByteString -> Either UnicodeException Text
decodeUtf8Strict = ByteString -> Either UnicodeException Text
forall a b. ConvertUtf8 a b => b -> Either UnicodeException a
decodeUtf8Strict (ByteString -> Either UnicodeException Text)
-> (ShortByteString -> ByteString)
-> ShortByteString
-> Either UnicodeException Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortByteString -> ByteString
fromShort
{-# INLINE decodeUtf8Strict #-}
instance ConvertUtf8 LText ShortByteString where
encodeUtf8 :: LText -> ShortByteString
encodeUtf8 :: LText -> ShortByteString
encodeUtf8 = ByteString -> ShortByteString
toShort (ByteString -> ShortByteString)
-> (LText -> ByteString) -> LText -> ShortByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LText -> ByteString
forall a b. ConvertUtf8 a b => a -> b
encodeUtf8
{-# INLINE encodeUtf8 #-}
decodeUtf8 :: ShortByteString -> LText
decodeUtf8 :: ShortByteString -> LText
decodeUtf8 = ByteString -> LText
forall a b. ConvertUtf8 a b => b -> a
decodeUtf8 (ByteString -> LText)
-> (ShortByteString -> ByteString) -> ShortByteString -> LText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortByteString -> ByteString
fromShort
{-# INLINE decodeUtf8 #-}
decodeUtf8Strict :: ShortByteString -> Either T.UnicodeException LText
decodeUtf8Strict :: ShortByteString -> Either UnicodeException LText
decodeUtf8Strict = ByteString -> Either UnicodeException LText
forall a b. ConvertUtf8 a b => b -> Either UnicodeException a
decodeUtf8Strict (ByteString -> Either UnicodeException LText)
-> (ShortByteString -> ByteString)
-> ShortByteString
-> Either UnicodeException LText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortByteString -> ByteString
fromShort
{-# INLINE decodeUtf8Strict #-}
class ToText a where
toText :: a -> Text
instance ToText String where
toText :: String -> Text
toText :: String -> Text
toText = String -> Text
T.pack
{-# INLINE toText #-}
instance ToText Text where
toText :: Text -> Text
toText :: Text -> Text
toText = Text -> Text
forall a. a -> a
id
{-# INLINE toText #-}
instance ToText LText where
toText :: LText -> Text
toText :: LText -> Text
toText = LText -> Text
LT.toStrict
{-# INLINE toText #-}
instance EncodingError ToText "ByteString" "Text" => ToText ByteString where
toText :: ByteString -> Text
toText :: ByteString -> Text
toText = String -> ByteString -> Text
forall a. HasCallStack => String -> a
error String
"Unreachable ByteString instance of ToText"
instance EncodingError ToText "LByteString" "Text" => ToText LByteString where
toText :: LByteString -> Text
toText :: ByteString -> Text
toText = String -> ByteString -> Text
forall a. HasCallStack => String -> a
error String
"Unreachable LByteString instance of ToText"
instance EncodingError ToText "ShortByteString" "Text" => ToText ShortByteString where
toText :: ShortByteString -> Text
toText :: ShortByteString -> Text
toText = String -> ShortByteString -> Text
forall a. HasCallStack => String -> a
error String
"Unreachable ShortByteString instance of ToText"
class ToLText a where
toLText :: a -> LText
instance ToLText String where
toLText :: String -> LText
toLText :: String -> LText
toLText = String -> LText
LT.pack
{-# INLINE toLText #-}
instance ToLText Text where
toLText :: Text -> LText
toLText :: Text -> LText
toLText = Text -> LText
LT.fromStrict
{-# INLINE toLText #-}
instance ToLText LT.Text where
toLText :: LText -> LText
toLText :: LText -> LText
toLText = LText -> LText
forall a. a -> a
id
{-# INLINE toLText #-}
instance EncodingError ToLText "ByteString" "LText" => ToLText ByteString where
toLText :: ByteString -> LText
toLText :: ByteString -> LText
toLText = String -> ByteString -> LText
forall a. HasCallStack => String -> a
error String
"Unreachable ByteString instance of ToLText"
instance EncodingError ToLText "LByteString" "LText" => ToLText LByteString where
toLText :: LByteString -> LText
toLText :: ByteString -> LText
toLText = String -> ByteString -> LText
forall a. HasCallStack => String -> a
error String
"Unreachable LByteString instance of ToLText"
instance EncodingError ToLText "ShortByteString" "LText" => ToLText ShortByteString where
toLText :: ShortByteString -> LText
toLText :: ShortByteString -> LText
toLText = String -> ShortByteString -> LText
forall a. HasCallStack => String -> a
error String
"Unreachable ShortByteString instance of ToLText"
class ToString a where
toString :: a -> String
instance ToString String where
toString :: String -> String
toString :: String -> String
toString = String -> String
forall a. a -> a
id
{-# INLINE toString #-}
instance ToString Text where
toString :: Text -> String
toString :: Text -> String
toString = Text -> String
T.unpack
{-# INLINE toString #-}
instance ToString LText where
toString :: LText -> String
toString :: LText -> String
toString = LText -> String
LT.unpack
{-# INLINE toString #-}
instance EncodingError ToString "ByteString" "String" => ToString ByteString where
toString :: ByteString -> String
toString :: ByteString -> String
toString = String -> ByteString -> String
forall a. HasCallStack => String -> a
error String
"Unreachable ByteString instance of ToString"
instance EncodingError ToString "LByteString" "String" => ToString LByteString where
toString :: LByteString -> String
toString :: ByteString -> String
toString = String -> ByteString -> String
forall a. HasCallStack => String -> a
error String
"Unreachable LByteString instance of ToString"
instance EncodingError ToString "ShortByteString" "String" => ToString ShortByteString where
toString :: ShortByteString -> String
toString :: ShortByteString -> String
toString = String -> ShortByteString -> String
forall a. HasCallStack => String -> a
error String
"Unreachable ShortByteString instance of ToString"
type family EncodingError
(c :: Type -> Constraint)
(from :: Symbol)
(to :: Symbol)
:: Constraint
where
EncodingError c from to = TypeError
( 'Text "Type '" ':<>: 'Text from ':<>: 'Text "' doesn't have instance of '"
':<>: 'ShowType c ':<>: 'Text "'."
':$$: 'Text "Use 'decodeUtf8' or 'decodeUtf8Strict' to convert from UTF-8:"
':$$: 'Text " decodeUtf8 :: " ':<>: 'Text from
':<>: 'Text " -> " ':<>: 'Text to
':$$: 'Text " decodeUtf8Strict :: " ':<>: 'Text from
':<>: 'Text " -> Either UnicodeException " ':<>: 'Text to
)
readEither :: (Read a) => String -> Either Text a
readEither :: String -> Either Text a
readEither = (String -> Text) -> Either String a -> Either Text a
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first String -> Text
forall a. ToText a => a -> Text
toText (Either String a -> Either Text a)
-> (String -> Either String a) -> String -> Either Text a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Either String a
forall a. Read a => String -> Either String a
Text.Read.readEither
{-# INLINEABLE readEither #-}
show :: forall b a . (Show.Show a, IsString b) => a -> b
show :: a -> b
show a
x = String -> b
forall a. IsString a => String -> a
fromString (a -> String
forall a. Show a => a -> String
Show.show a
x)
{-# INLINE show #-}
{-# SPECIALIZE show :: Show.Show a => a -> Text #-}
{-# SPECIALIZE show :: Show.Show a => a -> LText #-}
{-# SPECIALIZE show :: Show.Show a => a -> ByteString #-}
{-# SPECIALIZE show :: Show.Show a => a -> LByteString #-}
{-# SPECIALIZE show :: Show.Show a => a -> String #-}
class LazyStrict l s | l -> s, s -> l where
toLazy :: s -> l
toStrict :: l -> s
fromLazy :: LazyStrict l s => l -> s
fromLazy :: l -> s
fromLazy = l -> s
forall l s. LazyStrict l s => l -> s
toStrict
{-# INLINE fromLazy #-}
{-# SPECIALIZE fromLazy :: LByteString -> ByteString #-}
{-# SPECIALIZE fromLazy :: LText -> Text #-}
fromStrict :: LazyStrict l s => s -> l
fromStrict :: s -> l
fromStrict = s -> l
forall l s. LazyStrict l s => s -> l
toLazy
{-# INLINE fromStrict #-}
{-# SPECIALIZE fromStrict :: ByteString -> LByteString #-}
{-# SPECIALIZE fromStrict :: Text -> LText #-}
instance LazyStrict LByteString ByteString where
toLazy :: ByteString -> LByteString
toLazy :: ByteString -> ByteString
toLazy = ByteString -> ByteString
LB.fromStrict
{-# INLINE toLazy #-}
toStrict :: LByteString -> ByteString
toStrict :: ByteString -> ByteString
toStrict = ByteString -> ByteString
LB.toStrict
{-# INLINE toStrict #-}
instance LazyStrict LText Text where
toLazy :: Text -> LText
toLazy :: Text -> LText
toLazy = Text -> LText
LT.fromStrict
{-# INLINE toLazy #-}
toStrict :: LText -> Text
toStrict :: LText -> Text
toStrict = LText -> Text
LT.toStrict
{-# INLINE toStrict #-}