{-# 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