{-# LANGUAGE CPP, FlexibleInstances, OverloadedStrings #-}

-- |
-- Module      : Data.Text.Buildable
-- Copyright   : (c) 2011 MailRank, Inc.
--
-- License     : BSD-style
-- Maintainer  : bos@serpentine.com
-- Stability   : experimental
-- Portability : GHC
--
-- Types that can be rendered to a 'Builder'.

module Data.Text.Buildable
    (
      Buildable(..)
    ) where

#if MIN_VERSION_base(4,8,0)
import Data.Void (Void, absurd)
#endif

import Data.Semigroup ((<>))
import Data.Monoid (mempty)
import Data.Int (Int8, Int16, Int32, Int64)
import Data.Fixed (Fixed, HasResolution, showFixed)
import Data.Ratio (Ratio, denominator, numerator)
import Data.Text.Format.Int (decimal, hexadecimal)
import Data.Text.Format.Types (Hex(..), Shown(..))
import Data.Text.Lazy.Builder
import Data.Time.Calendar (Day, showGregorian)
import Data.Time.Clock (DiffTime, NominalDiffTime, UTCTime, UniversalTime)
import Data.Time.Clock (getModJulianDate)
import Data.Time.LocalTime (LocalTime, TimeOfDay, TimeZone, ZonedTime)
import Data.Word (Word, Word8, Word16, Word32, Word64)
import Foreign.Ptr (IntPtr, WordPtr, Ptr, ptrToWordPtr)
import qualified Data.Double.Conversion.Text as C
import qualified Data.Text as ST
import qualified Data.Text.Lazy as LT

-- | The class of types that can be rendered to a 'Builder'.
class Buildable p where
    build :: p -> Builder

instance Buildable Builder where
    build :: Builder -> Builder
build = forall a. a -> a
id

#if MIN_VERSION_base(4,8,0)
instance Buildable Void where
    build :: Void -> Builder
build = forall a. Void -> a
absurd
#endif

instance Buildable LT.Text where
    build :: Text -> Builder
build = Text -> Builder
fromLazyText
    {-# INLINE build #-}

instance Buildable ST.Text where
    build :: Text -> Builder
build = Text -> Builder
fromText
    {-# INLINE build #-}

instance Buildable Char where
    build :: Char -> Builder
build = Char -> Builder
singleton
    {-# INLINE build #-}

instance Buildable [Char] where
    build :: [Char] -> Builder
build = [Char] -> Builder
fromString
    {-# INLINE build #-}

instance (Integral a) => Buildable (Hex a) where
    build :: Hex a -> Builder
build = forall a. Integral a => a -> Builder
hexadecimal
    {-# INLINE build #-}

instance Buildable Int8 where
    build :: Int8 -> Builder
build = forall a. Integral a => a -> Builder
decimal
    {-# INLINE build #-}

instance Buildable Int16 where
    build :: Int16 -> Builder
build = forall a. Integral a => a -> Builder
decimal
    {-# INLINE build #-}

instance Buildable Int32 where
    build :: Int32 -> Builder
build = forall a. Integral a => a -> Builder
decimal
    {-# INLINE build #-}

instance Buildable Int where
    build :: Int -> Builder
build = forall a. Integral a => a -> Builder
decimal
    {-# INLINE build #-}

instance Buildable Int64 where
    build :: Int64 -> Builder
build = forall a. Integral a => a -> Builder
decimal
    {-# INLINE build #-}

instance Buildable Integer where
    build :: Integer -> Builder
build = forall a. Integral a => a -> Builder
decimal
    {-# INLINE build #-}

instance (HasResolution a) => Buildable (Fixed a) where
    build :: Fixed a -> Builder
build = forall p. Buildable p => p -> Builder
build forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {k} (a :: k). HasResolution a => Bool -> Fixed a -> [Char]
showFixed Bool
False
    {-# INLINE build #-}

instance Buildable Word8 where
    build :: Word8 -> Builder
build = forall a. Integral a => a -> Builder
decimal
    {-# INLINE build #-}

instance Buildable Word16 where
    build :: Word16 -> Builder
build = forall a. Integral a => a -> Builder
decimal
    {-# INLINE build #-}

instance Buildable Word32 where
    build :: Word32 -> Builder
build = forall a. Integral a => a -> Builder
decimal
    {-# INLINE build #-}

instance Buildable Word where
    build :: Word -> Builder
build = forall a. Integral a => a -> Builder
decimal
    {-# INLINE build #-}

instance Buildable Word64 where
    build :: Word64 -> Builder
build = forall a. Integral a => a -> Builder
decimal
    {-# INLINE build #-}

instance (Integral a, Buildable a) => Buildable (Ratio a) where
    {-# SPECIALIZE instance Buildable (Ratio Integer) #-}
    build :: Ratio a -> Builder
build Ratio a
a = forall p. Buildable p => p -> Builder
build (forall a. Ratio a -> a
numerator Ratio a
a) forall a. Semigroup a => a -> a -> a
<> Char -> Builder
singleton Char
'/' forall a. Semigroup a => a -> a -> a
<> forall p. Buildable p => p -> Builder
build (forall a. Ratio a -> a
denominator Ratio a
a)

instance Buildable Float where
    build :: Float -> Builder
build = Text -> Builder
fromText forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Double -> Text
C.toPrecision Int
6 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Real a, Fractional b) => a -> b
realToFrac
    {-# INLINE build #-}

instance Buildable Double where
    build :: Double -> Builder
build = Text -> Builder
fromText forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Double -> Text
C.toPrecision Int
6
    {-# INLINE build #-}

instance Buildable DiffTime where
    build :: DiffTime -> Builder
build = forall p. Buildable p => p -> Builder
build forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Shown a
Shown
    {-# INLINE build #-}

instance Buildable NominalDiffTime where
    build :: NominalDiffTime -> Builder
build = forall p. Buildable p => p -> Builder
build forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Shown a
Shown
    {-# INLINE build #-}

instance Buildable UTCTime where
    build :: UTCTime -> Builder
build = forall p. Buildable p => p -> Builder
build forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Shown a
Shown
    {-# INLINE build #-}

instance Buildable UniversalTime where
    build :: UniversalTime -> Builder
build = forall p. Buildable p => p -> Builder
build forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Shown a
Shown forall b c a. (b -> c) -> (a -> b) -> a -> c
. UniversalTime -> Rational
getModJulianDate
    {-# INLINE build #-}

instance Buildable Day where
    build :: Day -> Builder
build = [Char] -> Builder
fromString forall b c a. (b -> c) -> (a -> b) -> a -> c
. Day -> [Char]
showGregorian
    {-# INLINE build #-}

instance (Show a) => Buildable (Shown a) where
    build :: Shown a -> Builder
build = [Char] -> Builder
fromString forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> [Char]
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Shown a -> a
shown
    {-# INLINE build #-}

instance (Buildable a) => Buildable (Maybe a) where
    build :: Maybe a -> Builder
build Maybe a
Nothing = forall a. Monoid a => a
mempty
    build (Just a
v) = forall p. Buildable p => p -> Builder
build a
v
    {-# INLINE build #-}

instance Buildable TimeOfDay where
    build :: TimeOfDay -> Builder
build = forall p. Buildable p => p -> Builder
build forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Shown a
Shown
    {-# INLINE build #-}

instance Buildable TimeZone where
    build :: TimeZone -> Builder
build = forall p. Buildable p => p -> Builder
build forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Shown a
Shown
    {-# INLINE build #-}

instance Buildable LocalTime where
    build :: LocalTime -> Builder
build = forall p. Buildable p => p -> Builder
build forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Shown a
Shown
    {-# INLINE build #-}

instance Buildable ZonedTime where
    build :: ZonedTime -> Builder
build = forall p. Buildable p => p -> Builder
build forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Shown a
Shown
    {-# INLINE build #-}

instance Buildable IntPtr where
    build :: IntPtr -> Builder
build IntPtr
p = Text -> Builder
fromText Text
"0x" forall a. Semigroup a => a -> a -> a
<> forall a. Integral a => a -> Builder
hexadecimal IntPtr
p

instance Buildable WordPtr where
    build :: WordPtr -> Builder
build WordPtr
p = Text -> Builder
fromText Text
"0x" forall a. Semigroup a => a -> a -> a
<> forall a. Integral a => a -> Builder
hexadecimal WordPtr
p

instance Buildable (Ptr a) where
    build :: Ptr a -> Builder
build = forall p. Buildable p => p -> Builder
build forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Ptr a -> WordPtr
ptrToWordPtr

instance Buildable Bool where
    build :: Bool -> Builder
build Bool
True = Text -> Builder
fromText Text
"True"
    build Bool
False = Text -> Builder
fromText Text
"False"