module Data.ByteString.Conversion.To
    ( ToByteString (..)
    , Builder
    , toByteString
    , toByteString'
    , runBuilder
    ) where
import Data.ByteString (ByteString)
import Data.ByteString.Conversion.Internal
import Data.ByteString.Lazy.Builder
import Data.ByteString.Lazy.Builder.Extras hiding (runBuilder)
import Data.Double.Conversion.Text
import Data.Int
import Data.List (intersperse)
import Data.Monoid
import Data.Text (Text)
import Data.Text.Encoding (encodeUtf8)
import Data.Word
import GHC.Float (float2Double)
import qualified Data.ByteString.Lazy    as L
import qualified Data.Text               as T
import qualified Data.Text.Lazy          as TL
import qualified Data.Text.Lazy.Encoding as TL
class ToByteString a where
    builder :: a -> Builder
instance ToByteString Builder      where builder x = x
instance ToByteString L.ByteString where builder x = lazyByteString x
instance ToByteString ByteString   where builder x = byteString x
instance ToByteString Text         where builder x = byteString $ encodeUtf8 x
instance ToByteString TL.Text      where builder x = lazyByteString $ TL.encodeUtf8 x
instance ToByteString Char         where builder x = builder $ T.singleton x
instance ToByteString [Char]       where builder x = builder $ TL.pack x
instance ToByteString Float        where builder x = builder $ toShortest $ float2Double x
instance ToByteString Double       where builder x = builder $ toShortest x
instance ToByteString Int          where builder x = intDec x
instance ToByteString Int8         where builder x = int8Dec x
instance ToByteString Int16        where builder x = int16Dec x
instance ToByteString Int32        where builder x = int32Dec x
instance ToByteString Int64        where builder x = int64Dec x
instance ToByteString Integer      where builder x = integerDec x
instance ToByteString Word         where builder x = wordDec x
instance ToByteString Word8        where builder x = word8Dec x
instance ToByteString Word16       where builder x = word16Dec x
instance ToByteString Word32       where builder x = word32Dec x
instance ToByteString Word64       where builder x = word64Dec x
instance ToByteString (Hex Int)    where builder (Hex x) = sign x <> wordHex (toWord x)
instance ToByteString (Hex Int8)   where builder (Hex x) = sign x <> word8Hex (toWord x)
instance ToByteString (Hex Int16)  where builder (Hex x) = sign x <> word16Hex (toWord x)
instance ToByteString (Hex Int32)  where builder (Hex x) = sign x <> word32Hex (toWord x)
instance ToByteString (Hex Int64)  where builder (Hex x) = sign x <> word64Hex (toWord x)
instance ToByteString (Hex Word)   where builder (Hex x) = wordHex x
instance ToByteString (Hex Word8)  where builder (Hex x) = word8Hex x
instance ToByteString (Hex Word16) where builder (Hex x) = word16Hex x
instance ToByteString (Hex Word32) where builder (Hex x) = word32Hex x
instance ToByteString (Hex Word64) where builder (Hex x) = word64Hex x
instance ToByteString a => ToByteString (List a) where
    builder = mconcat . intersperse comma . map builder . fromList
instance ToByteString Bool where
    builder True  = byteString "true"
    builder False = byteString "false"
toByteString :: ToByteString a => a -> L.ByteString
toByteString = runBuilder . builder
toByteString' :: ToByteString a => a -> ByteString
toByteString' = L.toStrict . toByteString
runBuilder :: Builder -> L.ByteString
runBuilder = toLazyByteStringWith (safeStrategy 32 smallChunkSize) L.empty
sign :: Integral a => a -> Builder
sign n = if n < 0 then minus else mempty
toWord :: (Integral a, Integral b) => a -> b
toWord = fromIntegral . abs
comma, minus :: Builder
comma = byteString ","
minus = byteString "-"