{-# options_haddock prune #-}

{- |
Copyright:  (c) 2016 Stephen Diehl
            (c) 2016-2018 Serokell
            (c) 2018-2021 Kowainik
SPDX-License-Identifier: MIT
Maintainer:  Kowainik <xrom.xkov@gmail.com>
Stability:   Stable
Portability: Portable

This module implements type class which allow to have conversion to and from
'Incipit.String.Reexport.Text', 'String' and 'ByteString' types
(including both strict and lazy versions). Usually you need to export
'Incipit.String.Reexport.Text' modules qualified and use 'T.pack' \/ 'T.unpack'
functions to convert to\/from 'Incipit.String.Reexport.Text'. Now you can just
use 'toText' \/ 'toString' functions.
-}

module Incipit.String.Conversion
    ( -- * Convenient type aliases
      LText
    , LByteString

      -- * Conversion type classes
    , ConvertUtf8 (..)
    , ToText (..)
    , ToLText (..)
    , ToString (..)
    , LazyStrict (..)
    , fromLazy
    , fromStrict

      -- * Show and read functions
    , readEither
    , show
    ) where

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 GHC.TypeLits as Error
import qualified Text.Read (readEither)

import Incipit.Base
import Incipit.String.Reexport (
  ByteString,
  IsString,
  Read,
  ShortByteString,
  String,
  Text,
  fromShort,
  fromString,
  toShort,
  )


-- $setup
-- >>> import Relude

-- | Type synonym for 'Data.Text.Lazy.Text'.
type LText = LT.Text

-- | Type synonym for 'Data.ByteString.Lazy.ByteString'.
type LByteString = LB.ByteString


-- | Type class for conversion to utf8 representation of text.
class ConvertUtf8 a b where
    -- | Encode as utf8 string (usually 'B.ByteString').
    --
    -- >>> encodeUtf8 @Text @ByteString "патак"
    -- "\208\191\208\176\209\130\208\176\208\186"
    encodeUtf8 :: a -> b

    -- | Decode from utf8 string.
    --
    -- >>> decodeUtf8 @Text @ByteString "\208\191\208\176\209\130\208\176\208\186"
    -- "\1087\1072\1090\1072\1082"
    -- >>> putTextLn $ decodeUtf8 @Text @ByteString "\208\191\208\176\209\130\208\176\208\186"
    -- патак
    decodeUtf8 :: b -> a

    {- | Decode as utf8 string but returning execption if byte sequence is malformed.

#if MIN_VERSION_text(1,2,3)
    >>> decodeUtf8 @Text @ByteString "\208\208\176\209\130\208\176\208\186"
    "\65533\1072\1090\1072\1082"
#else
    >>> decodeUtf8 @Text @ByteString "\208\208\176\209\130\208\176\208\186"
    "\65533\65533\1090\1072\1082"
#endif
    >>> decodeUtf8Strict @Text @ByteString "\208\208\176\209\130\208\176\208\186"
    Left Cannot decode byte '\xd0': Data.Text.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream
    -}
    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
forall a b. ConvertUtf8 a b => b -> a
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 = LByteString -> ByteString
LB.toStrict (LByteString -> ByteString)
-> (LText -> LByteString) -> LText -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LText -> LByteString
forall a b. ConvertUtf8 a b => a -> b
encodeUtf8
    {-# INLINE encodeUtf8 #-}

    decodeUtf8 :: ByteString -> LText
    decodeUtf8 :: ByteString -> LText
decodeUtf8 = OnDecodeError -> LByteString -> LText
LT.decodeUtf8With OnDecodeError
T.lenientDecode (LByteString -> LText)
-> (ByteString -> LByteString) -> ByteString -> LText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> LByteString
LB.fromStrict
    {-# INLINE decodeUtf8 #-}

    decodeUtf8Strict :: ByteString -> Either T.UnicodeException LText
    decodeUtf8Strict :: ByteString -> Either UnicodeException LText
decodeUtf8Strict = LByteString -> Either UnicodeException LText
forall a b. ConvertUtf8 a b => b -> Either UnicodeException a
decodeUtf8Strict (LByteString -> Either UnicodeException LText)
-> (ByteString -> LByteString)
-> ByteString
-> Either UnicodeException LText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> LByteString
LB.fromStrict
    {-# INLINE decodeUtf8Strict #-}

{- | Converting 'String' to 'LB.ByteString' might be a slow operation.
Consider using lazy bytestring at first place.
-}
instance ConvertUtf8 String LByteString where
    encodeUtf8 :: String -> LByteString
    encodeUtf8 :: String -> LByteString
encodeUtf8 = LText -> LByteString
LT.encodeUtf8 (LText -> LByteString)
-> (String -> LText) -> String -> LByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> LText
LT.pack
    {-# INLINE encodeUtf8 #-}

    decodeUtf8 :: LByteString -> String
    decodeUtf8 :: LByteString -> String
decodeUtf8 = LText -> String
LT.unpack (LText -> String)
-> (LByteString -> LText) -> LByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LByteString -> LText
forall a b. ConvertUtf8 a b => b -> a
decodeUtf8
    {-# INLINE decodeUtf8 #-}

    decodeUtf8Strict :: LByteString -> Either T.UnicodeException String
    decodeUtf8Strict :: LByteString -> 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)
-> (LByteString -> Either UnicodeException Text)
-> LByteString
-> Either UnicodeException String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LByteString -> 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 -> LByteString
encodeUtf8 = ByteString -> LByteString
LB.fromStrict (ByteString -> LByteString)
-> (Text -> ByteString) -> Text -> LByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
T.encodeUtf8
    {-# INLINE encodeUtf8 #-}

    decodeUtf8 :: LByteString -> Text
    decodeUtf8 :: LByteString -> Text
decodeUtf8 = OnDecodeError -> ByteString -> Text
T.decodeUtf8With OnDecodeError
T.lenientDecode (ByteString -> Text)
-> (LByteString -> ByteString) -> LByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LByteString -> ByteString
LB.toStrict
    {-# INLINE decodeUtf8 #-}

    decodeUtf8Strict :: LByteString -> Either T.UnicodeException Text
    decodeUtf8Strict :: LByteString -> Either UnicodeException Text
decodeUtf8Strict = ByteString -> Either UnicodeException Text
T.decodeUtf8' (ByteString -> Either UnicodeException Text)
-> (LByteString -> ByteString)
-> LByteString
-> Either UnicodeException Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LByteString -> ByteString
LB.toStrict
    {-# INLINE decodeUtf8Strict #-}

instance ConvertUtf8 LText LByteString where
    encodeUtf8 :: LText -> LByteString
    encodeUtf8 :: LText -> LByteString
encodeUtf8 = LText -> LByteString
LT.encodeUtf8
    {-# INLINE encodeUtf8 #-}

    decodeUtf8 :: LByteString -> LText
    decodeUtf8 :: LByteString -> LText
decodeUtf8 = OnDecodeError -> LByteString -> LText
LT.decodeUtf8With OnDecodeError
T.lenientDecode
    {-# INLINE decodeUtf8 #-}

    decodeUtf8Strict :: LByteString -> Either T.UnicodeException LText
    decodeUtf8Strict :: LByteString -> Either UnicodeException LText
decodeUtf8Strict = LByteString -> Either UnicodeException LText
LT.decodeUtf8'
    {-# INLINE decodeUtf8Strict #-}

-- | @since 0.6.0.0
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 #-}

-- | @since 0.6.0.0
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 #-}

-- | @since 0.6.0.0
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 #-}

-- | Type class for converting other strings to 'T.Text'.
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 #-}

{- | ⚠️__CAUTION__⚠️ This instance is for custom error display only.

You should always specify encoding of bytes explicitly.

In case it is used by mistake, the user will see the following:

>>> toText ("some string" :: ByteString)
...
... Type 'ByteString' doesn't have instance of 'ToText'.
      Use 'decodeUtf8' or 'decodeUtf8Strict' to convert from UTF-8:
          decodeUtf8       :: ByteString -> Text
          decodeUtf8Strict :: ByteString -> Either UnicodeException Text
...

@since 0.6.0.0
-}
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"

{- | ⚠️__CAUTION__⚠️ This instance is for custom error display only.

You should always specify encoding of bytes explicitly.

In case it is used by mistake, the user will see the following:

>>> toText ("some string" :: LByteString)
...
... Type 'LByteString' doesn't have instance of 'ToText'.
      Use 'decodeUtf8' or 'decodeUtf8Strict' to convert from UTF-8:
          decodeUtf8       :: LByteString -> Text
          decodeUtf8Strict :: LByteString -> Either UnicodeException Text
...

@since 0.6.0.0
-}
instance EncodingError ToText "LByteString" "Text" => ToText LByteString where
    toText :: LByteString -> Text
    toText :: LByteString -> Text
toText = String -> LByteString -> Text
forall a. HasCallStack => String -> a
error String
"Unreachable LByteString instance of ToText"

{- | ⚠️__CAUTION__⚠️ This instance is for custom error display only.

You should always specify encoding of bytes explicitly.

In case it is used by mistake, the user will see the following:

>>> toText ("some string" :: ShortByteString)
...
... Type 'ShortByteString' doesn't have instance of 'ToText'.
      Use 'decodeUtf8' or 'decodeUtf8Strict' to convert from UTF-8:
          decodeUtf8       :: ShortByteString -> Text
          decodeUtf8Strict :: ShortByteString -> Either UnicodeException Text
...

@since 0.6.0.0
-}
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"

-- | Type class for converting other strings to 'LT.Text'.
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 #-}

{- | ⚠️__CAUTION__⚠️ This instance is for custom error display only.

You should always specify encoding of bytes explicitly.

In case it is used by mistake, the user will see the following:

>>> toLText ("some string" :: ByteString)
...
... Type 'ByteString' doesn't have instance of 'ToLText'.
      Use 'decodeUtf8' or 'decodeUtf8Strict' to convert from UTF-8:
          decodeUtf8       :: ByteString -> LText
          decodeUtf8Strict :: ByteString -> Either UnicodeException LText
...

@since 0.6.0.0
-}
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"

{- | ⚠️__CAUTION__⚠️ This instance is for custom error display only.

You should always specify encoding of bytes explicitly.

In case it is used by mistake, the user will see the following:

>>> toLText ("some string" :: LByteString)
...
... Type 'LByteString' doesn't have instance of 'ToLText'.
      Use 'decodeUtf8' or 'decodeUtf8Strict' to convert from UTF-8:
          decodeUtf8       :: LByteString -> LText
          decodeUtf8Strict :: LByteString -> Either UnicodeException LText
...

@since 0.6.0.0
-}
instance EncodingError ToLText "LByteString" "LText" => ToLText LByteString where
    toLText :: LByteString -> LText
    toLText :: LByteString -> LText
toLText = String -> LByteString -> LText
forall a. HasCallStack => String -> a
error String
"Unreachable LByteString instance of ToLText"

{- | ⚠️__CAUTION__⚠️ This instance is for custom error display only.

You should always specify encoding of bytes explicitly.

In case it is used by mistake, the user will see the following:

>>> toLText ("some string" :: ShortByteString)
...
... Type 'ShortByteString' doesn't have instance of 'ToLText'.
      Use 'decodeUtf8' or 'decodeUtf8Strict' to convert from UTF-8:
          decodeUtf8       :: ShortByteString -> LText
          decodeUtf8Strict :: ShortByteString -> Either UnicodeException LText
...

@since 0.6.0.0
-}
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"

-- | Type class for converting other strings to 'String'.
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 #-}

{- | ⚠️__CAUTION__⚠️ This instance is for custom error display only.

You should always specify encoding of bytes explicitly.

In case it is used by mistake, the user will see the following:

>>> toString ("some string" :: ByteString)
...
... Type 'ByteString' doesn't have instance of 'ToString'.
      Use 'decodeUtf8' or 'decodeUtf8Strict' to convert from UTF-8:
          decodeUtf8       :: ByteString -> String
          decodeUtf8Strict :: ByteString -> Either UnicodeException String
...

@since 0.6.0.0
-}
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"

{- | ⚠️__CAUTION__⚠️ This instance is for custom error display only.

You should always specify encoding of bytes explicitly.

In case it is used by mistake, the user will see the following:

>>> toString ("some string" :: LByteString)
...
... Type 'LByteString' doesn't have instance of 'ToString'.
      Use 'decodeUtf8' or 'decodeUtf8Strict' to convert from UTF-8:
          decodeUtf8       :: LByteString -> String
          decodeUtf8Strict :: LByteString -> Either UnicodeException String
...

@since 0.6.0.0
-}
instance EncodingError ToString "LByteString" "String" => ToString LByteString where
    toString :: LByteString -> String
    toString :: LByteString -> String
toString = String -> LByteString -> String
forall a. HasCallStack => String -> a
error String
"Unreachable LByteString instance of ToString"

{- | ⚠️__CAUTION__⚠️ This instance is for custom error display only.

You should always specify encoding of bytes explicitly.

In case it is used by mistake, the user will see the following:

>>> toString ("some string" :: ShortByteString)
...
... Type 'ShortByteString' doesn't have instance of 'ToString'.
      Use 'decodeUtf8' or 'decodeUtf8Strict' to convert from UTF-8:
          decodeUtf8       :: ShortByteString -> String
          decodeUtf8Strict :: ShortByteString -> Either UnicodeException String
...

@since 0.6.0.0
-}
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"

-- | Helper type family to produce error messages
type family EncodingError
    (c :: Type -> Constraint)
    (from :: Symbol)
    (to :: Symbol)
    :: Constraint
  where
    EncodingError c from to = TypeError
        ( 'Error.Text "Type '" ':<>: 'Error.Text from ':<>: 'Error.Text "' doesn't have instance of '"
        ':<>: 'ShowType c ':<>: 'Error.Text "'."
        ':$$: 'Error.Text "Use 'decodeUtf8' or 'decodeUtf8Strict' to convert from UTF-8:"
        ':$$: 'Error.Text "    decodeUtf8       :: " ':<>: 'Error.Text from
        ':<>: 'Error.Text " -> " ':<>: 'Error.Text to
        ':$$: 'Error.Text "    decodeUtf8Strict :: " ':<>: 'Error.Text from
        ':<>: 'Error.Text " -> Either UnicodeException " ':<>: 'Error.Text to
        )

{- | Version of 'Text.Read.readEither' that returns 'Text' in case of the parse
error.

>>> readEither @Int "123"
Right 123
>>> readEither @Int "aa"
Left "Prelude.read: no parse"
-}
readEither :: (Read a) => String -> Either Text a
readEither :: forall a. Read a => String -> Either Text a
readEither = (String -> Text) -> Either String a -> Either Text a
forall a b c. (a -> b) -> Either a c -> Either b c
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 #-}

{- | Generalized version of 'Prelude.show'. Unlike 'Prelude.show' this function
is polymorphic in its result type. This makes it more convenient to work with
data types like 'Incipit.String.Reexport.Text' or 'ByteString'. However, if you
pass the result of 'show' to a function that expects polymorphic argument, this
can break type inference, so use @-XTypeApplications@ to specify the textual
type explicitly.

>>> show (42 :: Int)
"42"
>>> show (42 :: Double)
"42.0"
>>> print (show @Text True)
"True"
-}
show ::  b a . (Show.Show a, IsString b) => a -> b
show :: forall b a. (Show a, IsString b) => 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  #-}

{- | Type class for lazy-strict conversions.

@since 0.1.0
-}
class LazyStrict l s | l -> s, s -> l where
    toLazy   :: s -> l
    toStrict :: l -> s

-- | Alias for 'toStrict' function.
fromLazy :: LazyStrict l s => l -> s
fromLazy :: forall l s. LazyStrict l s => l -> s
fromLazy = l -> s
forall l s. LazyStrict l s => l -> s
toStrict
{-# INLINE fromLazy #-}
{-# SPECIALIZE fromLazy :: LByteString -> ByteString  #-}
{-# SPECIALIZE fromLazy :: LText -> Text  #-}

-- | Alias for 'toLazy' function.
fromStrict :: LazyStrict l s => s -> l
fromStrict :: forall l s. LazyStrict l s => 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 -> LByteString
toLazy = ByteString -> LByteString
LB.fromStrict
    {-# INLINE toLazy #-}

    toStrict :: LByteString -> ByteString
    toStrict :: LByteString -> ByteString
toStrict = LByteString -> 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 #-}