@@ -103,7 +103,7 @@ import Foreign.Marshal.Alloc (alloca, free)
103103import Foreign.Marshal.Array (newArray , withArrayLen )
104104import Foreign.Marshal.Unsafe (unsafeLocalState )
105105import Foreign.Marshal.Utils (new , with )
106- import Foreign.Ptr (FunPtr , Ptr , freeHaskellFunPtr )
106+ import Foreign.Ptr (FunPtr , Ptr , freeHaskellFunPtr , nullPtr )
107107
108108import Control.Monad (void )
109109import Data.List (intercalate )
@@ -315,6 +315,7 @@ processQQ safety isPure (QQParse rustRet rustBody rustNamedArgs) = do
315315 (returnFfi, haskRet') <- do
316316 marshalForm <- ghcMarshallable haskRet
317317 let fptrRet haskRet' = [t |Ptr (Ptr $(pure haskRet'), FunPtr (Ptr $(pure haskRet') -> IO ())) -> IO ()|]
318+ let bsRet = [t |Ptr (Ptr Word8, Word, FunPtr (Ptr Word8 -> Word -> IO ())) -> IO ()|]
318319 ret <- case marshalForm of
319320 BoxedDirect -> [t |IO $(pure haskRet)|]
320321 BoxedIndirect -> [t |Ptr $(pure haskRet) -> IO ()|]
@@ -323,7 +324,8 @@ processQQ safety isPure (QQParse rustRet rustBody rustNamedArgs) = do
323324 | otherwise ->
324325 let retTy = showTy haskRet
325326 in fail (" Cannot put unlifted type ‘" ++ retTy ++ " ’ in IO" )
326- ByteString -> [t |Ptr (Ptr Word8, Word, FunPtr (Ptr Word8 -> Word -> IO ())) -> IO ()|]
327+ ByteString -> bsRet
328+ OptionalByteString -> bsRet
327329 ForeignPtr
328330 | AppT _ haskRet' <- haskRet -> fptrRet haskRet'
329331 | otherwise -> fail (" Cannot marshal " ++ showTy haskRet ++ " using the ForeignPtr calling convention" )
@@ -356,6 +358,9 @@ processQQ safety isPure (QQParse rustRet rustBody rustNamedArgs) = do
356358 ByteString -> do
357359 rbsT <- [t |Ptr (Ptr Word8, Word)|]
358360 pure (ByteString , rbsT)
361+ OptionalByteString -> do
362+ rbsT <- [t |Ptr (Ptr Word8, Word)|]
363+ pure (OptionalByteString , rbsT)
359364 ForeignPtr
360365 | AppT _ haskArg' <- haskArg -> do
361366 ptr <- [t |Ptr $(pure haskArg')|]
@@ -431,6 +436,26 @@ processQQ safety isPure (QQParse rustRet rustBody rustNamedArgs) = do
431436 else Just <$> newForeignPtr $(varE finalizer) $(varE ptr)
432437 )
433438 |]
439+ | returnFfi == OptionalByteString = do
440+ ret <- newName " ret"
441+ ptr <- newName " ptr"
442+ len <- newName " len"
443+ finalizer <- newName " finalizer"
444+ [e |
445+ alloca
446+ ( \($(varP ret)) -> do
447+ $(appsE (varE qqName : reverse (varE ret : acc)))
448+ ($(varP ptr), $(varP len), $(varP finalizer)) <- peek $(varE ret)
449+ if $(varE ptr) == nullPtr
450+ then pure Nothing
451+ else
452+ Just
453+ <$> ByteString.unsafePackCStringFinalizer
454+ $(varE ptr)
455+ (fromIntegral $(varE len))
456+ ($(varE bsFree) $(varE finalizer) $(varE ptr) $(varE len))
457+ )
458+ |]
434459 | returnByValue returnFfi = appsE (varE qqName : reverse acc)
435460 | otherwise = do
436461 ret <- newName " ret"
@@ -475,6 +500,7 @@ processQQ safety isPure (QQParse rustRet rustBody rustNamedArgs) = do
475500 Just $(varP fptr) ->
476501 withForeignPtr $(varE fptr) (\($(varP ptr)) -> $(goArgs (varE ptr : acc) args))
477502 |]
503+ | marshalForm == OptionalByteString -> fail " Don't"
478504 | passByValue marshalForm -> goArgs (varE argName : acc) args
479505 | otherwise -> do
480506 x <- newName " x"
0 commit comments