module Data.Binary.Builder.Sized where

import qualified Data.ByteString.Builder as B
import Data.Monoid (mempty, mappend, Monoid)
import qualified Data.ByteString.Lazy as LBS
import qualified Data.ByteString as BS
import Data.Semigroup (Semigroup, (<>))
import qualified Data.Word as W

data Builder = Builder {-# UNPACK #-} !Int B.Builder

instance Semigroup Builder where
  Builder Int
i Builder
b <> :: Builder -> Builder -> Builder
<> Builder Int
i' Builder
b' = Int -> Builder -> Builder
Builder (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i') (Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
mappend Builder
b Builder
b')

instance Monoid Builder where
  mempty :: Builder
mempty = Int -> Builder -> Builder
Builder Int
0 Builder
forall a. Monoid a => a
mempty
  mappend :: Builder -> Builder -> Builder
mappend = Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
(<>)

toLazyByteString :: Builder -> LBS.ByteString
toLazyByteString :: Builder -> ByteString
toLazyByteString (Builder Int
_ Builder
b) = Builder -> ByteString
B.toLazyByteString Builder
b

size :: Builder -> Int
size :: Builder -> Int
size (Builder Int
i Builder
_) = Int
i

empty :: Builder
empty :: Builder
empty = Builder
forall a. Monoid a => a
mempty

singleton :: W.Word8 -> Builder
singleton :: Word8 -> Builder
singleton = Int -> Builder -> Builder
Builder Int
1 (Builder -> Builder) -> (Word8 -> Builder) -> Word8 -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Builder
B.word8

append :: Builder -> Builder -> Builder
append :: Builder -> Builder -> Builder
append = Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
mappend

fromByteString :: BS.ByteString -> Builder
fromByteString :: ByteString -> Builder
fromByteString ByteString
s = Int -> Builder -> Builder
Builder (ByteString -> Int
BS.length ByteString
s) (Builder -> Builder) -> Builder -> Builder
forall a b. (a -> b) -> a -> b
$ ByteString -> Builder
B.byteString ByteString
s

fromLazyByteString :: LBS.ByteString -> Builder
fromLazyByteString :: ByteString -> Builder
fromLazyByteString ByteString
s = Int -> Builder -> Builder
Builder (Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64 -> Int) -> Int64 -> Int
forall a b. (a -> b) -> a -> b
$ ByteString -> Int64
LBS.length ByteString
s) (Builder -> Builder) -> Builder -> Builder
forall a b. (a -> b) -> a -> b
$ ByteString -> Builder
B.lazyByteString ByteString
s

putWord16be :: W.Word16 -> Builder
putWord16be :: Word16 -> Builder
putWord16be = Int -> Builder -> Builder
Builder Int
2 (Builder -> Builder) -> (Word16 -> Builder) -> Word16 -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word16 -> Builder
B.word16BE

putWord32be :: W.Word32 -> Builder
putWord32be :: Word32 -> Builder
putWord32be = Int -> Builder -> Builder
Builder Int
4 (Builder -> Builder) -> (Word32 -> Builder) -> Word32 -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> Builder
B.word32BE

putWord64be :: W.Word64 -> Builder
putWord64be :: Word64 -> Builder
putWord64be = Int -> Builder -> Builder
Builder Int
8 (Builder -> Builder) -> (Word64 -> Builder) -> Word64 -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Builder
B.word64BE

putWord16le :: W.Word16 -> Builder
putWord16le :: Word16 -> Builder
putWord16le = Int -> Builder -> Builder
Builder Int
2 (Builder -> Builder) -> (Word16 -> Builder) -> Word16 -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word16 -> Builder
B.word16LE

putWord32le :: W.Word32 -> Builder
putWord32le :: Word32 -> Builder
putWord32le = Int -> Builder -> Builder
Builder Int
4 (Builder -> Builder) -> (Word32 -> Builder) -> Word32 -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> Builder
B.word32LE

putWord64le :: W.Word64 -> Builder
putWord64le :: Word64 -> Builder
putWord64le = Int -> Builder -> Builder
Builder Int
8 (Builder -> Builder) -> (Word64 -> Builder) -> Word64 -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Builder
B.word64LE