packages feed

haskell-gi-0.12: 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.Maybe (mapMaybe, isJust)
import Data.Text (Text)
import qualified Data.Text as T

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" `T.isSuffixOf` name

-- | Canonical name for the type of a callback type embedded in a
-- struct field.
fieldCallbackType :: Text -> Field -> Text
fieldCallbackType structName field =
    structName <> (underscoresToCamelCase . 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 <- tshow <$> haskellType (fieldType field)
  fType <- tshow <$> foreignType (fieldType field)
  unless ("Private" `T.isSuffixOf` hType) $ do
     fName <- upperName $ Name ns (fieldName field)
     let getter = lcFirst name' <> "Read" <> fName
     line $ getter <> " :: " <> name' <> " -> IO " <>
                 if T.any (== ' ') hType
                 then parenthesize hType
                 else hType
     line $ getter <> " s = withManagedPtr s $ \\ptr -> do"
     indent $ do
       line $ "val <- peek (ptr `plusPtr` " <> tshow (fieldOffset field)
            <> ") :: IO " <> if T.any (== ' ') fType
                            then parenthesize fType
                            else fType
       result <- convert "val" $ fToH (fieldType field) TransferNothing
       line $ "return " <> result

     exportProperty fName getter

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' <>
                               ":" <> fieldName field <> "\" :: " <>
                               describeCGError e))
                  (buildFieldGetter n field)