module FFI.Anything.TypeUncurry.Msgpack (
MessagePackRec (..)
, getTypeListFromMsgpackArray
, uncurryMsgpack
, tryUncurryMsgpack
, tryUncurryMsgpackIO
, byteStringToCStringFun
, byteStringToCStringFunIO
, export
, exportIO
) 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.Proxy
import Data.Vector (Vector)
import qualified Data.Vector as V
import Foreign.C
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