haskell-gi-0.8: src/GI/Struct.hs
module GI.Struct ( genStructOrUnionFields
, extractCallbacksInStruct
, fixAPIStructs
, ignoreStruct)
where
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>))
#endif
import Control.Monad (forM_, unless, when)
import Data.List (isSuffixOf)
import Data.Maybe (mapMaybe, isJust)
import Data.Text (unpack)
import GI.API
import GI.Conversions
import GI.Code
import GI.SymbolNaming
import GI.Type
import GI.Util
-- | Whether (not) to generate bindings for the given struct.
ignoreStruct :: Name -> Struct -> Bool
ignoreStruct (Name _ name) s = isJust (gtypeStructFor s) ||
"Private" `isSuffixOf` name
-- | Canonical name for the type of a callback type embedded in a
-- struct field.
fieldCallbackType :: String -> Field -> String
fieldCallbackType structName field = structName
++ (underscoresToCamelCase . unpack .
fieldName) field
++ "FieldCallback"
-- | Fix the interface names of callback fields in the struct to
-- correspond to the ones that we are going to generate.
fixCallbackStructFields :: Name -> Struct -> Struct
fixCallbackStructFields (Name ns structName) s = s {structFields = fixedFields}
where fixedFields :: [Field]
fixedFields = map fixField (structFields s)
fixField :: Field -> Field
fixField field =
case fieldCallback field of
Nothing -> field
Just _ -> let n' = fieldCallbackType structName field
in field {fieldType = TInterface ns n'}
-- | Fix the interface names of callback fields in an APIStruct to
-- correspond to the ones that we are going to generate. If something
-- other than an APIStruct is passed in we don't touch it.
fixAPIStructs :: (Name, API) -> (Name, API)
fixAPIStructs (n, APIStruct s) = (n, APIStruct $ fixCallbackStructFields n s)
fixAPIStructs api = api
-- | Extract the callback types embedded in the fields of structs, and
-- at the same time fix the type of the corresponding fields. Returns
-- the list of APIs associated to this struct, not including the
-- struct itself.
extractCallbacksInStruct :: (Name, API) -> [(Name, API)]
extractCallbacksInStruct (n@(Name ns structName), APIStruct s)
| ignoreStruct n s = []
| otherwise =
mapMaybe callbackInField (structFields s)
where callbackInField :: Field -> Maybe (Name, API)
callbackInField field = do
callback <- fieldCallback field
let n' = fieldCallbackType structName field
return (Name ns n', APICallback callback)
extractCallbacksInStruct _ = []
buildFieldGetter :: Name -> Field -> ExcCodeGen ()
buildFieldGetter n@(Name ns _) field = do
name' <- upperName n
hType <- show <$> haskellType (fieldType field)
fType <- show <$> foreignType (fieldType field)
unless ("Private" `isSuffixOf` hType) $ do
fName <- upperName $ Name ns (unpack . fieldName $ field)
let getter = lcFirst name' ++ "Read" ++ fName
line $ getter ++ " :: " ++ name' ++ " -> IO " ++
if ' ' `elem` hType
then parenthesize hType
else hType
line $ getter ++ " s = withManagedPtr s $ \\ptr -> do"
indent $ do
line $ "val <- peek (ptr `plusPtr` " ++ show (fieldOffset field)
++ ") :: IO " ++ if ' ' `elem` fType
then parenthesize fType
else fType
result <- convert "val" $ fToH (fieldType field) TransferNothing
line $ "return " ++ result
genStructOrUnionFields :: Name -> [Field] -> CodeGen ()
genStructOrUnionFields n fields = do
name' <- upperName n
forM_ fields $ \field -> when (fieldVisible field) $ group $
handleCGExc (\e -> line ("-- XXX Skipped getter for \"" ++ name' ++
":" ++ unpack (fieldName field) ++ "\" :: " ++
describeCGError e))
(buildFieldGetter n field)