module Data.Beamable.Integer
( beamInteger
, unbeamInteger
) where
import Control.Arrow (first)
import Data.ByteString (ByteString)
import Data.Monoid (mappend)
import Blaze.ByteString.Builder
import qualified Data.ByteString as B
import GHC.Integer.GMP.Internals
import GHC.Base
import GHC.Word
import GHC.ST
import Data.Beamable.Int
beamInteger :: Integer -> Builder
beamInteger (S# x#) = beamInt (1) `mappend` beamInt (fromIntegral $ I# x#)
beamInteger (J# x# ba#) =
beamInt (fromIntegral $ I# baSize#) `mappend` beamInt (fromIntegral $ I# x#) `mappend`
fromWord8s [W8# (indexWord8Array# ba# i#) | I# i# <- [0 .. baSize 1]]
where
baSize# = sizeofByteArray# ba#
baSize = I# baSize#
unbeamInteger :: ByteString -> (Integer, ByteString)
unbeamInteger bs
| baSize# <# 0# = (S# x#, bs'')
| otherwise = runSTRep $ \s# ->
let (# s'#, mba# #) = newByteArray# baSize# s#
s''# = go mba# 0# s'#
(# s'''#, ba# #) = unsafeFreezeByteArray# mba# s''#
in (# s'''#, (J# x# ba#, B.drop (I# baSize#) bs'') #)
where
!(I# baSize#, bs') = first fromIntegral $ unbeamInt bs
!(I# x#, bs'') = first fromIntegral $ unbeamInt bs'
go mba# i# s#
| i# >=# baSize# = s#
| otherwise =
let !(W8# b#) = B.index bs'' (I# i#)
s'# = writeWord8Array# mba# i# b# s#
in go mba# (i# +# 1#) s'#