module FFI.Anything.TypeUncurry.Msgpack (
MessagePackRec (..)
, getTypeListFromMsgpackArray
, uncurryMsgpack
, tryUncurryMsgpack
, tryUncurryMsgpackIO
, byteStringToCStringFun
, byteStringToCStringFunIO
, export
, exportIO
, module FFI.Anything.TypeUncurry.ReturnResult
) where
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import Data.Maybe (fromMaybe)
import qualified Data.MessagePack as MSG
import Data.Vector (Vector)
import qualified Data.Vector as V
import Foreign.C
import FFI.Anything.TypeUncurry.ReturnResult
import FFI.Anything.TypeUncurry
class MessagePackRec l where
fromObjectRec :: Vector MSG.Object -> Maybe (TypeList l)
instance MessagePackRec '[] where
fromObjectRec v | V.null v = Just Nil
fromObjectRec _ = Nothing
instance (MSG.MessagePack a, MessagePackRec l) => MessagePackRec (a ': l) where
fromObjectRec v | not (V.null v) = (:::) <$> MSG.fromObject (V.head v) <*> fromObjectRec (V.tail v)
fromObjectRec _ = Nothing
getTypeListFromMsgpackArray :: forall l . (MessagePackRec l, ParamLength l) => MSG.Object -> Maybe (TypeList l)
getTypeListFromMsgpackArray obj = case obj of
MSG.ObjectArray v | V.length v == len -> fromObjectRec v
_ -> Nothing
where
len = paramLength (Proxy :: Proxy l)
instance (MessagePackRec l, ParamLength l) => MSG.MessagePack (TypeList l) where
fromObject = getTypeListFromMsgpackArray
toObject = error "call-haskell-from-anything: Serialising a TypeList is not supported (and not needed)!"
errorMsg :: String -> String
errorMsg locationStr = "call-haskell-from-anything: " ++ locationStr ++ ": got wrong number of function arguments or non-array"
uncurryMsgpack :: (MSG.MessagePack (TypeList l), ToTypeList f l r, MSG.MessagePack r) => f -> (ByteString -> ByteString)
uncurryMsgpack f = \bs -> BSL.toStrict . MSG.pack $ (translate f $ fromMaybe (error (errorMsg "uncurryMsgpack")) $ MSG.unpack $ BSL.fromStrict bs)
uncurryMsgpackIO :: (MSG.MessagePack (TypeList l), ToTypeList f l (IO r), MSG.MessagePack r) => f -> (ByteString -> IO ByteString)
uncurryMsgpackIO f = \bs -> BSL.toStrict . MSG.pack <$> (translate f $ fromMaybe (error (errorMsg "uncurryMsgpackIO")) $ MSG.unpack $ BSL.fromStrict bs)
tryUncurryMsgpack :: (MSG.MessagePack (TypeList l), ToTypeList f l r, MSG.MessagePack r) => f -> (ByteString -> Maybe ByteString)
tryUncurryMsgpack f = \bs -> case MSG.unpack $ BSL.fromStrict bs of
Nothing -> Nothing
Just args -> Just . BSL.toStrict . MSG.pack $ (translate f $ args)
tryUncurryMsgpackIO :: (MSG.MessagePack (TypeList l), ToTypeList f l (IO r), MSG.MessagePack r) => f -> (ByteString -> Maybe (IO ByteString))
tryUncurryMsgpackIO f = \bs -> case MSG.unpack $ BSL.fromStrict bs of
Nothing -> Nothing
Just args -> Just $ BSL.toStrict . MSG.pack <$> (translate f $ args)
byteStringToCStringFun :: (ByteString -> ByteString) -> CString -> IO CString
byteStringToCStringFun f cs = do
cs_bs <- BS.packCString cs
let res_bs = f cs_bs
res_cs <- BS.useAsCString res_bs return
return res_cs
byteStringToCStringFunIO :: (ByteString -> IO ByteString) -> CString -> IO CString
byteStringToCStringFunIO f cs = do
cs_bs <- BS.packCString cs
res_bs <- f cs_bs
res_cs <- BS.useAsCString res_bs return
return res_cs
export :: (MSG.MessagePack (TypeList l), ToTypeList f l r, MSG.MessagePack r) => f -> CString -> IO CString
export = byteStringToCStringFun . uncurryMsgpack
exportIO :: (MSG.MessagePack (TypeList l), ToTypeList f l (IO r), MSG.MessagePack r) => f -> CString -> IO CString
exportIO = byteStringToCStringFunIO . uncurryMsgpackIO