module ByteString.TreeBuilder.Poker where

import ByteString.TreeBuilder.Prelude
import Foreign hiding (void)
import qualified Data.ByteString as A
import qualified Data.ByteString.Internal as B
import qualified Foreign as D
import qualified ByteString.TreeBuilder.Tree as E


-- |
-- Write the given bytes into the pointer and
-- return a pointer incremented by the amount of written bytes.
pokeBytes :: ByteString -> Ptr Word8 -> IO (Ptr Word8)
pokeBytes :: ByteString -> Ptr Word8 -> IO (Ptr Word8)
pokeBytes (B.PS ForeignPtr Word8
foreignPointer Int
offset Int
length) Ptr Word8
pointer =
  do
    ForeignPtr Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
foreignPointer ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pointer' ->
      Ptr Word8 -> Ptr Word8 -> Int -> IO ()
B.memcpy Ptr Word8
pointer (Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
plusPtr Ptr Word8
pointer' Int
offset) Int
length
    Ptr Word8 -> IO (Ptr Word8)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
plusPtr Ptr Word8
pointer Int
length)

-- |
-- Write the given bytes into the pointer and
-- return a pointer decremented by the amount of written bytes.
pokeBytesMinus :: ByteString -> Ptr Word8 -> IO (Ptr Word8)
pokeBytesMinus :: ByteString -> Ptr Word8 -> IO (Ptr Word8)
pokeBytesMinus (B.PS ForeignPtr Word8
foreignPointer Int
offset Int
length) Ptr Word8
pointer =
  do
    ForeignPtr Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
foreignPointer ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pointer' ->
      Ptr Word8 -> Ptr Word8 -> Int -> IO ()
B.memcpy Ptr Word8
targetPointer (Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
plusPtr Ptr Word8
pointer' Int
offset) Int
length
    Ptr Word8 -> IO (Ptr Word8)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Ptr Word8
targetPointer
  where
    targetPointer :: Ptr Word8
targetPointer =
      Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
plusPtr Ptr Word8
pointer (Int -> Int
forall a. Num a => a -> a
negate Int
length)

pokeTree :: E.Tree -> D.Ptr Word8 -> IO (D.Ptr Word8)
pokeTree :: Tree -> Ptr Word8 -> IO (Ptr Word8)
pokeTree Tree
tree Ptr Word8
ptr =
  case Tree
tree of
    E.Leaf ByteString
bytes -> ByteString -> Ptr Word8 -> IO (Ptr Word8)
pokeBytes ByteString
bytes Ptr Word8
ptr
    E.Branch Tree
tree1 Tree
tree2 -> Tree -> Ptr Word8 -> IO (Ptr Word8)
pokeTree Tree
tree1 Ptr Word8
ptr IO (Ptr Word8) -> (Ptr Word8 -> IO (Ptr Word8)) -> IO (Ptr Word8)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Tree -> Ptr Word8 -> IO (Ptr Word8)
pokeTree Tree
tree2
    Tree
E.Empty -> Ptr Word8 -> IO (Ptr Word8)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Ptr Word8
ptr