    {-# LANGUAGE ForeignFunctionInterface #-}
    {-# LANGUAGE Trustworthy #-}

    {-# OPTIONS_HADDOCK not-home #-}

    -- | Copyright : (c) 2010 - 2011 Simon Meier
    -- License     : BSD3-style (see LICENSE)
    --
    -- Maintainer  : Simon Meier <iridcode@gmail.com>
    -- Portability : GHC
    --
    -- Constructing 'Builder's using ASCII-based encodings.
    --
    module Data.ByteString.Builder.ASCII
        (
          -- ** Formatting numbers as text
          -- | Formatting of numbers as ASCII text.
          --
          -- Note that you can also use these functions for the ISO/IEC 8859-1 and
          -- UTF-8 encodings, as the ASCII encoding is equivalent on the
          -- codepoints 0-127.

          -- *** Decimal numbers
          -- | Decimal encoding of numbers using ASCII encoded characters.
          int8Dec
        , int16Dec
        , int32Dec
        , int64Dec
        , intDec
        , integerDec

        , word8Dec
        , word16Dec
        , word32Dec
        , word64Dec
        , wordDec

        , floatDec
        , doubleDec

          -- *** Hexadecimal numbers

          -- | Encoding positive integers as hexadecimal numbers using lower-case
          -- ASCII characters. The shortest
          -- possible representation is used. For example,
          --
          -- >>> toLazyByteString (word16Hex 0x0a10)
          -- Chunk "a10" Empty
          --
          -- Note that there is no support for using upper-case characters. Please
          -- contact the maintainer, if your application cannot work without
          -- hexadecimal encodings that use upper-case characters.
          --
        , word8Hex
        , word16Hex
        , word32Hex
        , word64Hex
        , wordHex

          -- *** Fixed-width hexadecimal numbers
          --
        , int8HexFixed
        , int16HexFixed
        , int32HexFixed
        , int64HexFixed
        , word8HexFixed
        , word16HexFixed
        , word32HexFixed
        , word64HexFixed

        , floatHexFixed
        , doubleHexFixed

        , byteStringHex
        , lazyByteStringHex

        ) where

    import           Data.ByteString                                as S
    import           Data.ByteString.Lazy                           as L
    import           Data.ByteString.Builder.Internal (Builder)
    import qualified Data.ByteString.Builder.Prim                   as P
    import qualified Data.ByteString.Builder.Prim.Internal          as P
    import           Data.ByteString.Builder.RealFloat (floatDec, doubleDec)

    import           Foreign
    import           Foreign.C.Types

    ------------------------------------------------------------------------------
    -- Decimal Encoding
    ------------------------------------------------------------------------------

    -- Signed integers
    ------------------

    -- | Decimal encoding of an 'Int8' using the ASCII digits.
    --
    -- e.g.
    --
    -- > toLazyByteString (int8Dec 42)   = "42"
    -- > toLazyByteString (int8Dec (-1)) = "-1"
    --
    {-# INLINE int8Dec #-}
    int8Dec :: Int8 -> Builder
    int8Dec :: Int8 -> Builder
    int8Dec = forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Int8
    P.int8Dec

    -- | Decimal encoding of an 'Int16' using the ASCII digits.
    {-# INLINE int16Dec #-}
    int16Dec :: Int16 -> Builder
    int16Dec :: Int16 -> Builder
    int16Dec = forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Int16
    P.int16Dec

    -- | Decimal encoding of an 'Int32' using the ASCII digits.
    {-# INLINE int32Dec #-}
    int32Dec :: Int32 -> Builder
    int32Dec :: Int32 -> Builder
    int32Dec = forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Int32
    P.int32Dec

    -- | Decimal encoding of an 'Int64' using the ASCII digits.
    {-# INLINE int64Dec #-}
    int64Dec :: Int64 -> Builder
    int64Dec :: Int64 -> Builder
    int64Dec = forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Int64
    P.int64Dec

    -- | Decimal encoding of an 'Int' using the ASCII digits.
    {-# INLINE intDec #-}
    intDec :: Int -> Builder
    intDec :: Int -> Builder
    intDec = forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Int
    P.intDec

    -- Unsigned integers
    --------------------

    -- | Decimal encoding of a 'Word8' using the ASCII digits.
    {-# INLINE word8Dec #-}
    word8Dec :: Word8 -> Builder
    word8Dec :: Word8 -> Builder
    word8Dec = forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word8
    P.word8Dec

    -- | Decimal encoding of a 'Word16' using the ASCII digits.
    {-# INLINE word16Dec #-}
    word16Dec :: Word16 -> Builder
    word16Dec :: Word16 -> Builder
    word16Dec = forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word16
    P.word16Dec

    -- | Decimal encoding of a 'Word32' using the ASCII digits.
    {-# INLINE word32Dec #-}
    word32Dec :: Word32 -> Builder
    word32Dec :: Word32 -> Builder
    word32Dec = forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word32
    P.word32Dec

    -- | Decimal encoding of a 'Word64' using the ASCII digits.
    {-# INLINE word64Dec #-}
    word64Dec :: Word64 -> Builder
    word64Dec :: Word64 -> Builder
    word64Dec = forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word64
    P.word64Dec

    -- | Decimal encoding of a 'Word' using the ASCII digits.
    {-# INLINE wordDec #-}
    wordDec :: Word -> Builder
    wordDec :: Word -> Builder
    wordDec = forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word
    P.wordDec

    ------------------------------------------------------------------------------
    -- Hexadecimal Encoding
    ------------------------------------------------------------------------------

    -- without lead
    ---------------

    -- | Shortest hexadecimal encoding of a 'Word8' using lower-case characters.
    {-# INLINE word8Hex #-}
    word8Hex :: Word8 -> Builder
    word8Hex :: Word8 -> Builder
    word8Hex = forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word8
    P.word8Hex

    -- | Shortest hexadecimal encoding of a 'Word16' using lower-case characters.
    {-# INLINE word16Hex #-}
    word16Hex :: Word16 -> Builder
    word16Hex :: Word16 -> Builder
    word16Hex = forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word16
    P.word16Hex

    -- | Shortest hexadecimal encoding of a 'Word32' using lower-case characters.
    {-# INLINE word32Hex #-}
    word32Hex :: Word32 -> Builder
    word32Hex :: Word32 -> Builder
    word32Hex = forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word32
    P.word32Hex

    -- | Shortest hexadecimal encoding of a 'Word64' using lower-case characters.
    {-# INLINE word64Hex #-}
    word64Hex :: Word64 -> Builder
    word64Hex :: Word64 -> Builder
    word64Hex = forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word64
    P.word64Hex

    -- | Shortest hexadecimal encoding of a 'Word' using lower-case characters.
    {-# INLINE wordHex #-}
    wordHex :: Word -> Builder
    wordHex :: Word -> Builder
    wordHex = forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word
    P.wordHex

    -- fixed width; leading zeroes
    ------------------------------

    -- | Encode a 'Int8' using 2 nibbles (hexadecimal digits).
    {-# INLINE int8HexFixed #-}
    int8HexFixed :: Int8 -> Builder
    int8HexFixed :: Int8 -> Builder
    int8HexFixed = forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Int8
    P.int8HexFixed

    -- | Encode a 'Int16' using 4 nibbles.
    {-# INLINE int16HexFixed #-}
    int16HexFixed :: Int16 -> Builder
    int16HexFixed :: Int16 -> Builder
    int16HexFixed = forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Int16
    P.int16HexFixed

    -- | Encode a 'Int32' using 8 nibbles.
    {-# INLINE int32HexFixed #-}
    int32HexFixed :: Int32 -> Builder
    int32HexFixed :: Int32 -> Builder
    int32HexFixed = forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Int32
    P.int32HexFixed

    -- | Encode a 'Int64' using 16 nibbles.
    {-# INLINE int64HexFixed #-}
    int64HexFixed :: Int64 -> Builder
    int64HexFixed :: Int64 -> Builder
    int64HexFixed = forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Int64
    P.int64HexFixed

    -- | Encode a 'Word8' using 2 nibbles (hexadecimal digits).
    {-# INLINE word8HexFixed #-}
    word8HexFixed :: Word8 -> Builder
    word8HexFixed :: Word8 -> Builder
    word8HexFixed = forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Word8
    P.word8HexFixed

    -- | Encode a 'Word16' using 4 nibbles.
    {-# INLINE word16HexFixed #-}
    word16HexFixed :: Word16 -> Builder
    word16HexFixed :: Word16 -> Builder
    word16HexFixed = forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Word16
    P.word16HexFixed

    -- | Encode a 'Word32' using 8 nibbles.
    {-# INLINE word32HexFixed #-}
    word32HexFixed :: Word32 -> Builder
    word32HexFixed :: Word32 -> Builder
    word32HexFixed = forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Word32
    P.word32HexFixed

    -- | Encode a 'Word64' using 16 nibbles.
    {-# INLINE word64HexFixed #-}
    word64HexFixed :: Word64 -> Builder
    word64HexFixed :: Word64 -> Builder
    word64HexFixed = forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Word64
    P.word64HexFixed

    -- | Encode an IEEE 'Float' using 8 nibbles.
    {-# INLINE floatHexFixed #-}
    floatHexFixed :: Float -> Builder
    floatHexFixed :: Float -> Builder
    floatHexFixed = forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Float
    P.floatHexFixed

    -- | Encode an IEEE 'Double' using 16 nibbles.
    {-# INLINE doubleHexFixed #-}
    doubleHexFixed :: Double -> Builder
    doubleHexFixed :: Double -> Builder
    doubleHexFixed = forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Double
    P.doubleHexFixed

    -- | Encode each byte of a 'S.ByteString' using its fixed-width hex encoding.
    {-# NOINLINE byteStringHex #-} -- share code
    byteStringHex :: S.ByteString -> Builder
    byteStringHex :: ByteString -> Builder
    byteStringHex = FixedPrim Word8 -> ByteString -> Builder
    P.primMapByteStringFixed FixedPrim Word8
    P.word8HexFixed

    -- | Encode each byte of a lazy 'L.ByteString' using its fixed-width hex encoding.
    {-# NOINLINE lazyByteStringHex #-} -- share code
    lazyByteStringHex :: L.ByteString -> Builder
    lazyByteStringHex :: ByteString -> Builder
    lazyByteStringHex = FixedPrim Word8 -> ByteString -> Builder
    P.primMapLazyByteStringFixed FixedPrim Word8
    P.word8HexFixed

    ------------------------------------------------------------------------------
    -- Fast decimal 'Integer' encoding.
    ------------------------------------------------------------------------------

    -- An optimized version of the integer serialization code
    -- in blaze-textual (c) 2011 MailRank, Inc. Bryan O'Sullivan
    -- <bos@mailrank.com>. It is 2.5x faster on Int-sized integers and 4.5x faster
    -- on larger integers.

    -- | Maximal power of 10 fitting into an 'Int' without using the MSB.
    --     10 ^ 9  for 32 bit ints  (31 * log 2 / log 10 =  9.33)
    --     10 ^ 18 for 64 bit ints  (63 * log 2 / log 10 = 18.96)
    --
    -- FIXME: Think about also using the MSB. For 64 bit 'Int's this makes a
    -- difference.
    maxPow10 :: Integer
    maxPow10 :: Integer
    maxPow10 = forall a. Integral a => a -> Integer
    toInteger forall a b. (a -> b) -> a -> b
    $ (Int
    10 :: Int) forall a b. (Num a, Integral b) => a -> b -> a
    ^ forall a. a -> a -> a
    P.caseWordSize_32_64 (Int
    9 :: Int) Int
    18

    -- | Decimal encoding of an 'Integer' using the ASCII digits.
    integerDec :: Integer -> Builder
    integerDec :: Integer -> Builder
    integerDec Integer
    i
        | Int
    i' <- forall a. Num a => Integer -> a
    fromInteger Integer
    i, forall a. Integral a => a -> Integer
    toInteger Int
    i' forall a. Eq a => a -> a -> Bool
    == Integer
    i = Int -> Builder
    intDec Int
    i'
        | Integer
    i forall a. Ord a => a -> a -> Bool
    < Integer
    0     = forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Char
    P.char8 Char
    '-' forall a. Monoid a => a -> a -> a
    `mappend` Integer -> Builder
    go (-Integer
    i)
        | Bool
    otherwise =                                   Integer -> Builder
    go Integer
    i
      where
        errImpossible :: [Char] -> a
    errImpossible [Char]
    fun =
            forall a. HasCallStack => [Char] -> a
    error forall a b. (a -> b) -> a -> b
    $ [Char]
    "integerDec: " forall a. [a] -> [a] -> [a]
    ++ [Char]
    fun forall a. [a] -> [a] -> [a]
    ++ [Char]
    ": the impossible happened."

        go :: Integer -> Builder
        go :: Integer -> Builder
    go Integer
    n | Integer
    n forall a. Ord a => a -> a -> Bool
    < Integer
    maxPow10 = Int -> Builder
    intDec (forall a. Num a => Integer -> a
    fromInteger Integer
    n)
             | Bool
    otherwise    =
                 case [Integer] -> [Int]
    putH (Integer -> Integer -> [Integer]
    splitf (Integer
    maxPow10 forall a. Num a => a -> a -> a
    * Integer
    maxPow10) Integer
    n) of
                   (Int
    x:[Int]
    xs) -> Int -> Builder
    intDec Int
    x forall a. Monoid a => a -> a -> a
    `mappend` forall a. BoundedPrim a -> [a] -> Builder
    P.primMapListBounded BoundedPrim Int
    intDecPadded [Int]
    xs
                   []     -> forall {a}. [Char] -> a
    errImpossible [Char]
    "integerDec: go"

        splitf :: Integer -> Integer -> [Integer]
        splitf :: Integer -> Integer -> [Integer]
    splitf Integer
    pow10 Integer
    n0
          | Integer
    pow10 forall a. Ord a => a -> a -> Bool
    > Integer
    n0  = [Integer
    n0]
          | Bool
    otherwise   = [Integer] -> [Integer]
    splith (Integer -> Integer -> [Integer]
    splitf (Integer
    pow10 forall a. Num a => a -> a -> a
    * Integer
    pow10) Integer
    n0)
          where
            splith :: [Integer] -> [Integer]
    splith []     = forall {a}. [Char] -> a
    errImpossible [Char]
    "splith"
            splith (Integer
    n:[Integer]
    ns) =
                case Integer
    n forall a. Integral a => a -> a -> (a, a)
    `quotRem` Integer
    pow10 of
                    (Integer
    q,Integer
    r) | Integer
    q forall a. Ord a => a -> a -> Bool
    > Integer
    0     -> Integer
    q forall a. a -> [a] -> [a]
    : Integer
    r forall a. a -> [a] -> [a]
    : [Integer] -> [Integer]
    splitb [Integer]
    ns
                          | Bool
    otherwise ->     Integer
    r forall a. a -> [a] -> [a]
    : [Integer] -> [Integer]
    splitb [Integer]
    ns

            splitb :: [Integer] -> [Integer]
    splitb []     = []
            splitb (Integer
    n:[Integer]
    ns) = case Integer
    n forall a. Integral a => a -> a -> (a, a)
    `quotRem` Integer
    pow10 of
                                (Integer
    q,Integer
    r) -> Integer
    q forall a. a -> [a] -> [a]
    : Integer
    r forall a. a -> [a] -> [a]
    : [Integer] -> [Integer]
    splitb [Integer]
    ns

        putH :: [Integer] -> [Int]
        putH :: [Integer] -> [Int]
    putH []     = forall {a}. [Char] -> a
    errImpossible [Char]
    "putH"
        putH (Integer
    n:[Integer]
    ns) = case Integer
    n forall a. Integral a => a -> a -> (a, a)
    `quotRem` Integer
    maxPow10 of
                        (Integer
    x,Integer
    y)
                            | Int
    q forall a. Ord a => a -> a -> Bool
    > Int
    0     -> Int
    q forall a. a -> [a] -> [a]
    : Int
    r forall a. a -> [a] -> [a]
    : [Integer] -> [Int]
    putB [Integer]
    ns
                            | Bool
    otherwise ->     Int
    r forall a. a -> [a] -> [a]
    : [Integer] -> [Int]
    putB [Integer]
    ns
                            where q :: Int
    q = forall a. Num a => Integer -> a
    fromInteger Integer
    x
                                  r :: Int
    r = forall a. Num a => Integer -> a
    fromInteger Integer
    y

        putB :: [Integer] -> [Int]
        putB :: [Integer] -> [Int]
    putB []     = []
        putB (Integer
    n:[Integer]
    ns) = case Integer
    n forall a. Integral a => a -> a -> (a, a)
    `quotRem` Integer
    maxPow10 of
                        (Integer
    q,Integer
    r) -> forall a. Num a => Integer -> a
    fromInteger Integer
    q forall a. a -> [a] -> [a]
    : forall a. Num a => Integer -> a
    fromInteger Integer
    r forall a. a -> [a] -> [a]
    : [Integer] -> [Int]
    putB [Integer]
    ns

    foreign import ccall unsafe "static _hs_bytestring_int_dec_padded9"
        c_int_dec_padded9 :: CInt -> Ptr Word8 -> IO ()

    foreign import ccall unsafe "static _hs_bytestring_long_long_int_dec_padded18"
        c_long_long_int_dec_padded18 :: CLLong -> Ptr Word8 -> IO ()

    {-# INLINE intDecPadded #-}
    intDecPadded :: P.BoundedPrim Int
    intDecPadded :: BoundedPrim Int
    intDecPadded = forall a. FixedPrim a -> BoundedPrim a
    P.liftFixedToBounded forall a b. (a -> b) -> a -> b
    $ forall a. a -> a -> a
    P.caseWordSize_32_64
        (forall a. Int -> (a -> Ptr Word8 -> IO ()) -> FixedPrim a
    P.fixedPrim  Int
    9 forall a b. (a -> b) -> a -> b
    $ CInt -> Ptr Word8 -> IO ()
    c_int_dec_padded9            forall b c a. (b -> c) -> (a -> b) -> a -> c
    . forall a b. (Integral a, Num b) => a -> b
    fromIntegral)
        (forall a. Int -> (a -> Ptr Word8 -> IO ()) -> FixedPrim a
    P.fixedPrim Int
    18 forall a b. (a -> b) -> a -> b
    $ CLLong -> Ptr Word8 -> IO ()
    c_long_long_int_dec_padded18 forall b c a. (b -> c) -> (a -> b) -> a -> c
    . forall a b. (Integral a, Num b) => a -> b
    fromIntegral)