keel-abi-0.1.0.0: test/Layout.hs
-- | Layout gate: compare every offset\/size in the Haskell layout tables
-- against a real C compiler's @offsetof@\/@sizeof@ (computed in
-- @cbits\/layout_gate.c@, which also carries compile-time
-- @_Static_assert@s for the same numbers).
module Main (main) where
import Control.Monad (forM, unless)
import Foreign.C.Types (CSize (..))
import Foreign.Marshal.Array (allocaArray, peekArray)
import Foreign.Ptr (Ptr)
import System.Exit (exitFailure)
import Keel.Abi.Arrow.Raw
import Keel.Abi.DLPack.Raw
foreign import ccall unsafe "keel_layout_ArrowSchema"
c_layout_ArrowSchema :: Ptr CSize -> IO CSize
foreign import ccall unsafe "keel_layout_ArrowArray"
c_layout_ArrowArray :: Ptr CSize -> IO CSize
foreign import ccall unsafe "keel_layout_ArrowArrayStream"
c_layout_ArrowArrayStream :: Ptr CSize -> IO CSize
foreign import ccall unsafe "keel_layout_DLPackVersion"
c_layout_DLPackVersion :: Ptr CSize -> IO CSize
foreign import ccall unsafe "keel_layout_DLDevice"
c_layout_DLDevice :: Ptr CSize -> IO CSize
foreign import ccall unsafe "keel_layout_DLDataType"
c_layout_DLDataType :: Ptr CSize -> IO CSize
foreign import ccall unsafe "keel_layout_DLTensor"
c_layout_DLTensor :: Ptr CSize -> IO CSize
foreign import ccall unsafe "keel_layout_DLManagedTensorVersioned"
c_layout_DLManagedTensorVersioned :: Ptr CSize -> IO CSize
-- | Returns the list of mismatch descriptions (empty = pass).
checkStruct
:: String
-> (Int, [(String, Int)])
-> (Ptr CSize -> IO CSize)
-> IO [String]
checkStruct structName (hsSize, fields) probe =
allocaArray (length fields) $ \out -> do
cSize <- probe out
cOffs <- peekArray (length fields) out
let sizeErrs =
[ structName <> ": sizeof C=" <> show cSize <> " hs=" <> show hsSize
| fromIntegral cSize /= hsSize
]
fieldErrs =
[ structName <> "." <> fname
<> ": offsetof C=" <> show cOff <> " hs=" <> show hsOff
| ((fname, hsOff), cOff) <- zip fields cOffs
, fromIntegral cOff /= hsOff
]
pure (sizeErrs <> fieldErrs)
main :: IO ()
main = do
errs <- fmap concat . forM checks $ \(nm, layout, probe) ->
checkStruct nm layout probe
unless (null errs) $ do
mapM_ putStrLn errs
exitFailure
putStrLn ("keel-abi: layout gate passed (" <> show (length checks) <> " structs)")
where
checks =
[ ("ArrowSchema", arrowSchemaLayout, c_layout_ArrowSchema)
, ("ArrowArray", arrowArrayLayout, c_layout_ArrowArray)
, ("ArrowArrayStream", arrowArrayStreamLayout, c_layout_ArrowArrayStream)
, ("DLPackVersion", dlPackVersionLayout, c_layout_DLPackVersion)
, ("DLDevice", dlDeviceLayout, c_layout_DLDevice)
, ("DLDataType", dlDataTypeLayout, c_layout_DLDataType)
, ("DLTensor", dlTensorLayout, c_layout_DLTensor)
, ("DLManagedTensorVersioned", dlManagedTensorVersionedLayout, c_layout_DLManagedTensorVersioned)
]