{-# LANGUAGE CPP                #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric      #-}

-- | Compact representation of short 'Strings'
--
-- This module is designed to be import qualifeid
--
-- @
-- import Distribution.Utils.ShortText (ShortText)
-- import qualified Distribution.Utils.ShortText as ShortText
-- @
module Distribution.Utils.ShortText
    ( -- * 'ShortText' type
      ShortText
    , toShortText
    , fromShortText
    , unsafeFromUTF8BS

      -- * Operations
    , null
    , length

      -- * internal utilities
    , decodeStringUtf8
    , encodeStringUtf8
    ) where

import Distribution.Compat.Prelude hiding (length, null)
import Prelude ()

import Distribution.Utils.String     (decodeStringUtf8, encodeStringUtf8)
import Distribution.Utils.Structured (Structured (..), nominalStructure)

#if defined(MIN_VERSION_bytestring)
# if MIN_VERSION_bytestring(0,10,4)
# define HAVE_SHORTBYTESTRING 1
# endif
#endif

-- Hack for GHC bootstrapping
--
-- Currently (as of GHC 8.1), GHC bootstraps Cabal by building
-- binary and Cabal in one giant ghc --make command.  This
-- means no MIN_VERSION_binary macro is available.
--
-- We could try to cleverly figure something out in this case,
-- but there is a better plan: just use the unoptimized version
-- of the Binary instance.  We're not going to use it for anything
-- real in any case.
--
-- WARNING: Don't use MIN_VERSION_binary to smooth over a BC-break!
--
#ifndef MIN_VERSION_binary
#define MIN_VERSION_binary(x, y, z) 0
#endif

import qualified Data.ByteString as BS
import qualified Data.List       as List

#if HAVE_SHORTBYTESTRING
import qualified Data.ByteString.Short as BS.Short
#else
import Distribution.Utils.Generic (fromUTF8BS)
#endif

-- | Construct 'ShortText' from 'String'
toShortText :: String -> ShortText

-- | Convert 'ShortText' to 'String'
fromShortText :: ShortText -> String

-- | Convert from UTF-8 encoded strict 'ByteString'.
--
-- @since 3.2.0.0
unsafeFromUTF8BS :: BS.ByteString -> ShortText

-- | Text whether 'ShortText' is empty.
--
-- @since 3.2.0.0
null :: ShortText -> Bool

-- | Compact representation of short 'Strings'
--
-- The data is stored internally as UTF8 in an
-- 'BS.Short.ShortByteString' when compiled against @bytestring >=
-- 0.10.4@, and otherwise the fallback is to use plain old non-compat
-- '[Char]'.
--
-- Note: This type is for internal uses (such as e.g. 'PackageName')
-- and shall not be exposed in Cabal's API
--
-- @since 2.0.0.2
#if HAVE_SHORTBYTESTRING
newtype ShortText = ST { ShortText -> ShortByteString
unST :: BS.Short.ShortByteString }
                  deriving (ShortText -> ShortText -> Bool
(ShortText -> ShortText -> Bool)
-> (ShortText -> ShortText -> Bool) -> Eq ShortText
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ShortText -> ShortText -> Bool
== :: ShortText -> ShortText -> Bool
$c/= :: ShortText -> ShortText -> Bool
/= :: ShortText -> ShortText -> Bool
Eq,Eq ShortText
Eq ShortText
-> (ShortText -> ShortText -> Ordering)
-> (ShortText -> ShortText -> Bool)
-> (ShortText -> ShortText -> Bool)
-> (ShortText -> ShortText -> Bool)
-> (ShortText -> ShortText -> Bool)
-> (ShortText -> ShortText -> ShortText)
-> (ShortText -> ShortText -> ShortText)
-> Ord ShortText
ShortText -> ShortText -> Bool
ShortText -> ShortText -> Ordering
ShortText -> ShortText -> ShortText
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: ShortText -> ShortText -> Ordering
compare :: ShortText -> ShortText -> Ordering
$c< :: ShortText -> ShortText -> Bool
< :: ShortText -> ShortText -> Bool
$c<= :: ShortText -> ShortText -> Bool
<= :: ShortText -> ShortText -> Bool
$c> :: ShortText -> ShortText -> Bool
> :: ShortText -> ShortText -> Bool
$c>= :: ShortText -> ShortText -> Bool
>= :: ShortText -> ShortText -> Bool
$cmax :: ShortText -> ShortText -> ShortText
max :: ShortText -> ShortText -> ShortText
$cmin :: ShortText -> ShortText -> ShortText
min :: ShortText -> ShortText -> ShortText
Ord,(forall x. ShortText -> Rep ShortText x)
-> (forall x. Rep ShortText x -> ShortText) -> Generic ShortText
forall x. Rep ShortText x -> ShortText
forall x. ShortText -> Rep ShortText x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ShortText -> Rep ShortText x
$cto :: forall x. Rep ShortText x -> ShortText
Generic,Typeable ShortText
Typeable ShortText
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> ShortText -> c ShortText)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c ShortText)
-> (ShortText -> Constr)
-> (ShortText -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c ShortText))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c ShortText))
-> ((forall b. Data b => b -> b) -> ShortText -> ShortText)
-> (forall r r'.
    (r -> r' -> r)
    -> r -> (forall d. Data d => d -> r') -> ShortText -> r)
-> (forall r r'.
    (r' -> r -> r)
    -> r -> (forall d. Data d => d -> r') -> ShortText -> r)
-> (forall u. (forall d. Data d => d -> u) -> ShortText -> [u])
-> (forall u.
    Int -> (forall d. Data d => d -> u) -> ShortText -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> ShortText -> m ShortText)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> ShortText -> m ShortText)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> ShortText -> m ShortText)
-> Data ShortText
ShortText -> Constr
ShortText -> DataType
(forall b. Data b => b -> b) -> ShortText -> ShortText
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> ShortText -> u
forall u. (forall d. Data d => d -> u) -> ShortText -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> ShortText -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> ShortText -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> ShortText -> m ShortText
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ShortText -> m ShortText
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c ShortText
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ShortText -> c ShortText
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c ShortText)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c ShortText)
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ShortText -> c ShortText
gfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ShortText -> c ShortText
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c ShortText
gunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c ShortText
$ctoConstr :: ShortText -> Constr
toConstr :: ShortText -> Constr
$cdataTypeOf :: ShortText -> DataType
dataTypeOf :: ShortText -> DataType
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c ShortText)
dataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c ShortText)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c ShortText)
dataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c ShortText)
$cgmapT :: (forall b. Data b => b -> b) -> ShortText -> ShortText
gmapT :: (forall b. Data b => b -> b) -> ShortText -> ShortText
$cgmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> ShortText -> r
gmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> ShortText -> r
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> ShortText -> r
gmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> ShortText -> r
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> ShortText -> [u]
gmapQ :: forall u. (forall d. Data d => d -> u) -> ShortText -> [u]
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> ShortText -> u
gmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> ShortText -> u
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> ShortText -> m ShortText
gmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> ShortText -> m ShortText
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ShortText -> m ShortText
gmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ShortText -> m ShortText
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ShortText -> m ShortText
gmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ShortText -> m ShortText
Data,Typeable)

