-- |
-- Module: Data.AttoBencode.Encode
-- Copyright: Florian Hartwig
-- License: BSD3
-- Maintainer: Florian Hartwig <florian.j.hartwig@gmail.com>
-- Stability: experimental
-- Portability: GHC

module Data.AttoBencode.Encode (encode) where

import Data.AttoBencode.Types
import Blaze.ByteString.Builder
import Blaze.Text.Int (integral)
import Data.Map (toAscList)
import Data.Monoid
import qualified Data.ByteString.Char8 as B
import Data.Word (Word8)

-- | Serialise a Bencode value to a (strict) ByteString
encode :: ToBencode a => a -> B.ByteString
encode = toByteString . fromBValue . toBencode

dWord, iWord, eWord, lWord, colon :: Word8
dWord = 100
eWord = 101
lWord = 108
iWord = 105
colon = 58

fromBValue :: BValue -> Builder
fromBValue (BString s) = fromString s
fromBValue (BList l)   = fromWord8 lWord <> (mconcat . map fromBValue) l <> fromWord8 eWord
fromBValue (BDict d)   = fromWord8 dWord <> (mconcat . map fromPair) (toAscList d) <> fromWord8 eWord
fromBValue (BInt n)    = fromWord8 iWord <> integral n <> fromWord8 eWord

fromString :: B.ByteString -> Builder
fromString s = integral (B.length s) <> fromWord8 colon <> fromByteString s
{-# INLINE fromString #-}

fromPair :: (B.ByteString, BValue) -> Builder
fromPair (k, v) = fromString k <> fromBValue v