C-structs-0.1.0.1: src/Foreign/C/Structs/Utils.hs
{- |
Module : Foreign.C.Structs.Utils
Description : Create C structs from Haskell
Copyright : (c) Simon Plakolb, 2020
License : MIT
Maintainer : s.plakolb@gmail.com
Stability : beta
This module defined some utility functions for Storable instance declarations.
-}
module Foreign.C.Structs.Utils (
next, fmax, sizeof
) where
import Foreign.Storable (Storable, peek, sizeOf, alignment)
import Foreign.Marshal (alloca)
import Foreign.Ptr (Ptr, plusPtr, alignPtr)
-- | Due to alignment constraints the size of C structs is dependent on the order of fields and their respectible sizes. The function 'sizeof' can calculate the resulting size given a list of all 'alignments' and 'sizes'.
sizeof :: [Int] -> [Int] -> Int
sizeof alignments sizes = sizeof' 0 alignments sizes
where
sizeof' 0 (a:as) (s:ss) = sizeof' s as ss
sizeof' s [] [] = s `pad` foldr max 0 alignments
sizeof' x (a:as) (s:ss) = let
s' = x+s
in sizeof' (s' `pad` a) as ss
pad x a
| x `mod` a == 0 = x
| otherwise = pad (x+1) a
-- | Jumps to the next pointer location in the struct.
next :: (Storable a, Storable b, Storable c) => Ptr a -> b -> IO (Ptr c)
next ptr x = alloca $ next' ptr x
where next' :: (Storable a, Storable b, Storable c) => Ptr a -> b -> Ptr c -> IO (Ptr c)
next' ptr x ptr_x = do
let ptr_y = plusPtr ptr $ sizeOf x
y <- peek ptr_x
return $ alignPtr ptr_y $ alignment y
-- | Alias for @foldr max 0@.
fmax :: Integral a => [a] -> a
fmax = foldr max 0