# if MIN_VERSION_binary(0,8,1)
instance Binary ShortText where
    put :: ShortText -> Put
put = ShortByteString -> Put
forall t. Binary t => t -> Put
put (ShortByteString -> Put)
-> (ShortText -> ShortByteString) -> ShortText -> Put
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortText -> ShortByteString
unST
    get :: Get ShortText
get = (ShortByteString -> ShortText)
-> Get ShortByteString -> Get ShortText
forall a b. (a -> b) -> Get a -> Get b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ShortByteString -> ShortText
ST Get ShortByteString
forall t. Binary t => Get t
get
# else
instance Binary ShortText where
    put = put . BS.Short.fromShort . unST
    get = fmap (ST . BS.Short.toShort) get
# endif


toShortText :: String -> ShortText
toShortText = ShortByteString -> ShortText
ST (ShortByteString -> ShortText)
-> (String -> ShortByteString) -> String -> ShortText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> ShortByteString
BS.Short.pack ([Word8] -> ShortByteString)
-> (String -> [Word8]) -> String -> ShortByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [Word8]
encodeStringUtf8

fromShortText :: ShortText -> String
fromShortText = [Word8] -> String
decodeStringUtf8 ([Word8] -> String)
-> (ShortText -> [Word8]) -> ShortText -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortByteString -> [Word8]
BS.Short.unpack (ShortByteString -> [Word8])
-> (ShortText -> ShortByteString) -> ShortText -> [Word8]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortText -> ShortByteString
unST

