clr-inline-0.1.0.0: src/Clr/Inline/Types.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ViewPatterns #-}
module Clr.Inline.Types where
import Clr.Host.BStr
import Clr.Marshal
import Clr.Marshal.Host
import Data.Int
import Data.IORef
import Data.Maybe
import Data.Proxy
import Data.Text (Text)
import Data.Word
import Foreign
import GHC.TypeLits
import Language.Haskell.TH
import System.IO.Unsafe
-- | A pointer to a Clr object.
-- The only way to access the contents is via clr-inline quotations.
newtype ClrPtr (name::Symbol)= ClrPtr Int64
-- | A wrapper around a 'ClrPtr', which will be released once this
-- wrapper is no longer referenced.
-- The only way to access the contents is in clr-inline quotations.
data Clr (name::Symbol) = Clr (ClrPtr name) (IORef ())
foreign import ccall "dynamic" releaseObject :: FunPtr (Int64 -> IO ()) -> (Int64 -> IO ())
instance Unmarshal (ClrPtr n) (Clr n) where
unmarshal o@(ClrPtr id) = do
ref <- newIORef ()
_ <- mkWeakIORef ref $ do
let f = unsafeDupablePerformIO (unsafeGetPointerToMethod "ReleaseObject")
releaseObject f id
return (Clr o ref)
instance Marshal (Clr n) (ClrPtr n) where
marshal (Clr ptr ref) f = do
() <- readIORef ref
f ptr
newtype ClrType = ClrType {getClrType :: String} deriving Show
newtype TextBStr = TextBStr BStr
instance Unmarshal TextBStr Text where unmarshal (TextBStr t) = unmarshal t
instance Marshal Text TextBStr where marshal x f = marshal x (f . TextBStr)
-- | Extensible mapping between quotable CLR types and Haskell types
class Unmarshal marshal haskell =>
Quotable (quoted::Symbol) (clr::Symbol) marshal haskell | marshal -> haskell clr
instance Quotable "bool" "System.Boolean" Bool Bool
instance Quotable "double" "System.Double" Double Double
instance Quotable "int" "System.Int32" Int Int
instance Quotable "int16" "System.Int16" Int16 Int16
instance Quotable "int32" "System.Int32" Int32 Int32
instance Quotable "int64" "System.Int64" Int64 Int64
instance Quotable "long" "System.Int64" Int64 Int64
instance Quotable "uint16" "System.UInt16" Word16 Word16
instance Quotable "word16" "System.UInt16" Word16 Word16
instance Quotable "uint32" "System.UInt32" Word32 Word32
instance Quotable "word32" "System.UInt32" Word32 Word32
instance Quotable "uint64" "System.UInt64" Word64 Word64
instance Quotable "word64" "System.UInt64" Word64 Word64
instance Quotable "string" "System.String" BStr String
instance Quotable "text" "System.String" TextBStr Text
instance Quotable "void" "System.Void" () ()
-- | All reference types are handled by this instance.
instance Quotable a a (ClrPtr a) (Clr a)
lookupQuotable :: Show a => ([InstanceDec] -> a) -> String -> Q a
lookupQuotable extract quote = do
let ty = LitT (StrTyLit quote)
a <- newName "clr"
b <- newName "rep"
c <- newName "haskell"
instances <- reifyInstances ''Quotable [ ty, VarT a, VarT b, VarT c ]
return $ extract instances
lookupQuotableClrType :: String -> Q ClrType
lookupQuotableClrType s = lookupQuotable extractClrType s
where
extractClrType instances = fromMaybe (general instances) $ listToMaybe $ mapMaybe specific instances
specific (InstanceD _ _ (_ `AppT` _ `AppT` LitT (StrTyLit s) `AppT` _ `AppT` _) _) = Just $ ClrType s
specific _ = Nothing
general [InstanceD _ _ (_ `AppT` quote `AppT` clr `AppT` _ `AppT` _) _] | quote == clr = ClrType s
general _ = error $ "Overlapping instances for Quotable " ++ s
lookupQuotableMarshalType :: String -> Q Type
lookupQuotableMarshalType s = lookupQuotable extractMarshalType s
where
extractMarshalType instances = fromMaybe (general instances) $ listToMaybe $ mapMaybe specific instances
specific (InstanceD _ _ (_ `AppT` quote `AppT` clr `AppT` _ `AppT` _) _) | quote == clr = Nothing
specific (InstanceD _ _ (_ `AppT` _ `AppT` _ `AppT` marshalTy `AppT` _) _) = Just marshalTy
specific _ = Nothing
general [InstanceD _ _ (_ `AppT` quote `AppT` clr `AppT` AppT (ConT clrPtr) _ `AppT` _) _] | quote == clr && clrPtr == ''ClrPtr = AppT (ConT clrPtr) (LitT (StrTyLit s))
general _ = error $ "Overlapping instances for Quotable " ++ s
unmarshalAuto :: Quotable quote clr a unmarshal => Proxy quote -> a -> IO unmarshal
unmarshalAuto _ = unmarshal