Next Previous Contents

7.1 The HDirect library

The HDirect library provides basic functionality for packing and unpacking a range of basic values between their external and Haskell representations. It is used quite heavily by the generated the HaskellDirect code, but the functions it exports are often of use in other contexts.

For each of the basic types, it provides the following set of marshaling actions:

module HDirect where

marshallInt    :: Int -> IO Int
unmarshallInt  :: Int -> IO Int
writeInt       :: Ptr Int -> Int -> IO ()
readInt        :: Ptr Int -> IO Int
sizeofInt      :: Word32

 same for  Int{8,16,32,64}
           Word{8,16,32,64}
           Char, Addr
           Double, Float
           Bool, ForeignObj

The library defines five marshalling functions for each of the basic types, by-value and by-reference marshallers plus a constant holding the size of the marshalled representation of the basic type. See the HaskellDirect paper for information of how these functions are used.

To manipulate pointers in Haskell, we define a synonym, Ptr, to (at least) make the type signatures of the pointer manipulating functions more concisely convey their behaviour:

type Ptr a    = Addr  -- we could (and should) use a newtype here.

addNCastPtr   :: Ptr a -> Word32 -> Ptr b
mkPtr         :: Addr  -> Ptr a
pointerToAddr :: Ptr a -> Addr
derefPtr      :: Ptr (Ptr a) -> IO (Ptr a)
indexPtr      :: Ptr (Ptr a) -> Int -> IO (Ptr a)

allocOutPtr   :: IO (Ptr a)
allocBytes    :: Int -> IO (Ptr a)
allocWords    :: Int -> IO (Ptr a)

Ptrs are allocated using the C run-time's malloc(), since they need to be (immovable) pointers that we can hand over to the outside world. To free pointers, the following three actions are provided:

freePtr     :: Ptr a -> IO ()
trivialFree :: Ptr a -> IO ()    -- trivial freeing just 
doThenFree  :: (Ptr a -> IO ())  -- freeing action
            -> (Ptr a -> IO b)   -- unmarshaller
            -> Ptr a             -- the ptr.
            -> IO b

with doThenFree capturing the pattern of unmarshalling a pointer value followed by the release of it. trivialFree is the nullary freeing action, it doesn't call free() on its argument, just ignores it.

DCE IDL categorises pointers into three kinds, ptrs, uniques and refs -- see IDL documentation and the HDirect paper for more information of what distinguishes them. The HDirect library provides the implementation of the pointer marshalling schemes given in that paper -- here's the ptr marshallers:

marshallptr   :: Ptr a -> IO (Ptr a)
unmarshallptr :: Ptr a -> IO (Ptr a)
writeptr      :: Ptr (Ptr a) -> Ptr a -> IO ()
readptr       :: Ptr (Ptr a) -> IO (Ptr a)

writefptr     :: Ptr ForeignObj -> ForeignObj -> IO ()

A unique pointer is represented in Haskell as a Maybe value:

marshallunique :: IO (Ptr a)             -- allocate
               -> (Ptr a -> a -> IO ())  -- marshall into
               -> Maybe a                -- value
               -> IO (Ptr a)
unmarshallunique :: (Ptr a -> IO a)      -- unmarshall value
                 -> Ptr a                -- unique ptr
                 -> IO (Maybe a)
writeunique   :: IO (Ptr a)              -- allocate
              -> (Ptr a -> a -> IO ())   -- marshall into
              -> Ptr a                   -- (ptr to) unique ptr
              -> Maybe a
              -> IO ()
readunique    :: (Ptr a -> IO a)   -- unmarshall value
              -> Ptr (Ptr a)       -- unique ptr.
              -> IO (Maybe a)
freeunique    :: (Ptr a -> IO ())
              -> Ptr (Ptr a)
              -> IO ()

Reference (ref) pointers are invisible in Haskell, representing them by the value they point to:

marshallref  :: IO (Ptr a)
             -> (Ptr a -> a -> IO ())
             -> a
             -> IO (Ptr a)
unmarshallref :: (Ptr a -> IO b)
              -> Ptr a
              -> IO b
writeref      :: IO (Ptr a)
              -> (Ptr a -> a -> IO ())
              -> Ptr (Ptr a)
              -> a
              -> IO ()
readref       :: (Ptr a -> IO a)
              -> Ptr (Ptr a)
              -> IO a
freeref       :: (Ptr a -> IO ())
              -> Ptr b
              -> IO ()

The generated HaskellDirect source maps IDL enumerations onto Haskell enumeration types (and define Enum instances over them). To marshall such values across the boundary, the following helper functions are used:

marshallEnum32   :: Enum a => a -> IO Int32
unmarshallEnum32 :: Enum a => Int32 -> IO a
writeEnum32      :: Enum a => Ptr Int32 -> a -> IO ()
readEnum32       :: Enum a => Ptr Int32 -> IO a

marshallEnum16   :: Enum a => a -> IO Int16
unmarshallEnum16 :: Enum a => Int16 -> IO a
writeEnum16      :: Enum a => Ptr Int16 -> a -> IO ()
readEnum16       :: Enum a => Ptr Int16 -> IO a

To marshall lists of values, the following set of actions are provided:

marshalllist :: Word32                 -- size of a (marshalled) value
             -> (Ptr a -> a -> IO ())  -- (reference) marshaller for a value
             -> [a]                    -- values
             -> IO (Ptr [a])

unmarshalllist :: Word32               -- size of a (marshalled) value
               -> Word32               -- starting offset (in sizeof units).
               -> Word32               -- number of values to unmarshal
               -> (Ptr a -> IO a)      -- (reference) unmarshall for a value
               -> Ptr [a]
               -> IO [a]

writelist      :: Bool                  -- do we have to allocate?
               -> Word32                -- size of a (marshalled) value
               -> (Ptr a -> a -> IO ()) -- (reference) marshaller.
               -> Ptr [a]               -- where to put the marshalled list.
               -> [a]
               -> IO ()

readlist       :: Word32                -- size of a (marshalled) value.
               -> Word32                -- number of elements to unmarshal
               -> (Ptr a -> IO a)       -- (reference) unmarshaller.
               -> Ptr [a]
               -> IO [a]

freelist       :: Word32                -- size of a (marshalled) value.
               -> Word32                -- number of elements
               -> (Ptr a -> IO ())      -- how to free an element.
               -> Ptr [a]
               -> IO ()

We provide a special set of marshallers for String, which map to and from the external representation of a zero-terminated sequence of (8-bit byte) characters:

marshallString    :: String -> IO (Ptr String)
unmarshallString  :: Ptr String -> IO String
readString        :: Ptr (Ptr String) -> IO String
writeString       :: Bool -> Ptr String -> String -> IO ()
freeString        :: Ptr String -> IO ()

A special case of the string marshallers allow you to express the number of characters you want to marshall across (in either direction):

marshallBString   :: Int  -> String -> IO (Ptr String)
unmarshallBString :: Int  -> Ptr String -> IO String
writeBString      :: Bool -> Int -> Ptr String -> String -> IO ()
readBString       :: Int  -> Ptr (Ptr String) -> IO String

Restricting the marshalling to a fixed number of elements in a list is sometimes useful for other list values too, so we provide the following set:

marshallblist :: Word32
              -> Word32
              -> (Ptr a -> a -> IO ())
              -> [a]
              -> IO (Ptr [a])
writeblist    :: Word32
              -> Word32
              -> (Ptr a -> a -> IO ())
              -> Ptr [a]
              -> [a]
              -> IO ()
readblist     :: Word32
              -> Word32
              -> (Ptr a -> IO a)
              -> Ptr a
              -> IO [a]


Next Previous Contents