unsafeFromUTF8BS :: ByteString -> ShortText
unsafeFromUTF8BS = ShortByteString -> ShortText
ST (ShortByteString -> ShortText)
-> (ByteString -> ShortByteString) -> ByteString -> ShortText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ShortByteString
BS.Short.toShort

null :: ShortText -> Bool
null = ShortByteString -> Bool
BS.Short.null (ShortByteString -> Bool)
-> (ShortText -> ShortByteString) -> ShortText -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortText -> ShortByteString
unST
#else
newtype ShortText = ST { unST :: String }
                  deriving (Eq,Ord,Generic,Data,Typeable)

instance Binary ShortText where
    put = put . encodeStringUtf8 . unST
    get = fmap (ST . decodeStringUtf8) get

toShortText = ST

fromShortText = unST

unsafeFromUTF8BS = ST . fromUTF8BS

null = List.null . unST
#endif

instance Structured ShortText where structure :: Proxy ShortText -> Structure
structure = Proxy ShortText -> Structure
forall {k} (a :: k). Typeable a => Proxy a -> Structure
nominalStructure

instance NFData ShortText where
    rnf :: ShortText -> ()
rnf = ShortByteString -> ()
forall a. NFData a => a -> ()
rnf (ShortByteString -> ())
-> (ShortText -> ShortByteString) -> ShortText -> ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortText -> ShortByteString
unST

instance Show ShortText where
    show :: ShortText -> String
show = ShowS
forall a. Show a => a -> String
show ShowS -> (ShortText -> String) -> ShortText -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortText -> String
fromShortText

instance Read ShortText where
    readsPrec :: Int -> ReadS ShortText
readsPrec Int
p = ((String, String) -> (ShortText, String))
-> [(String, String)] -> [(ShortText, String)]
forall a b. (a -> b) -> [a] -> [b]
map ((String -> ShortText) -> (String, String) -> (ShortText, String)
forall b c d. (b -> c) -> (b, d) -> (c, d)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first String -> ShortText
toShortText) ([(String, String)] -> [(ShortText, String)])
-> (String -> [(String, String)]) -> ReadS ShortText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String -> [(String, String)]
forall a. Read a => Int -> ReadS a
readsPrec Int
p

instance Semigroup ShortText where
    ST ShortByteString
a <> :: ShortText -> ShortText -> ShortText
<> ST ShortByteString
b = ShortByteString -> ShortText
ST (ShortByteString -> ShortByteString -> ShortByteString
forall a. Monoid a => a -> a -> a
mappend ShortByteString
a ShortByteString
b)

instance Monoid ShortText where
    mempty :: ShortText
mempty = ShortByteString -> ShortText
ST ShortByteString
forall a. Monoid a => a
mempty
    mappend :: ShortText -> ShortText -> ShortText
mappend = ShortText -> ShortText -> ShortText
forall a. Semigroup a => a -> a -> a
(<>)

instance IsString ShortText where
    fromString :: String -> ShortText
fromString = String -> ShortText
toShortText

-- | /O(n)/. Length in characters. /Slow/ as converts to string.
--
-- @since 3.2.0.0
length :: ShortText -> Int
length :: ShortText -> Int
length = String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
List.length (String -> Int) -> (ShortText -> String) -> ShortText -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortText -> String
fromShortText
-- Note: avoid using it, we use it @cabal check@ implementation, where it's ok.