bencodex-1.0.0: src/Data/Bencodex/Writer.hs
module Data.Bencodex.Writer
( encodeLazy
, encodeStrict
) where
import Data.List (sort)
import Data.ByteString hiding (sort)
import Data.ByteString.Builder
import qualified Data.ByteString.Lazy
import Data.HashMap.Strict
import Data.Text.Encoding
import Data.Bencodex.Types
encodeLazy :: BValue -> Data.ByteString.Lazy.ByteString
encodeLazy = toLazyByteString . renderBValue
encodeStrict :: BValue -> ByteString
encodeStrict = Data.ByteString.Lazy.toStrict . encodeLazy
renderBValue :: BValue -> Builder
renderBValue BNull = char7 'n'
renderBValue (BBool True) = char7 't'
renderBValue (BBool False) = char7 'f'
renderBValue (BInteger int) = mconcat
[ char7 'i'
, integerDec int
, char7 'e'
]
renderBValue (BByteString bs) = mconcat
[ intDec (Data.ByteString.length bs)
, char7 ':'
, byteString bs
]
renderBValue (BText txt) = mconcat
[ char7 'u'
, intDec (Data.ByteString.length encoded)
, char7 ':'
, byteString encoded
]
where
encoded :: ByteString
encoded = encodeUtf8 txt
renderBValue (BList elements) =
char7 'l' <> mconcat (renderBValue <$> elements) <> char7 'e'
renderBValue (BMap hmap) =
char7 'd' <> mconcat renderedPairs <> char7 'e'
where
pairs :: [(KeyType, ByteString, BValue)]
pairs = sort
[ case k of
BTextKey k' -> (UnicodeKey, encodeUtf8 k', v)
BByteStringKey k' -> (BytesKey, k', v)
| (k, v) <- toList hmap
]
renderedPairs :: [Builder]
renderedPairs =
[ renderKey kt k <> renderBValue v
| (kt, k, v) <- pairs
]
data KeyType = BytesKey | UnicodeKey deriving (Eq, Ord, Show)
renderKey :: KeyType -> ByteString -> Builder
renderKey kt bs =
case kt of
BytesKey -> common
UnicodeKey -> char7 'u' <> common
where
common :: Builder
common = mconcat
[ intDec (Data.ByteString.length bs)
, char7 ':'
, byteString bs
]