From: <cod...@go...> - 2008-10-07 23:09:10
|
Author: wol...@gm... Date: Tue Oct 7 16:07:50 2008 New Revision: 331 Added: trunk/hoc/HOC/HOC/CStruct.hs Modified: trunk/hoc/HOC.cabal trunk/hoc/HOC/HOC.hs Log: Add a template function for marshalling structs. Modified: trunk/hoc/HOC.cabal ============================================================================== --- trunk/hoc/HOC.cabal (original) +++ trunk/hoc/HOC.cabal Tue Oct 7 16:07:50 2008 @@ -44,7 +44,8 @@ HOC.TH, HOC.Unicode, HOC.Utilities, - HOC.THDebug + HOC.THDebug, + HOC.CStruct hs-source-dirs: HOC extensions: MagicHash, TemplateHaskell, Modified: trunk/hoc/HOC/HOC.hs ============================================================================== --- trunk/hoc/HOC/HOC.hs (original) +++ trunk/hoc/HOC/HOC.hs Tue Oct 7 16:07:50 2008 @@ -55,6 +55,9 @@ WrappedNSException(..), + declareCStruct, + declareCStructWithTag, + -- debugging & statistics: objectMapStatistics @@ -81,3 +84,4 @@ import HOC.Selectors import HOC.Exception import HOC.FFICallInterface +import HOC.CStruct Added: trunk/hoc/HOC/HOC/CStruct.hs ============================================================================== --- (empty file) +++ trunk/hoc/HOC/HOC/CStruct.hs Tue Oct 7 16:07:50 2008 @@ -0,0 +1,133 @@ +{-# OPTIONS -fglasgow-exts -fth #-} +module HOC.CStruct( declareCStruct, declareCStructWithTag ) where + +import HOC.Arguments ( ObjCArgument(..) ) +import HOC.TH +import HOC.NameCaseChange ( nameToUppercase ) +import HOC.FFICallInterface + +import Control.Monad.State +import Data.Bits +import Data.Maybe ( fromMaybe ) +import Foreign + +declareCStruct :: String -> [TypeQ] -> Q [Dec] +declareCStructWithTag :: String -> Maybe String -> [TypeQ] -> Q [Dec] + + +mkRawThing :: ObjCArgument a b => a -> b +mkRawThing _ = undefined + +sizeMember :: ObjCArgument a b => a -> State Int () +sizeMember thing = + modify (\offset -> align offset (alignment rawThing) + sizeOf rawThing) + + where align x a = (x + (a-1)) .&. complement (a-1) + rawThing = mkRawThing thing + +alignMember :: ObjCArgument a b => a -> Int +alignMember = alignment . mkRawThing + +pokeMember :: ObjCArgument a b => a -> StateT (Ptr c) IO () +pokeMember thing = do + rawThing <- lift $ exportArgument thing + modify (`alignPtr` alignment rawThing) + p <- get + lift $ poke (castPtr p) rawThing + modify (`plusPtr` sizeOf rawThing) + +peekMember :: ObjCArgument a b => StateT (Ptr c) IO a +peekMember = (mfix $ \result -> do + modify (`alignPtr` alignment result) + p <- get + rawThing <- lift $ peek (castPtr p) + modify (`plusPtr` sizeOf rawThing) + return rawThing) >>= \rawThing -> lift (importArgument rawThing) + +ffiMember :: ObjCArgument a b => a -> StateT [FFIType] IO () +ffiMember thing = do + t <- lift $ makeFFIType (mkRawThing thing) + modify (t :) + + +declareCStruct cname fieldTypes + = declareCStructWithTag cname Nothing fieldTypes + +declareCStructWithTag cname mbTag fieldTypes + = do + let name = mkName $ nameToUppercase cname + structTag = fromMaybe "?" mbTag + dataDecl <- dataD (cxt []) name [] [ + normalC name $ + map (strictType (return NotStrict)) fieldTypes + ] [''Eq, ''Ord] --, ''Read, ''Show] + + varNames <- mapM (const $ newName "field") fieldTypes + ptrName <- newName "ptr" + + let takeApartP = conP name $ map varP varNames + putTogetherE | null varNames = conE name + | otherwise = appsE $ (conE name : map varE varNames) + + doWithArgs name | null varNames = [| return () |] + doWithArgs name = doE $ + [ noBindS (varE name `appE` varE field) + | field <- varNames ] + + doWithResults name = doE $ + [ bindS (varP field) (varE name) + | field <- varNames ] + ++ [ noBindS [| return $(putTogetherE) |] ] + + mapArgs name = listE $ + [ varE name `appE` varE field | field <- varNames ] + + storableDecl <- instanceD (cxt []) (conT ''Storable `appT` conT name) + [ + funD 'alignment [ + clause [tildeP takeApartP] + (normalB [| maximum ( 1 : $(mapArgs 'alignMember) ) |]) [] + ], + funD 'sizeOf [ + clause [tildeP takeApartP] + (normalB [| execState $(doWithArgs 'sizeMember) 0 | ]) + [] + ], + funD 'poke [ + clause [varP ptrName, takeApartP] + (normalB [| evalStateT $(doWithArgs 'pokeMember) $(varE ptrName) |]) + [] + ], + funD 'peek [ + clause [varP ptrName] + (normalB [| evalStateT $(doWithResults 'peekMember) $(varE ptrName) |]) + [] + ] + ] + + ffiDecl <- instanceD (cxt []) (conT ''FFITypeable `appT` conT name) + [ + funD 'isStructType [ clause [wildP] (normalB [| True |]) [] ], + funD 'makeFFIType [ + clause [tildeP takeApartP] + (normalB [| execStateT $(doWithArgs 'ffiMember) [] + >>= makeStructType . reverse |]) + [] + ] + ] + + argDecl <- instanceD (cxt []) (conT ''ObjCArgument `appT` + conT name `appT` conT name) + [ + valD (varP 'exportArgument) (normalB [| return |]) [], + valD (varP 'importArgument) (normalB [| return |]) [], + funD 'objCTypeString [ + clause [tildeP takeApartP] + (normalB [| "{" ++ structTag ++ "=" ++ + concat $(mapArgs 'objCTypeString) ++ + "}" |]) + [] + ] + ] + + return [dataDecl, storableDecl, ffiDecl, argDecl] |