ByteStrings, FFI, iovec
Folks, 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. Antoine [1] http://linux.die.net/man/3/writev [2] http://www.cse.unsw.edu.au/~chak/haskell/c2hs/ Foreign/IOVec.chs
-- -*-haskell-*-
module Foreign.IOVec (IOVec() ,withLazyByteString ) where 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> #c typedef struct iovec hs_iovec; #endc {#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 <<<<<
Quoth Antoine Latter <aslatter@gmail.com>,
... I haven't put this into practice yet,
Really? haven't even tried it? Well, this is just a comment, since I'm not a qualified guru or anything, but I have been using the foreign array functions to do some of the things you're doing by hand, which I suppose in your case means you would need to make a Storable instance for IOVec. Maybe c2hs does this for you? dunno. That done, I would have something like withIOVec :: [P.ByteString] -> ((Ptr IOVec) -> CInt -> IO a) -> IO a withIOVec ss f = wv ss [] where wv [] si = withArray (reverse si) $ \ pa -> f pa (length si) wv (a:ax) si = P.useAsCStringLen a $ \ (p, n) -> wv ax ((IOVec p n):si) writev fd ss = withIOVec ss $ c_writev fd Donn
Hi Antoine, On Sat, Mar 28, 2009 at 7:59 PM, Antoine Latter <aslatter@gmail.com> wrote:
Folks,
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.
network-bytestring [1] includes a FFI wrapper for iovecs that might be useful to look at. 1. http://github.com/tibbe/network-bytestring/tree/master Cheers, Johan
participants (3)
-
Antoine Latter -
Donn Cave -
Johan Tibell