-----------------------------------------------------------------------------
{-# LANGUAGE CPP               #-}
{-# LANGUAGE FlexibleInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Miso.String
-- Copyright   :  (C) 2016-2025 David M. Johnson
-- License     :  BSD3-style (see the file LICENSE)
-- Maintainer  :  David M. Johnson <code@dmj.io>
-- Stability   :  experimental
-- Portability :  non-portable
----------------------------------------------------------------------------
module Miso.String
  ( -- ** Classes
    ToMisoString (..)
  , FromMisoString (..)
    -- ** Types
  , MisoString
    -- ** Functions
  , ms
  , fromMisoString
    -- ** Re-exports
  , module S
  ) where
----------------------------------------------------------------------------
import           Control.Exception (SomeException)
import qualified Data.ByteString         as B
import qualified Data.ByteString.Builder as B
import qualified Data.ByteString.Lazy    as BL
import           Data.JSString
import           Data.JSString.Text
import           Data.Monoid             as S
import           Data.Text               as S hiding (
#if MIN_VERSION_text(2,1,2)
  show,
#endif
#if MIN_VERSION_text(1,2,5)
  elem,
#endif
  )
import qualified Data.Text               as T
import qualified Data.Text.Encoding      as T
import qualified Data.Text.Lazy          as LT
import qualified Data.Text.Lazy.Encoding as LT
import           Text.Read(readEither)
import           Prelude                 as P
----------------------------------------------------------------------------
-- | String type swappable based on compiler
type MisoString = Text
----------------------------------------------------------------------------
-- | Convenience class for creating `MisoString` from other string-like types
class ToMisoString str where
  toMisoString :: str -> MisoString
----------------------------------------------------------------------------
-- | Class from safely parsing 'MisoString'
class FromMisoString t where
  fromMisoStringEither :: MisoString -> Either String t
----------------------------------------------------------------------------
-- | Parses a `MisoString`, throws an error when decoding
-- fails. Use `fromMisoStringEither` for as a safe alternative.
fromMisoString :: FromMisoString a => MisoString -> a
fromMisoString :: forall a. FromMisoString a => MisoString -> a
fromMisoString MisoString
s =
  case MisoString -> Either String a
forall t. FromMisoString t => MisoString -> Either String t
fromMisoStringEither MisoString
s of
    Left String
err -> String -> a
forall a. HasCallStack => String -> a
error String
err
    Right a
x  -> a
x
----------------------------------------------------------------------------
-- | Convenience function, shorthand for `toMisoString`
ms :: ToMisoString str => str -> MisoString
ms :: forall str. ToMisoString str => str -> MisoString
ms = str -> MisoString
forall str. ToMisoString str => str -> MisoString
toMisoString
----------------------------------------------------------------------------
instance ToMisoString MisoString where
  toMisoString :: MisoString -> MisoString
toMisoString = MisoString -> MisoString
forall a. a -> a
id
----------------------------------------------------------------------------
instance ToMisoString SomeException where
  toMisoString :: SomeException -> MisoString
toMisoString = String -> MisoString
forall str. ToMisoString str => str -> MisoString
toMisoString (String -> MisoString)
-> (SomeException -> String) -> SomeException -> MisoString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SomeException -> String
forall a. Show a => a -> String
show
----------------------------------------------------------------------------
instance ToMisoString String where
  toMisoString :: String -> MisoString
toMisoString = String -> MisoString
T.pack
----------------------------------------------------------------------------
instance ToMisoString LT.Text where
  toMisoString :: Text -> MisoString
toMisoString = Text -> MisoString
LT.toStrict
----------------------------------------------------------------------------
instance ToMisoString JSString where
  toMisoString :: JSString -> MisoString
toMisoString = JSString -> MisoString
textFromJSString
----------------------------------------------------------------------------
instance ToMisoString B.ByteString where
  toMisoString :: ByteString -> MisoString
toMisoString = MisoString -> MisoString
forall str. ToMisoString str => str -> MisoString
toMisoString (MisoString -> MisoString)
-> (ByteString -> MisoString) -> ByteString -> MisoString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> MisoString
T.decodeUtf8
----------------------------------------------------------------------------
instance ToMisoString BL.ByteString where
  toMisoString :: ByteString -> MisoString
toMisoString = Text -> MisoString
forall str. ToMisoString str => str -> MisoString
toMisoString (Text -> MisoString)
-> (ByteString -> Text) -> ByteString -> MisoString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
LT.decodeUtf8
----------------------------------------------------------------------------
instance ToMisoString B.Builder where
  toMisoString :: Builder -> MisoString
toMisoString = ByteString -> MisoString
forall str. ToMisoString str => str -> MisoString
toMisoString (ByteString -> MisoString)
-> (Builder -> ByteString) -> Builder -> MisoString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> ByteString
B.toLazyByteString
----------------------------------------------------------------------------
instance ToMisoString Float where
  toMisoString :: Float -> MisoString
toMisoString = String -> MisoString
T.pack (String -> MisoString) -> (Float -> String) -> Float -> MisoString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Float -> String
forall a. Show a => a -> String
P.show
----------------------------------------------------------------------------
instance ToMisoString Double where
  toMisoString :: Double -> MisoString
toMisoString = String -> MisoString
T.pack (String -> MisoString)
-> (Double -> String) -> Double -> MisoString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> String
forall a. Show a => a -> String
P.show
----------------------------------------------------------------------------
instance ToMisoString Int where
  toMisoString :: Int -> MisoString
toMisoString = String -> MisoString
T.pack (String -> MisoString) -> (Int -> String) -> Int -> MisoString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String
forall a. Show a => a -> String
P.show
----------------------------------------------------------------------------
instance ToMisoString Word where
  toMisoString :: Word -> MisoString
toMisoString = String -> MisoString
T.pack (String -> MisoString) -> (Word -> String) -> Word -> MisoString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word -> String
forall a. Show a => a -> String
P.show
----------------------------------------------------------------------------
instance FromMisoString MisoString where
  fromMisoStringEither :: MisoString -> Either String MisoString
fromMisoStringEither = MisoString -> Either String MisoString
forall a b. b -> Either a b
Right
----------------------------------------------------------------------------
instance FromMisoString String where
  fromMisoStringEither :: MisoString -> Either String String
fromMisoStringEither = String -> Either String String
forall a b. b -> Either a b
Right (String -> Either String String)
-> (MisoString -> String) -> MisoString -> Either String String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MisoString -> String
T.unpack
----------------------------------------------------------------------------
instance FromMisoString LT.Text where
  fromMisoStringEither :: MisoString -> Either String Text
fromMisoStringEither = Text -> Either String Text
forall a b. b -> Either a b
Right (Text -> Either String Text)
-> (MisoString -> Text) -> MisoString -> Either String Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MisoString -> Text
LT.fromStrict
----------------------------------------------------------------------------
instance FromMisoString JSString where
  fromMisoStringEither :: MisoString -> Either String JSString
fromMisoStringEither = JSString -> Either String JSString
forall a b. b -> Either a b
Right (JSString -> Either String JSString)
-> (MisoString -> JSString) -> MisoString -> Either String JSString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MisoString -> JSString
textToJSString
----------------------------------------------------------------------------
instance FromMisoString B.ByteString where
  fromMisoStringEither :: MisoString -> Either String ByteString
fromMisoStringEither = (MisoString -> ByteString)
-> Either String MisoString -> Either String ByteString
forall a b. (a -> b) -> Either String a -> Either String b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap MisoString -> ByteString
T.encodeUtf8 (Either String MisoString -> Either String ByteString)
-> (MisoString -> Either String MisoString)
-> MisoString
-> Either String ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MisoString -> Either String MisoString
forall t. FromMisoString t => MisoString -> Either String t
fromMisoStringEither
----------------------------------------------------------------------------
instance FromMisoString BL.ByteString where
  fromMisoStringEither :: MisoString -> Either String ByteString
fromMisoStringEither = (Text -> ByteString)
-> Either String Text -> Either String ByteString
forall a b. (a -> b) -> Either String a -> Either String b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> ByteString
LT.encodeUtf8 (Either String Text -> Either String ByteString)
-> (MisoString -> Either String Text)
-> MisoString
-> Either String ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MisoString -> Either String Text
forall t. FromMisoString t => MisoString -> Either String t
fromMisoStringEither
----------------------------------------------------------------------------
instance FromMisoString B.Builder where
  fromMisoStringEither :: MisoString -> Either String Builder
fromMisoStringEither = (ByteString -> Builder)
-> Either String ByteString -> Either String Builder
forall a b. (a -> b) -> Either String a -> Either String b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString -> Builder
B.byteString (Either String ByteString -> Either String Builder)
-> (MisoString -> Either String ByteString)
-> MisoString
-> Either String Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MisoString -> Either String ByteString
forall t. FromMisoString t => MisoString -> Either String t
fromMisoStringEither
----------------------------------------------------------------------------
instance FromMisoString Float where
  fromMisoStringEither :: MisoString -> Either String Float
fromMisoStringEither = String -> Either String Float
forall a. Read a => String -> Either String a
readEither (String -> Either String Float)
-> (MisoString -> String) -> MisoString -> Either String Float
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MisoString -> String
T.unpack
----------------------------------------------------------------------------
instance FromMisoString Double where
  fromMisoStringEither :: MisoString -> Either String Double
fromMisoStringEither = String -> Either String Double
forall a. Read a => String -> Either String a
readEither (String -> Either String Double)
-> (MisoString -> String) -> MisoString -> Either String Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MisoString -> String
T.unpack
----------------------------------------------------------------------------
instance FromMisoString Int where
  fromMisoStringEither :: MisoString -> Either String Int
fromMisoStringEither = String -> Either String Int
forall a. Read a => String -> Either String a
readEither (String -> Either String Int)
-> (MisoString -> String) -> MisoString -> Either String Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MisoString -> String
T.unpack
----------------------------------------------------------------------------
instance FromMisoString Word where
  fromMisoStringEither :: MisoString -> Either String Word
fromMisoStringEither = String -> Either String Word
forall a. Read a => String -> Either String a
readEither (String -> Either String Word)
-> (MisoString -> String) -> MisoString -> Either String Word
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MisoString -> String
T.unpack
----------------------------------------------------------------------------