-- | Parsing of Enums.
module Data.GI.GIR.Enum
    ( Enumeration(..)
    , EnumerationMember(..)
    , parseEnum
    ) where

import Data.Int (Int64)
import Data.Text (Text)
import Foreign.C (CInt(..))

import Data.GI.GIR.Parser
import Data.GI.GIR.Type (parseCType)

data Enumeration = Enumeration {
    Enumeration -> [EnumerationMember]
enumMembers :: [EnumerationMember],
    Enumeration -> Maybe ParseError
enumErrorDomain :: Maybe Text,
    Enumeration -> Maybe ParseError
enumTypeInit :: Maybe Text,
    Enumeration -> Documentation
enumDocumentation :: Documentation,
    Enumeration -> ParseError
enumCType    :: Text,
    Enumeration -> Int
enumStorageBytes :: Int, -- ^ Bytes used for storage of this struct.
    Enumeration -> Maybe DeprecationInfo
enumDeprecated :: Maybe DeprecationInfo }
    deriving Int -> Enumeration -> ShowS
[Enumeration] -> ShowS
Enumeration -> String
(Int -> Enumeration -> ShowS)
-> (Enumeration -> String)
-> ([Enumeration] -> ShowS)
-> Show Enumeration
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Enumeration -> ShowS
showsPrec :: Int -> Enumeration -> ShowS
$cshow :: Enumeration -> String
show :: Enumeration -> String
$cshowList :: [Enumeration] -> ShowS
showList :: [Enumeration] -> ShowS
Show

-- | Member of an enumeration.
data EnumerationMember = EnumerationMember {
  EnumerationMember -> ParseError
enumMemberName   :: Text,
  EnumerationMember -> Int64
enumMemberValue  :: Int64,
  EnumerationMember -> ParseError
enumMemberCId    :: Text,
  EnumerationMember -> Documentation
enumMemberDoc    :: Documentation
  } deriving Int -> EnumerationMember -> ShowS
[EnumerationMember] -> ShowS
EnumerationMember -> String
(Int -> EnumerationMember -> ShowS)
-> (EnumerationMember -> String)
-> ([EnumerationMember] -> ShowS)
-> Show EnumerationMember
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> EnumerationMember -> ShowS
showsPrec :: Int -> EnumerationMember -> ShowS
$cshow :: EnumerationMember -> String
show :: EnumerationMember -> String
$cshowList :: [EnumerationMember] -> ShowS
showList :: [EnumerationMember] -> ShowS
Show

-- | Parse a struct member.
parseEnumMember :: Parser EnumerationMember
parseEnumMember :: Parser EnumerationMember
parseEnumMember = do
  ParseError
name <- Name -> Parser ParseError
getAttr Name
"name"
  Int64
value <- Name -> Parser ParseError
getAttr Name
"value" Parser ParseError
-> (ParseError -> ReaderT ParseContext (Except ParseError) Int64)
-> ReaderT ParseContext (Except ParseError) Int64
forall a b.
ReaderT ParseContext (Except ParseError) a
-> (a -> ReaderT ParseContext (Except ParseError) b)
-> ReaderT ParseContext (Except ParseError) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ParseError -> ReaderT ParseContext (Except ParseError) Int64
forall a. Integral a => ParseError -> Parser a
parseIntegral
  ParseError
cid <- GIRXMLNamespace -> Name -> Parser ParseError
getAttrWithNamespace GIRXMLNamespace
CGIRNS Name
"identifier"
  Documentation
doc <- Parser Documentation
parseDocumentation
  EnumerationMember -> Parser EnumerationMember
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return (EnumerationMember -> Parser EnumerationMember)
-> EnumerationMember -> Parser EnumerationMember
forall a b. (a -> b) -> a -> b
$ EnumerationMember {
    enumMemberName :: ParseError
enumMemberName = ParseError
name,
    enumMemberValue :: Int64
enumMemberValue = Int64
value,
    enumMemberCId :: ParseError
enumMemberCId = ParseError
cid,
    enumMemberDoc :: Documentation
enumMemberDoc = Documentation
doc
    }

foreign import ccall "_gi_get_enum_storage_bytes" get_storage_bytes ::
    Int64 -> Int64 -> CInt

-- | Return the number of bytes that should be allocated for storage
-- of the given values in an enum.
extractEnumStorageBytes :: [Int64] -> Int
extractEnumStorageBytes :: [Int64] -> Int
extractEnumStorageBytes [Int64]
values =
    CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CInt -> Int) -> CInt -> Int
forall a b. (a -> b) -> a -> b
$ Int64 -> Int64 -> CInt
get_storage_bytes ([Int64] -> Int64
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [Int64]
values) ([Int64] -> Int64
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [Int64]
values)

-- | Parse an "enumeration" element from the GIR file.
parseEnum :: Parser (Name, Enumeration)
parseEnum :: Parser (Name, Enumeration)
parseEnum = do
  Name
name <- Parser Name
parseName
  ParseError
ctype <- Parser ParseError
parseCType
  Documentation
doc <- Parser Documentation
parseDocumentation
  Maybe DeprecationInfo
deprecated <- Parser (Maybe DeprecationInfo)
parseDeprecation
  Maybe ParseError
errorDomain <- GIRXMLNamespace -> Name -> Parser (Maybe ParseError)
queryAttrWithNamespace GIRXMLNamespace
GLibGIRNS Name
"error-domain"
  Maybe ParseError
typeInit <- GIRXMLNamespace -> Name -> Parser (Maybe ParseError)
queryAttrWithNamespace GIRXMLNamespace
GLibGIRNS Name
"get-type"
  [EnumerationMember]
members <- ParseError
-> Parser EnumerationMember -> Parser [EnumerationMember]
forall a. ParseError -> Parser a -> Parser [a]
parseChildrenWithLocalName ParseError
"member" Parser EnumerationMember
parseEnumMember
  (Name, Enumeration) -> Parser (Name, Enumeration)
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return (Name
name,
          Enumeration {
            enumMembers :: [EnumerationMember]
enumMembers = [EnumerationMember]
members
          , enumErrorDomain :: Maybe ParseError
enumErrorDomain = Maybe ParseError
errorDomain
          , enumDocumentation :: Documentation
enumDocumentation = Documentation
doc
          , enumTypeInit :: Maybe ParseError
enumTypeInit = Maybe ParseError
typeInit
          , enumCType :: ParseError
enumCType = ParseError
ctype
          , enumStorageBytes :: Int
enumStorageBytes = [Int64] -> Int
extractEnumStorageBytes ((EnumerationMember -> Int64) -> [EnumerationMember] -> [Int64]
forall a b. (a -> b) -> [a] -> [b]
map EnumerationMember -> Int64
enumMemberValue [EnumerationMember]
members)
          , enumDeprecated :: Maybe DeprecationInfo
enumDeprecated = Maybe DeprecationInfo
deprecated
          })