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]