fpco / inline-c

284 stars 50 forks source link

[feature request] Return tuple #87

Closed cblp closed 5 years ago

cblp commented 5 years ago

I found myself writing such code:

allocaArray 4 $ \arena -> do
    [Cpp.block| void {
        uint64_t * const arena = $(uint64_t * arena);
        uint64_t & x   = arena[0];
        uint64_t & y   = arena[1];
        uint64_t & ptr = arena[2];
        uint64_t & len = arena[3];
        Status & status = * $fptr-ptr:(Status * statusFP);
        x = uint64_t(status.code().value());
        y = uint64_t(status.code().origin());
        ptr = uintptr_t(status.comment().data());
        len = status.comment().length();
    } |]
    code <- UUID <$> peekElemOff arena 0 <*> peekElemOff arena 1
    ptr <- wordPtrToPtr . fromIntegral <$> peekElemOff arena 2
    len <- fromIntegral <$> peekElemOff arena 3
    comment <- BS.packCStringLen (ptr, len)
    pure Status{code, comment}

It would be nice to write instead

[Cpp.block| ARENA(uint64_t x, uint64_t y, const char * ptr, size_t len) {
    Status & status = * $fptr-ptr:(Status * statusFP);
    x = uint64_t(status.code().value());
    y = uint64_t(status.code().origin());
    ptr = uintptr_t(status.comment().data());
    len = status.comment().length();
} |]
code <- UUID x y
comment <- BS.packCStringLen (ptr, len)
pure Status{code, comment}

with all boilerplate generated automagically.

I want to implement it. What do you think?

Alternatives:

  1. http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Structures.html#Structures

    • too complex to use by hand
    • may be useful instead of the arena approach
  2. https://gitlab.haskell.org/ghc/ghc/issues/9700

    • looks too far from done
bitonic commented 5 years ago

@cblp I like the idea! Feel free to submit a PR.

cblp commented 5 years ago

Hm, TH seems to be unable to emit do-statements, so we can't introduce variables in a do-block.

chpatrick commented 5 years ago

I usually use withPtrs for this, it's a bit more boilerplate but it works: http://hackage.haskell.org/package/inline-c-0.7.0.1/docs/Language-C-Inline.html#t:WithPtrs

( x, y, ptr, len ) <- withPtrs_ $ \(xPtr, yPtr, ptrPtr, lenPtr) ->
  [Cpp.block| void {
    Status & status = * $fptr-ptr:(Status * statusFP);
    *$(uint64_t* xPtr) = uint64_t(status.code().value());
    *$(uint64_t* yPtr) = uint64_t(status.code().origin());
    *$(const char** ptrPtr) = uintptr_t(status.comment().data());
    *$(size_t* lenPtr) = status.comment().length();
    } |]

It's a bit more boilerplate but it's not too bad.

cblp commented 5 years ago

@chpatrick, great! thanks!