rio-0.1.23.0: src/RIO/Prelude/Display.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module RIO.Prelude.Display
( Utf8Builder (..)
, Display (..)
, displayShow
, utf8BuilderToText
, utf8BuilderToLazyText
, displayBytesUtf8
, writeFileUtf8Builder
) where
import Data.String (IsString (..))
import Data.ByteString (ByteString)
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Builder as BB
import Data.ByteString.Builder (Builder)
import Data.Foldable (fold)
import Data.Semigroup (Semigroup(..))
import Data.Text (Text)
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Encoding as TL
import UnliftIO
import Data.Text.Encoding (decodeUtf8With, encodeUtf8Builder)
import Data.Text.Encoding.Error (lenientDecode)
import Data.Int
import Data.Word
import System.Process.Typed (ProcessConfig, setEnvInherit)
-- | A builder of binary data, with the invariant that the underlying
-- data is supposed to be UTF-8 encoded.
--
-- @since 0.1.0.0
newtype Utf8Builder = Utf8Builder { getUtf8Builder :: Builder }
deriving (Semigroup)
-- Custom instance is created instead of deriving, otherwise list fusion breaks
-- for `mconcat`.
instance Monoid Utf8Builder where
mempty = Utf8Builder mempty
{-# INLINE mempty #-}
mappend = (Data.Semigroup.<>)
{-# INLINE mappend #-}
mconcat = fold
{-# INLINE mconcat #-}
-- | @since 0.1.0.0
instance IsString Utf8Builder where
fromString = Utf8Builder . BB.stringUtf8
-- | A typeclass for values which can be converted to a
-- 'Utf8Builder'. The intention of this typeclass is to provide a
-- human-friendly display of the data.
--
-- @since 0.1.0.0
class Display a where
{-# MINIMAL display | textDisplay #-}
display :: a -> Utf8Builder
display = display . textDisplay
-- | Display data as `Text`, which will also be used for `display` if it is
-- not overriden.
--
-- @since 0.1.7.0
textDisplay :: a -> Text
textDisplay = utf8BuilderToText . display
-- | @since 0.1.0.0
instance Display Utf8Builder where
display = id
-- | @since 0.1.0.0
instance Display Text where
display = Utf8Builder . encodeUtf8Builder
-- | @since 0.1.0.0
instance Display TL.Text where
display = foldMap display . TL.toChunks
-- | @since 0.1.0.0
instance Display Char where
display = Utf8Builder . BB.charUtf8
-- | @since 0.1.0.0
instance Display Integer where
display = Utf8Builder . BB.integerDec
-- | @since 0.1.0.0
instance Display Float where
display = Utf8Builder . BB.floatDec
instance Display Double where
display = Utf8Builder . BB.doubleDec
-- | @since 0.1.0.0
instance Display Int where
display = Utf8Builder . BB.intDec
-- | @since 0.1.0.0
instance Display Int8 where
display = Utf8Builder . BB.int8Dec
-- | @since 0.1.0.0
instance Display Int16 where
display = Utf8Builder . BB.int16Dec
-- | @since 0.1.0.0
instance Display Int32 where
display = Utf8Builder . BB.int32Dec
-- | @since 0.1.0.0
instance Display Int64 where
display = Utf8Builder . BB.int64Dec
-- | @since 0.1.0.0
instance Display Word where
display = Utf8Builder . BB.wordDec
-- | @since 0.1.0.0
instance Display Word8 where
display = Utf8Builder . BB.word8Dec
-- | @since 0.1.0.0
instance Display Word16 where
display = Utf8Builder . BB.word16Dec
-- | @since 0.1.0.0
instance Display Word32 where
display = Utf8Builder . BB.word32Dec
-- | @since 0.1.0.0
instance Display Word64 where
display = Utf8Builder . BB.word64Dec
-- | @since 0.1.0.0
instance Display SomeException where
display = fromString . displayException
-- | @since 0.1.0.0
instance Display IOException where
display = fromString . displayException
-- | @since 0.1.0.0
instance Display (ProcessConfig a b c) where
display = displayShow . setEnvInherit
-- | Use the 'Show' instance for a value to convert it to a
-- 'Utf8Builder'.
--
-- @since 0.1.0.0
displayShow :: Show a => a -> Utf8Builder
displayShow = fromString . show
-- | Convert a 'ByteString' into a 'Utf8Builder'.
--
-- /NOTE/ This function performs no checks to ensure that the data is,
-- in fact, UTF8 encoded. If you provide non-UTF8 data, later
-- functions may fail.
--
-- @since 0.1.0.0
displayBytesUtf8 :: ByteString -> Utf8Builder
displayBytesUtf8 = Utf8Builder . BB.byteString
-- | Convert a 'Utf8Builder' value into a strict 'Text'.
--
-- @since 0.1.0.0
utf8BuilderToText :: Utf8Builder -> Text
utf8BuilderToText =
decodeUtf8With lenientDecode . BL.toStrict . BB.toLazyByteString . getUtf8Builder
-- | Convert a 'Utf8Builder' value into a lazy 'Text'.
--
-- @since 0.1.0.0
utf8BuilderToLazyText :: Utf8Builder -> TL.Text
utf8BuilderToLazyText =
TL.decodeUtf8With lenientDecode . BB.toLazyByteString . getUtf8Builder
-- | Write the given 'Utf8Builder' value to a file.
--
-- @since 0.1.0.0
writeFileUtf8Builder :: MonadIO m => FilePath -> Utf8Builder -> m ()
writeFileUtf8Builder fp (Utf8Builder builder) =
liftIO $ withBinaryFile fp WriteMode $ \h -> BB.hPutBuilder h builder