hsqml-datamodel-0.2.0.2: src/Graphics/QML/DataModel/Internal/Generic/Get.hs
{-# OPTIONS_HADDOCK show-extensions #-}
{-# LANGUAGE
DefaultSignatures
, FlexibleContexts
, FlexibleInstances
, PolyKinds
, ScopedTypeVariables
, TypeOperators
#-}
{-|
Module : Graphics.QML.DataModel.Internal.Generic.Get
Copyright : (c) Marcin Mrotek, 2015
License : BSD3
Maintainer : marcin.jan.mrotek@gmail.com
Stability : experimental
Indexing data types by columns.
-}
module Graphics.QML.DataModel.Internal.Generic.Get where
import Graphics.QML.DataModel.Internal.FFI
import Graphics.QML.DataModel.Internal.Generic.Count
import Control.Exception
import Control.Monad
import Data.Proxy
import Data.Text (Text, unpack)
import Foreign.C.Types
import GHC.Generics
import Numeric.Natural
-- |A class of types with columns that can be indexed by an integer. A generic implementation is provided for all single constructor types.
class QtTable t where
getColumn :: Int -> t -> IO QtVariant
default getColumn :: (Generic t, GQtTable (Rep t)) => Int -> t -> IO QtVariant
getColumn ix = gGetColumn ix . from
-- |A generic implementation of 'QtTable'.
class GQtTable f where
gGetColumn :: Int -> f a -> IO QtVariant
-- |If only one value is available, it's returned regardless of the index.
instance QtField t => GQtTable (K1 i t) where
gGetColumn _ (K1 v) = qtField v
-- |Meta information is skipped, and the recursion proceeds further down.
instance GQtTable f => GQtTable (M1 i t f) where
gGetColumn ix (M1 a) = gGetColumn ix a
-- |One branch of a product type is chosen depending on the index.
instance (GCountFields a, GCountFields b, GQtTable a, GQtTable b) => GQtTable (a :*: b) where
gGetColumn ix (a :*: b) = do
when (ix < 0) . throwIO $ ColumnIndexNegative ix
when (ix >= (na + nb)) . throwIO $ ColumnIndexOutOfBounds ix (na + nb)
if ix < na
then gGetColumn ix a
else gGetColumn (ix - na) b
where na = gCountFields pa
nb = gCountFields pb
pa :: Proxy a = Proxy
pb :: Proxy b = Proxy
-- |A class of types with columns that can be cast to a 'QtVariant'.
class QtField t where
qtField :: t -> IO QtVariant
instance QtField Int where
qtField = c_newQtInt . CInt . fromIntegral
instance QtField Double where
qtField = c_newQtDouble . CDouble
instance QtField String where
qtField = newQtString
instance QtField Text where
qtField = newQtString . unpack
instance QtField Bool where
qtField v = c_newQtBool $ fromIntegral b
where b :: Int
b = if v then 1 else 0
-- |Integers are marshalled through QT strings rather than ints.
instance QtField Integer where
qtField = newQtString . show
-- |Naturals are marshalled through QT strings rather than ints.
instance QtField Natural where
qtField = newQtString . show
-- |'Nothing' is marshalled as QT null.
instance QtField t => QtField (Maybe t) where
qtField Nothing = c_newQtNull
qtField (Just t) = qtField t