[Haskell-cafe] ByteStrings, FFI, iovec

Antoine Latter aslatter at gmail.com
Sat Mar 28 14:59:16 EDT 2009


I'm putting together an FFI layer to a library which uses writev for
its IO, and so expects an array of iovec structs as an argument to one
of its calls.  for more information, check out "man writev"[1].

Since I'm already using Data.Binary, the writev call almost sounds
like a perfect match for lazy bytestrings, so I thought I'd put up
what I have for comments. I'm using c2hs[2].  The recursive nesting of
'withForeignPtr' put me off at first, but I thought I'd at least give
it a shot.  I haven't put this into practice yet, so it could be
buggy.  I'm more looking for comments on the approach.


[1] http://linux.die.net/man/3/writev
[2] http://www.cse.unsw.edu.au/~chak/haskell/c2hs/

-- -*-haskell-*-

module Foreign.IOVec

import C2HS

import qualified Data.ByteString as S
import qualified Data.ByteString.Internal as S
import qualified Data.ByteString.Lazy as L

#include <sys/uio.h>

typedef struct iovec hs_iovec;

{#pointer *hs_iovec as IOVec newtype#}

-- | This is intended for calling into something like writev.
-- But I suppose that nothing stops you from calling into
-- readv and blowing away the passed-in ByteString.
withLazyByteString :: L.ByteString -> (IOVec -> Int -> IO b) -> IO b
withLazyByteString b f =
    let bs = L.toChunks b
        num = length bs
    in allocaBytes (num * {#sizeof hs_iovec#}) $ \vecAry -> go vecAry 0 bs

   where go vecAry off [] = f (IOVec vecAry) off
         go vecAry off (b:bs) =

             let vec = vecAry `plusPtr` (off * {#sizeof hs_iovec#})
                 (fptr, bsOff, bsLen) = S.toForeignPtr b

             in withForeignPtr fptr $ \bsPtr -> do
                  {#set hs_iovec->iov_base#} vec $ castPtr $ bsPtr
`plusPtr` bsOff
                  {#set hs_iovec->iov_len#}  vec $ cIntConv bsLen
                  go vecAry (off+1) bs


More information about the Haskell-Cafe mailing list