{-# language
BangPatterns
, MagicHash
, RankNTypes
, UnboxedTuples
#-}
module Builder
(
Builder
, build
, buildUnaligned
, buildWord8
, buildWord16
, buildWord32
, buildWord64
, buildWord
, buildInt8
, buildInt16
, buildInt32
, buildInt64
, buildInt
, buildFloat
, buildDouble
, buildChar
, buildPtr
, buildByteArray
, buildFixed
) where
import Data.Primitive hiding (writeByteArray)
import Data.Primitive.ByteArray.Unaligned
import Data.Int
import Data.Word
import GHC.Exts hiding (build)
import System.ByteOrder
newtype Writer s = W
{ _w :: ()
=> MutableByteArray# s
-> Int#
-> (State# s -> (# State# s, Int# #))
}
instance Semigroup (Writer s) where
W x <> W y = W $ \marr# ix0# s0# -> case x marr# ix0# s0# of
(# s1#, ix1# #) -> y marr# ix1# s1#
{-# inline (<>) #-}
instance Monoid (Writer s) where
mempty = W $ \_ ix0# s0# -> (# s0#, ix0# #)
{-# inline mempty #-}
data BI s = BI !Int !(Writer s)
instance Semigroup (BI s) where
BI len0 w0 <> BI len1 w1 = BI (len0 + len1) (w0 <> w1)
{-# inline (<>) #-}
instance Monoid (BI s) where
mempty = BI 0 mempty
{-# inline mempty #-}
newtype Builder = Builder (forall s. BI s)
instance Semigroup Builder where
Builder b0 <> Builder b1 = Builder (b0 <> b1)
{-# inline (<>) #-}
instance Monoid Builder where
mempty = Builder mempty
{-# inline mempty #-}
runWriter# :: Int# -> Writer s -> State# s -> (# State# s, ByteArray# #)
runWriter# sz# (W g) = \s0# -> case newByteArray# sz# s0# of
(# s1#, marr# #) -> case g marr# 0# s1# of
(# s2#, _ #) -> case unsafeFreezeByteArray# marr# s2# of
(# s3#, b# #) -> (# s3#, b# #)
{-# inline runWriter# #-}
build :: Builder -> ByteArray
build (Builder (BI (I# len#) w)) = case runRW# (runWriter# len# w) of
(# _, b# #) -> ByteArray b#
{-# inline build #-}
writeUnaligned :: (Prim a, PrimUnaligned a)
=> a
-> Writer s
writeUnaligned a = W $ \marr# ix0# s0# ->
case writeUnalignedByteArray# marr# ix0# a s0# of
s1# -> (# s1#, ix0# +# alignment# a #)
{-# inline writeUnaligned #-}
writeByteArray :: ()
=> ByteArray
-> Int
-> Int
-> Writer s
writeByteArray (ByteArray src#) (I# off#) (I# len#)
= W $ \marr# ix0# s0# ->
case copyByteArray# src# off# marr# ix0# len# s0# of
s1# -> (# s1#, ix0# +# len# #)
{-# inline writeByteArray #-}
buildUnaligned :: (Prim a, PrimUnaligned a)
=> a
-> Builder
buildUnaligned a = Builder (BI (sizeOf a) (writeUnaligned a))
{-# inline buildUnaligned #-}
buildWord8 :: Word8 -> Builder
buildWord8 = buildUnaligned
{-# inline buildWord8 #-}
buildWord16 :: Word16 -> Builder
buildWord16 = buildUnaligned
{-# inline buildWord16 #-}
buildWord32 :: Word32 -> Builder
buildWord32 = buildUnaligned
{-# inline buildWord32 #-}
buildWord64 :: Word64 -> Builder
buildWord64 = buildUnaligned
{-# inline buildWord64 #-}
buildWord :: Word -> Builder
buildWord = buildUnaligned
{-# inline buildWord #-}
buildInt8 :: Int8 -> Builder
buildInt8 = buildUnaligned
{-# inline buildInt8 #-}
buildInt16 :: Int16 -> Builder
buildInt16 = buildUnaligned
{-# inline buildInt16 #-}
buildInt32 :: Int32 -> Builder
buildInt32 = buildUnaligned
{-# inline buildInt32 #-}
buildInt64 :: Int64 -> Builder
buildInt64 = buildUnaligned
{-# inline buildInt64 #-}
buildInt :: Int -> Builder
buildInt = buildUnaligned
{-# inline buildInt #-}
buildChar :: Char -> Builder
buildChar = buildUnaligned
{-# inline buildChar #-}
buildByteArray :: ()
=> ByteArray
-> Int
-> Int
-> Builder
buildByteArray b o n = Builder (BI n (writeByteArray b o n))
{-# inline buildByteArray #-}
buildFloat :: Float -> Builder
buildFloat = buildUnaligned
{-# inline buildFloat #-}
buildDouble :: Double -> Builder
buildDouble = buildUnaligned
{-# inline buildDouble #-}
buildPtr :: Ptr a -> Builder
buildPtr = buildUnaligned
{-# inline buildPtr #-}
buildFixed :: (FixedOrdering b, Bytes a, Prim a, PrimUnaligned a)
=> Fixed b a
-> Builder
buildFixed = buildUnaligned
{-# inline buildFixed #-}