Converting things to and from binary

Glynn Clements glynn.clements@virgin.net
Tue, 20 May 2003 03:48:24 +0100


Tomasz Zielonka wrote:

> > > The general problem to solve is "How to we convert things to and from a
> > > binary format, so they can be efficiently written to and from disk".
> > 
> > Possibly the best way to handle this would be to extend the Storable
> > class, e.g.
> > 
> > class Storable a where
> > 	...
> > 	hPutObj :: Handle -> a -> IO ()
> > 	hGetObj :: Handle -> IO a
> > 	toByteList :: a -> [Word8]
> > 	fromByteList :: [Word8] -> a
> > 	toByteArray :: a -> Array Int Word8
> > 	fromByteArray :: Array Int Word8 -> a
> 
> Hmmm, I thought that Foreign.Storable.Storable is meant for different
> purposes, namely for accessing C data in memory and for marshalling
> between Haskell and C worlds. Are you sure that these functionalities
> must overlap?
> 
> Extending Storable would require to extend its every existing instance.
> It might be better to introduce some subclass, but I'm not sure that
> every type supporting marshalling to and from binary format can
> support operations from Storable.
> 
> It's quite easy to write value of type [[Int]] to disk, but how to
> define alignment and sizeOf methods for this type?

Sorry, I'd overlooked the fact that Storable was limited to fixed-size
types.

In any case, reading/writing data to memory and to disk aren't all
that different; the existence of mmap() relies upon that fact. And,
mmap() aside, on most OSes, all I/O comes down to reading and writing
blocks of memory (i.e. read() and write()); everything else is just
additional layers.

I still think that we need a superclass of Storable, as any instance
of Storable can be read and written with e.g.:

hPutObj :: (Storable a) => Handle -> a -> IO ()
hPutObj h x = do
	alloca $ \ptr -> do
		poke ptr x
		fd <- handleToFd h
		let bptr = castPtr ptr :: Ptr CChar
		let blen = fromIntegral $ sizeOf x
		write fd bptr blen

hGetObj' :: (Storable a) => Handle -> a -> IO a
hGetObj' h dummy = do
	alloca $ \ptr -> do
		let blen = fromIntegral $ sizeOf dummy
		let bptr = castPtr ptr :: Ptr CChar
		fd <- handleToFd h
		read fd bptr blen
		x <- peek ptr
		return x

hGetObj :: (Storable a) => Handle -> IO a
hGetObj h = hGetObj' h undefined

A similar process can be used to convert instances of Storable to or
from a list (or array) of bytes.

-- 
Glynn Clements <glynn.clements@virgin.net>