module Foreign.HaPy.Internal (
  sizeOfList,
  peekList,
  pokeList,
  copyList
) where

import Foreign.C ( CInt )
import Foreign.Marshal.Array ( pokeArray, peekArray )
import Foreign.Marshal.Alloc ( mallocBytes )
import Foreign.Storable ( Storable(..) )
import Foreign.Ptr ( Ptr, plusPtr, castPtr, alignPtr )

cInt :: CInt
cInt = undefined

lenPtr :: Storable a => Ptr [a] -> Ptr CInt
lenPtr = castPtr

arrPtr :: Storable a => Ptr [a] -> Ptr a
arrPtr ptr = castPtr $ (ptr `plusPtr` sizeOf cInt) `alignPtr` alignment (ptrElem ptr)
  where ptrElem :: Ptr [a] -> a
        ptrElem = undefined

sizeOfList :: Storable a => [a] -> Int
sizeOfList xs = alignedIntSize + length xs * sizeOf (head xs)
  where alignedIntSize = max (sizeOf cInt) (alignment $ head xs)

peekList :: Storable a => Ptr [a] -> IO [a]
peekList ptr = do
  len <- peek $ lenPtr ptr
  peekArray (fromIntegral len) $ arrPtr ptr

pokeList :: Storable a => Ptr [a] -> [a] -> IO ()
pokeList ptr xs = do
  poke (lenPtr ptr) (fromIntegral $ length xs)
  pokeArray (arrPtr ptr) xs

copyList :: Storable a => [a] -> IO (Ptr [a])
copyList xs = do
  ptr <- mallocBytes $ sizeOfList xs
  pokeList ptr xs
  return ptr