{-# LANGUAGE GADTs, ScopedTypeVariables, DataKinds, KindSignatures,
TypeFamilies, TypeOperators, MultiParamTypeClasses, ConstraintKinds,
UndecidableInstances, FlexibleInstances #-}
module Data.GI.Base.Attributes (
AttrInfo(..),
AttrOpTag(..),
AttrOp(..),
AttrOpAllowed,
AttrGetC,
AttrSetC,
AttrConstructC,
AttrClearC,
get,
set,
clear,
AttrLabelProxy(..)
) where
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Proxy (Proxy(..))
import Data.GI.Base.GValue (GValueConstruct)
import Data.GI.Base.Overloading (HasAttributeList,
ResolveAttribute, IsLabelProxy(..))
import GHC.TypeLits
import GHC.Exts (Constraint)
#if MIN_VERSION_base(4,9,0)
import GHC.OverloadedLabels (IsLabel(..))
#endif
infixr 0 :=,:~,:=>,:~>
data AttrLabelProxy (a :: Symbol) = AttrLabelProxy
instance a ~ x => IsLabelProxy x (AttrLabelProxy a) where
fromLabelProxy _ = AttrLabelProxy
#if MIN_VERSION_base(4,10,0)
instance a ~ x => IsLabel x (AttrLabelProxy a) where
fromLabel = AttrLabelProxy
#elif MIN_VERSION_base(4,9,0)
instance a ~ x => IsLabel x (AttrLabelProxy a) where
fromLabel _ = AttrLabelProxy
#endif
class AttrInfo (info :: *) where
type AttrAllowedOps info :: [AttrOpTag]
type AttrSetTypeConstraint info :: * -> Constraint
type AttrBaseTypeConstraint info :: * -> Constraint
type AttrGetType info
type AttrLabel info :: Symbol
type AttrOrigin info
attrGet :: AttrBaseTypeConstraint info o =>
Proxy info -> o -> IO (AttrGetType info)
attrSet :: (AttrBaseTypeConstraint info o,
AttrSetTypeConstraint info b) =>
Proxy info -> o -> b -> IO ()
attrClear :: AttrBaseTypeConstraint info o =>
Proxy info -> o -> IO ()
attrConstruct :: (AttrBaseTypeConstraint info o,
AttrSetTypeConstraint info b) =>
Proxy info -> b -> IO (GValueConstruct o)
data OpAllowed tag attrName definingType useType =
OpIsAllowed
#if !MIN_VERSION_base(4,9,0)
| AttrOpNotAllowed Symbol tag Symbol definingType Symbol attrName
#endif
#if MIN_VERSION_base(4,9,0)
type family TypeOriginInfo definingType useType :: ErrorMessage where
TypeOriginInfo definingType definingType =
'Text "‘" ':<>: 'ShowType definingType ':<>: 'Text "’"
TypeOriginInfo definingType useType =
'Text "‘" ':<>: 'ShowType useType ':<>:
'Text "’ (inherited from parent type ‘" ':<>:
'ShowType definingType ':<>: 'Text "’)"
#endif
type family AttrOpIsAllowed (tag :: AttrOpTag) (ops :: [AttrOpTag]) (label :: Symbol) (definingType :: *) (useType :: *) :: OpAllowed AttrOpTag Symbol * * where
AttrOpIsAllowed tag '[] label definingType useType =
#if !MIN_VERSION_base(4,9,0)
'AttrOpNotAllowed "Error: operation " tag " not allowed for attribute " definingType "." label
#else
TypeError ('Text "Attribute ‘" ':<>: 'Text label ':<>:
'Text "’ for type " ':<>:
TypeOriginInfo definingType useType ':<>:
'Text " is not " ':<>:
'Text (AttrOpText tag) ':<>: 'Text ".")
#endif
AttrOpIsAllowed tag (tag ': ops) label definingType useType = 'OpIsAllowed
AttrOpIsAllowed tag (other ': ops) label definingType useType = AttrOpIsAllowed tag ops label definingType useType
type family AttrOpAllowed (tag :: AttrOpTag) (info :: *) (useType :: *) :: Constraint where
AttrOpAllowed tag info useType =
AttrOpIsAllowed tag (AttrAllowedOps info) (AttrLabel info) (AttrOrigin info) useType ~ 'OpIsAllowed
data AttrOpTag = AttrGet | AttrSet | AttrConstruct | AttrClear
deriving (Eq, Ord, Enum, Bounded, Show)
#if MIN_VERSION_base(4,9,0)
type family AttrOpText (tag :: AttrOpTag) :: Symbol where
AttrOpText 'AttrGet = "gettable"
AttrOpText 'AttrSet = "settable"
AttrOpText 'AttrConstruct = "constructible"
AttrOpText 'AttrClear = "nullable"
#endif
type AttrSetC info obj attr value = (HasAttributeList obj,
info ~ ResolveAttribute attr obj,
AttrInfo info,
AttrBaseTypeConstraint info obj,
AttrOpAllowed 'AttrSet info obj,
(AttrSetTypeConstraint info) value)
type AttrConstructC info obj attr value = (HasAttributeList obj,
info ~ ResolveAttribute attr obj,
AttrInfo info,
AttrBaseTypeConstraint info obj,
AttrOpAllowed 'AttrConstruct info obj,
(AttrSetTypeConstraint info) value)
data AttrOp obj (tag :: AttrOpTag) where
(:=) :: (HasAttributeList obj,
info ~ ResolveAttribute attr obj,
AttrInfo info,
AttrBaseTypeConstraint info obj,
AttrOpAllowed tag info obj,
(AttrSetTypeConstraint info) b) =>
AttrLabelProxy (attr :: Symbol) -> b -> AttrOp obj tag
(:=>) :: (HasAttributeList obj,
info ~ ResolveAttribute attr obj,
AttrInfo info,
AttrBaseTypeConstraint info obj,
AttrOpAllowed tag info obj,
(AttrSetTypeConstraint info) b) =>
AttrLabelProxy (attr :: Symbol) -> IO b -> AttrOp obj tag
(:~) :: (HasAttributeList obj,
info ~ ResolveAttribute attr obj,
AttrInfo info,
AttrBaseTypeConstraint info obj,
tag ~ 'AttrSet,
AttrOpAllowed 'AttrSet info obj,
AttrOpAllowed 'AttrGet info obj,
(AttrSetTypeConstraint info) b,
a ~ (AttrGetType info)) =>
AttrLabelProxy (attr :: Symbol) -> (a -> b) -> AttrOp obj tag
(:~>) :: (HasAttributeList obj,
info ~ ResolveAttribute attr obj,
AttrInfo info,
AttrBaseTypeConstraint info obj,
tag ~ 'AttrSet,
AttrOpAllowed 'AttrSet info obj,
AttrOpAllowed 'AttrGet info obj,
(AttrSetTypeConstraint info) b,
a ~ (AttrGetType info)) =>
AttrLabelProxy (attr :: Symbol) -> (a -> IO b) -> AttrOp obj tag
set :: forall o m. MonadIO m => o -> [AttrOp o 'AttrSet] -> m ()
set obj = liftIO . mapM_ app
where
resolve :: AttrLabelProxy attr -> Proxy (ResolveAttribute attr o)
resolve _ = Proxy
app :: AttrOp o 'AttrSet -> IO ()
app (attr := x) = attrSet (resolve attr) obj x
app (attr :=> x) = x >>= attrSet (resolve attr) obj
app (attr :~ f) = attrGet (resolve attr) obj >>=
\v -> attrSet (resolve attr) obj (f v)
app (attr :~> f) = attrGet (resolve attr) obj >>= f >>=
attrSet (resolve attr) obj
type AttrGetC info obj attr result = (HasAttributeList obj,
info ~ ResolveAttribute attr obj,
AttrInfo info,
(AttrBaseTypeConstraint info) obj,
AttrOpAllowed 'AttrGet info obj,
result ~ AttrGetType info)
get :: forall info attr obj result m.
(AttrGetC info obj attr result, MonadIO m) =>
obj -> AttrLabelProxy (attr :: Symbol) -> m result
get o _ = liftIO $ attrGet (Proxy :: Proxy info) o
type AttrClearC info obj attr = (HasAttributeList obj,
info ~ ResolveAttribute attr obj,
AttrInfo info,
(AttrBaseTypeConstraint info) obj,
AttrOpAllowed 'AttrClear info obj)
clear :: forall info attr obj m.
(AttrClearC info obj attr, MonadIO m) =>
obj -> AttrLabelProxy (attr :: Symbol) -> m ()
clear o _ = liftIO $ attrClear (Proxy :: Proxy info) o