From: simonmar Date: Thu, 9 May 2002 13:14:02 +0000 (+0000) Subject: [project @ 2002-05-09 13:13:28 by simonmar] X-Git-Tag: nhc98-1-18-release~1035 X-Git-Url: http://git.megacz.com/?a=commitdiff_plain;h=771f9ba7d06cd1b454d4bf2b133a028887a4d2af;p=ghc-base.git [project @ 2002-05-09 13:13:28 by simonmar] Add documentation Haddock-style --- diff --git a/Foreign/ForeignPtr.hs b/Foreign/ForeignPtr.hs index 43c3325..705bf1f 100644 --- a/Foreign/ForeignPtr.hs +++ b/Foreign/ForeignPtr.hs @@ -9,13 +9,16 @@ -- Stability : provisional -- Portability : portable -- --- This module defines foreign pointers, i.e. addresses with associated --- finalizers. +-- The 'ForeignPtr' type and operations. This module is part of the +-- Foreign Function Interface (FFI) and will usually be imported via +-- the "Foreign" module. -- ----------------------------------------------------------------------------- module Foreign.ForeignPtr - ( ForeignPtr, -- abstract, instance of: Eq + ( + -- * Finalised data pointers + ForeignPtr, -- abstract, instance of: Eq , newForeignPtr -- :: Ptr a -> IO () -> IO (ForeignPtr a) , addForeignPtrFinalizer -- :: ForeignPtr a -> IO () -> IO () , withForeignPtr -- :: ForeignPtr a -> (Ptr a -> IO b) -> IO b @@ -39,7 +42,24 @@ import GHC.Err INSTANCE_TYPEABLE1(ForeignPtr,foreignPtrTc,"ForeignPtr") #ifdef __GLASGOW_HASKELL__ +-- |The type 'ForeignPtr' represents references to objects that are +-- maintained in a foreign language, i.e., that are not part of the +-- data structures usually managed by the Haskell storage manager. +-- The essential difference between 'ForeignPtr's and vanilla memory +-- references of type @Ptr a@ is that the former may be associated +-- with /finalisers/. A finaliser is a routine that is invoked when +-- the Haskell storage manager detects that - within the Haskell heap +-- and stack - there are no more references left that are pointing to +-- the 'ForeignPtr'. Typically, the finaliser will, then, invoke +-- routines in the foreign language that free the resources bound by +-- the foreign object. +-- +-- The 'ForeignPtr' is parameterised in the same way as 'Ptr'. The +-- type argument of 'ForeignPtr' should normally be an instance of +-- class 'Storable'. +-- data ForeignPtr a = ForeignPtr ForeignObj# + instance CCallable (ForeignPtr a) eqForeignPtr :: ForeignPtr a -> ForeignPtr a -> Bool @@ -50,12 +70,24 @@ instance Eq (ForeignPtr a) where p /= q = not (eqForeignPtr p q) newForeignPtr :: Ptr a -> IO () -> IO (ForeignPtr a) +-- ^Turns a plain memory reference into a foreign object +-- by associating a finaliser - given by the monadic operation +-- - with the reference. The finaliser will be executed after +-- the last reference to the foreign object is dropped. Note +-- that there is no guarantee on how soon the finaliser is +-- executed after the last reference was dropped; this depends +-- on the details of the Haskell storage manager. The only +-- guarantee is that the finaliser runs before the program +-- terminates. newForeignPtr p finalizer = do fObj <- mkForeignPtr p addForeignPtrFinalizer fObj finalizer return fObj addForeignPtrFinalizer :: ForeignPtr a -> IO () -> IO () +-- ^This function adds another finaliser to the given +-- foreign object. No guarantees are made on the order in +-- which multiple finalisers for a single object are run. addForeignPtrFinalizer (ForeignPtr fo) finalizer = IO $ \s -> case mkWeak# fo () finalizer s of { (# s1, w #) -> (# s1, () #) } @@ -65,18 +97,72 @@ mkForeignPtr (Ptr obj) = IO ( \ s# -> (# s1#, fo# #) -> (# s1#, ForeignPtr fo# #) ) touchForeignPtr :: ForeignPtr a -> IO () +-- ^This function ensures that the foreign object in +-- question is alive at the given place in the sequence of IO +-- actions. In particular 'withForeignPtr' +-- does a 'touchForeignPtr' after it +-- executes the user action. +-- +-- This function can be used to express liveness +-- dependencies between 'ForeignPtr's: for +-- example, if the finalizer for one +-- 'ForeignPtr' touches a second +-- 'ForeignPtr', then it is ensured that the +-- second 'ForeignPtr' will stay alive at +-- least as long as the first. This can be useful when you +-- want to manipulate /interior pointers/ to +-- a foreign structure: you can use +-- 'touchForeignObj' to express the +-- requirement that the exterior pointer must not be finalized +-- until the interior pointer is no longer referenced. touchForeignPtr (ForeignPtr fo) = IO $ \s -> case touch# fo s of s -> (# s, () #) withForeignPtr :: ForeignPtr a -> (Ptr a -> IO b) -> IO b +-- ^This is a way to look at the pointer living inside a +-- foreign object. This function takes a function which is +-- applied to that pointer. The resulting 'IO' action is then +-- executed. The foreign object is kept alive at least during +-- the whole action, even if it is not used directly +-- inside. Note that it is not safe to return the pointer from +-- the action and use it after the action completes. All uses +-- of the pointer should be inside the +-- 'withForeignPtr' bracket. The reason for +-- this unsafety is the same as for +-- 'foreignPtrToPtr' below: the finalizer +-- may run earlier than expected, because the compiler can only +-- track usage of the 'ForeignPtr' object, not +-- a 'Ptr' object made from it. +-- +-- This function is normally used for marshalling data to +-- or from the object pointed to by the +-- 'ForeignPtr', using the operations from the +-- 'Storable' class. withForeignPtr fo io = do r <- io (foreignPtrToPtr fo) touchForeignPtr fo return r foreignPtrToPtr :: ForeignPtr a -> Ptr a +-- ^This function extracts the pointer component of a foreign +-- pointer. This is a potentially dangerous operations, as if the +-- argument to 'foreignPtrToPtr' is the last usage +-- occurence of the given foreign pointer, then its finaliser(s) will +-- be run, which potentially invalidates the plain pointer just +-- obtained. Hence, 'touchForeignPtr' must be used +-- wherever it has to be guaranteed that the pointer lives on - i.e., +-- has another usage occurrence. +-- +-- To avoid subtle coding errors, hand written marshalling code +-- should preferably use 'withForeignPtr' rather +-- than combinations of 'foreignPtrToPtr' and +-- 'touchForeignPtr'. However, the later routines +-- are occasionally preferred in tool generated marshalling code. foreignPtrToPtr (ForeignPtr fo) = Ptr (foreignObjToAddr# fo) +castForeignPtr :: ForeignPtr a -> ForeignPtr b +-- ^This function casts a 'ForeignPtr' +-- parameterised by one type into another type. castForeignPtr (ForeignPtr a) = ForeignPtr a #endif diff --git a/Foreign/Marshal/Alloc.hs b/Foreign/Marshal/Alloc.hs index d02ef75..7567743 100644 --- a/Foreign/Marshal/Alloc.hs +++ b/Foreign/Marshal/Alloc.hs @@ -14,6 +14,7 @@ ----------------------------------------------------------------------------- module Foreign.Marshal.Alloc ( + -- * Allocation malloc, -- :: Storable a => IO (Ptr a) mallocBytes, -- :: Int -> IO (Ptr a) @@ -43,7 +44,9 @@ import GHC.Base -- exported functions -- ------------------ --- allocate space for storable type +-- |Allocate space for storable type. The size of the area allocated +-- is determined by the 'sizeOf' method from the instance of +-- 'Storable' for the appropriate type. -- malloc :: Storable a => IO (Ptr a) malloc = doMalloc undefined @@ -51,16 +54,16 @@ malloc = doMalloc undefined doMalloc :: Storable a => a -> IO (Ptr a) doMalloc dummy = mallocBytes (sizeOf dummy) --- allocate given number of bytes of storage +-- |Allocate given number of bytes of storage, equivalent to C\'s @malloc()@. -- mallocBytes :: Int -> IO (Ptr a) mallocBytes size = failWhenNULL "malloc" (_malloc (fromIntegral size)) --- temporarily allocate space for a storable type +-- |Temporarily allocate space for a storable type. -- --- * the pointer passed as an argument to the function must *not* escape from --- this function; in other words, in `alloca f' the allocated storage must --- not be used after `f' returns +-- * the pointer passed as an argument to the function must /not/ escape from +-- this function; in other words, in @alloca f@ the allocated storage must +-- not be used after @f@ returns -- alloca :: Storable a => (Ptr a -> IO b) -> IO b alloca = doAlloca undefined @@ -68,11 +71,11 @@ alloca = doAlloca undefined doAlloca :: Storable a => a -> (Ptr a -> IO b) -> IO b doAlloca dummy = allocaBytes (sizeOf dummy) --- temporarily allocate the given number of bytes of storage +-- |Temporarily allocate the given number of bytes of storage. -- --- * the pointer passed as an argument to the function must *not* escape from --- this function; in other words, in `allocaBytes n f' the allocated storage --- must not be used after `f' returns +-- * the pointer passed as an argument to the function must /not/ escape from +-- this function; in other words, in @allocaBytes n f@ the allocated storage +-- must not be used after @f@ returns -- #ifdef __GLASGOW_HASKELL__ allocaBytes :: Int -> (Ptr a -> IO b) -> IO b @@ -90,13 +93,15 @@ allocaBytes :: Int -> (Ptr a -> IO b) -> IO b allocaBytes size = bracket (mallocBytes size) free #endif --- adjust a malloc'ed storage area to the given size +-- |Adjust a malloc\'ed storage area to the given size (equivalent to +-- C\'s @realloc()@). -- reallocBytes :: Ptr a -> Int -> IO (Ptr a) reallocBytes ptr size = failWhenNULL "realloc" (_realloc ptr (fromIntegral size)) --- free malloc'ed storage +-- |Free malloc\'ed storage (equivalent to +-- C\'s @free()@) -- free :: Ptr a -> IO () free = _free diff --git a/Foreign/Marshal/Array.hs b/Foreign/Marshal/Array.hs index 55b9c11..002961e 100644 --- a/Foreign/Marshal/Array.hs +++ b/Foreign/Marshal/Array.hs @@ -15,8 +15,9 @@ ----------------------------------------------------------------------------- module Foreign.Marshal.Array ( + -- * Marshalling arrays - -- allocation + -- ** Allocation -- mallocArray, -- :: Storable a => Int -> IO (Ptr a) mallocArray0, -- :: Storable a => Int -> IO (Ptr a) @@ -27,7 +28,7 @@ module Foreign.Marshal.Array ( reallocArray, -- :: Storable a => Ptr a -> Int -> IO (Ptr a) reallocArray0, -- :: Storable a => Ptr a -> Int -> IO (Ptr a) - -- marshalling + -- ** Marshalling -- peekArray, -- :: Storable a => Int -> Ptr a -> IO [a] peekArray0, -- :: (Storable a, Eq a) => a -> Ptr a -> IO [a] @@ -35,7 +36,7 @@ module Foreign.Marshal.Array ( pokeArray, -- :: Storable a => Ptr a -> [a] -> IO () pokeArray0, -- :: Storable a => a -> Ptr a -> [a] -> IO () - -- combined allocation and marshalling + -- ** Combined allocation and marshalling -- newArray, -- :: Storable a => [a] -> IO (Ptr a) newArray0, -- :: Storable a => a -> [a] -> IO (Ptr a) @@ -43,16 +44,17 @@ module Foreign.Marshal.Array ( withArray, -- :: Storable a => [a] -> (Ptr a -> IO b) -> IO b withArray0, -- :: Storable a => a -> [a] -> (Ptr a -> IO b) -> IO b - -- copying (argument order: destination, source) - -- + -- ** Copying + + -- | (argument order: destination, source) copyArray, -- :: Storable a => Ptr a -> Ptr a -> Int -> IO () moveArray, -- :: Storable a => Ptr a -> Ptr a -> Int -> IO () - -- finding the length + -- ** Finding the length -- lengthArray0, -- :: (Storable a, Eq a) => a -> Ptr a -> IO Int - -- indexing + -- ** Indexing -- advancePtr, -- :: Storable a => Ptr a -> Int -> Ptr a ) where @@ -62,7 +64,7 @@ import Control.Monad #ifdef __GLASGOW_HASKELL__ import Foreign.Ptr (Ptr, plusPtr) import GHC.Storable (Storable(sizeOf,peekElemOff,pokeElemOff)) -import Foreign.Marshal.Alloc (mallocBytes, allocaBytes, reallocBytes) +import Foreign.Marshal.Alloc (alloca, mallocBytes, allocaBytes, reallocBytes) import Foreign.Marshal.Utils (copyBytes, moveBytes) import GHC.IOBase import GHC.Num @@ -74,7 +76,7 @@ import GHC.Base -- allocation -- ---------- --- allocate storage for the given number of elements of a storable type +-- |Allocate storage for the given number of elements of a storable type. -- mallocArray :: Storable a => Int -> IO (Ptr a) mallocArray = doMalloc undefined @@ -82,14 +84,14 @@ mallocArray = doMalloc undefined doMalloc :: Storable a => a -> Int -> IO (Ptr a) doMalloc dummy size = mallocBytes (size * sizeOf dummy) --- like `mallocArray', but add an extra element to signal the end of the array +-- |Like 'mallocArray', but add an extra element to signal the end of the array -- mallocArray0 :: Storable a => Int -> IO (Ptr a) mallocArray0 size = mallocArray (size + 1) --- temporarily allocate space for the given number of elements +-- |Temporarily allocate space for the given number of elements. -- --- * see `MarshalAlloc.alloca' for the storage lifetime constraints +-- * see 'Foreign.Marshal.Alloc.alloca' for the storage lifetime constraints -- allocaArray :: Storable a => Int -> (Ptr a -> IO b) -> IO b allocaArray = doAlloca undefined @@ -97,12 +99,12 @@ allocaArray = doAlloca undefined doAlloca :: Storable a => a -> Int -> (Ptr a -> IO b) -> IO b doAlloca dummy size = allocaBytes (size * sizeOf dummy) --- like `allocaArray', but add an extra element to signal the end of the array +-- |Like 'allocaArray', but add an extra element to signal the end of the array -- allocaArray0 :: Storable a => Int -> (Ptr a -> IO b) -> IO b allocaArray0 size = allocaArray (size + 1) --- adjust the size of an array +-- |Adjust the size of an array -- reallocArray :: Storable a => Ptr a -> Int -> IO (Ptr a) reallocArray = doRealloc undefined @@ -110,7 +112,7 @@ reallocArray = doRealloc undefined doRealloc :: Storable a => a -> Ptr a -> Int -> IO (Ptr a) doRealloc dummy ptr size = reallocBytes ptr (size * sizeOf dummy) --- adjust the size of an array while adding an element for the end marker +-- |Adjust the size of an array while adding an element for the end marker -- reallocArray0 :: Storable a => Ptr a -> Int -> IO (Ptr a) reallocArray0 ptr size = reallocArray ptr (size + 1) @@ -119,7 +121,7 @@ reallocArray0 ptr size = reallocArray ptr (size + 1) -- marshalling -- ----------- --- convert an array of given length into a Haskell list. This version +-- |Convert an array of given length into a Haskell list. This version -- traverses the array backwards using an accumulating parameter, -- which uses constant stack space. The previous version using mapM -- needed linear stack space. @@ -131,7 +133,7 @@ peekArray size ptr | size <= 0 = return [] f 0 acc = do e <- peekElemOff ptr 0; return (e:acc) f n acc = do e <- peekElemOff ptr n; f (n-1) (e:acc) --- convert an array terminated by the given end marker into a Haskell list +-- |Convert an array terminated by the given end marker into a Haskell list -- peekArray0 :: (Storable a, Eq a) => a -> Ptr a -> IO [a] peekArray0 marker ptr = loop 0 @@ -142,12 +144,12 @@ peekArray0 marker ptr = loop 0 rest <- loop (i+1) return (val:rest) --- write the list elements consecutive into memory +-- |Write the list elements consecutive into memory -- pokeArray :: Storable a => Ptr a -> [a] -> IO () pokeArray ptr vals = zipWithM_ (pokeElemOff ptr) [0..] vals --- write the list elements consecutive into memory and terminate them with the +-- |Write the list elements consecutive into memory and terminate them with the -- given marker element -- pokeArray0 :: Storable a => a -> Ptr a -> [a] -> IO () @@ -159,7 +161,7 @@ pokeArray0 marker ptr vals = do -- combined allocation and marshalling -- ----------------------------------- --- write a list of storable elements into a newly allocated, consecutive +-- |Write a list of storable elements into a newly allocated, consecutive -- sequence of storable values -- newArray :: Storable a => [a] -> IO (Ptr a) @@ -168,7 +170,7 @@ newArray vals = do pokeArray ptr vals return ptr --- write a list of storable elements into a newly allocated, consecutive +-- |Write a list of storable elements into a newly allocated, consecutive -- sequence of storable values, where the end is fixed by the given end marker -- newArray0 :: Storable a => a -> [a] -> IO (Ptr a) @@ -177,7 +179,7 @@ newArray0 marker vals = do pokeArray0 marker ptr vals return ptr --- temporarily store a list of storable values in memory +-- |Temporarily store a list of storable values in memory -- withArray :: Storable a => [a] -> (Ptr a -> IO b) -> IO b withArray vals f = @@ -188,7 +190,7 @@ withArray vals f = where len = length vals --- like `withArray', but a terminator indicates where the array ends +-- |Like 'withArray', but a terminator indicates where the array ends -- withArray0 :: Storable a => a -> [a] -> (Ptr a -> IO b) -> IO b withArray0 marker vals f = @@ -203,8 +205,8 @@ withArray0 marker vals f = -- copying (argument order: destination, source) -- ------- --- copy the given number of elements from the second array (source) into the --- first array (destination); the copied areas may *not* overlap +-- |Copy the given number of elements from the second array (source) into the +-- first array (destination); the copied areas may /not/ overlap -- copyArray :: Storable a => Ptr a -> Ptr a -> Int -> IO () copyArray = doCopy undefined @@ -212,8 +214,8 @@ copyArray = doCopy undefined doCopy :: Storable a => a -> Ptr a -> Ptr a -> Int -> IO () doCopy dummy dest src size = copyBytes dest src (size * sizeOf dummy) --- copy the given number of elements from the second array (source) into the --- first array (destination); the copied areas *may* overlap +-- |Copy the given number of elements from the second array (source) into the +-- first array (destination); the copied areas /may/ overlap -- moveArray :: Storable a => Ptr a -> Ptr a -> Int -> IO () moveArray = doMove undefined @@ -225,7 +227,7 @@ moveArray = doMove undefined -- finding the length -- ------------------ --- return the number of elements in an array, excluding the terminator +-- |Return the number of elements in an array, excluding the terminator -- lengthArray0 :: (Storable a, Eq a) => a -> Ptr a -> IO Int lengthArray0 marker ptr = loop 0 @@ -238,7 +240,7 @@ lengthArray0 marker ptr = loop 0 -- indexing -- -------- --- advance a pointer into an array by the given number of elements +-- |Advance a pointer into an array by the given number of elements -- advancePtr :: Storable a => Ptr a -> Int -> Ptr a advancePtr = doAdvance undefined diff --git a/Foreign/Marshal/Error.hs b/Foreign/Marshal/Error.hs index 1020f8a..889ab65 100644 --- a/Foreign/Marshal/Error.hs +++ b/Foreign/Marshal/Error.hs @@ -14,8 +14,9 @@ ----------------------------------------------------------------------------- module Foreign.Marshal.Error ( + -- * Error utilities - -- throw an exception on specific return values + -- |Throw an exception on specific return values -- throwIf, -- :: (a -> Bool) -> (a -> String) -> IO a -> IO a throwIf_, -- :: (a -> Bool) -> (a -> String) -> IO a -> IO () @@ -25,7 +26,7 @@ module Foreign.Marshal.Error ( -- => (a -> String) -> IO a -> IO () throwIfNull, -- :: String -> IO (Ptr a) -> IO (Ptr a) - -- discard return value + -- Discard return value -- void -- IO a -> IO () ) where @@ -41,10 +42,10 @@ import GHC.IOBase -- exported functions -- ------------------ --- guard an IO operation and throw an exception if the result meets the given +-- |Guard an 'IO' operation and throw an exception if the result meets the given -- predicate -- --- * the second argument computes an error message from the result of the IO +-- * the second argument computes an error message from the result of the 'IO' -- operation -- throwIf :: (a -> Bool) -> (a -> String) -> IO a -> IO a @@ -53,27 +54,27 @@ throwIf pred msgfct act = res <- act (if pred res then ioError . userError . msgfct else return) res --- like `throwIf', but discarding the result +-- |Like 'throwIf', but discarding the result -- throwIf_ :: (a -> Bool) -> (a -> String) -> IO a -> IO () throwIf_ pred msgfct act = void $ throwIf pred msgfct act --- guards against negative result values +-- |Guards against negative result values -- throwIfNeg :: (Ord a, Num a) => (a -> String) -> IO a -> IO a throwIfNeg = throwIf (< 0) --- like `throwIfNeg', but discarding the result +-- |Like 'throwIfNeg', but discarding the result -- throwIfNeg_ :: (Ord a, Num a) => (a -> String) -> IO a -> IO () throwIfNeg_ = throwIf_ (< 0) --- guards against null pointers +-- |Guards against null pointers -- throwIfNull :: String -> IO (Ptr a) -> IO (Ptr a) throwIfNull = throwIf (== nullPtr) . const --- discard the return value of an IO action +-- |Discard the return value of an 'IO' action -- void :: IO a -> IO () void act = act >> return () diff --git a/Foreign/Marshal/Utils.hs b/Foreign/Marshal/Utils.hs index c8a5f74..87881b6 100644 --- a/Foreign/Marshal/Utils.hs +++ b/Foreign/Marshal/Utils.hs @@ -14,19 +14,20 @@ ----------------------------------------------------------------------------- module Foreign.Marshal.Utils ( + -- * General marshalling utilities - -- combined allocation and marshalling + -- ** Combined allocation and marshalling -- withObject, -- :: Storable a => a -> (Ptr a -> IO b) -> IO b {- FIXME: should be `with' -} new, -- :: Storable a => a -> IO (Ptr a) - -- marshalling of Boolean values (non-zero corresponds to `True') + -- ** Marshalling of Boolean values (non-zero corresponds to 'True') -- fromBool, -- :: Num a => Bool -> a toBool, -- :: Num a => a -> Bool - -- marshalling of Maybe values + -- ** Marshalling of Maybe values -- maybeNew, -- :: ( a -> IO (Ptr a)) -- -> (Maybe a -> IO (Ptr a)) @@ -35,13 +36,13 @@ module Foreign.Marshal.Utils ( maybePeek, -- :: (Ptr a -> IO b ) -- -> (Ptr a -> IO (Maybe b)) - -- marshalling lists of storable objects + -- ** Marshalling lists of storable objects -- withMany, -- :: (a -> (b -> res) -> res) -> [a] -> ([b] -> res) -> res - -- Haskellish interface to memcpy and memmove - -- (argument order: destination, source) - -- + -- ** Haskellish interface to memcpy and memmove + + -- | (argument order: destination, source) copyBytes, -- :: Ptr a -> Ptr a -> Int -> IO () moveBytes -- :: Ptr a -> Ptr a -> Int -> IO () ) where @@ -62,7 +63,7 @@ import GHC.Base -- combined allocation and marshalling -- ----------------------------------- --- allocate storage for a value and marshal it into this storage +-- |Allocate storage for a value and marshal it into this storage -- new :: Storable a => a -> IO (Ptr a) new val = @@ -71,9 +72,9 @@ new val = poke ptr val return ptr --- allocate temporary storage for a value and marshal it into this storage +-- |Allocate temporary storage for a value and marshal it into this storage -- --- * see the life time constraints imposed by `alloca' +-- * see the life time constraints imposed by 'alloca' -- {- FIXME: should be called `with' -} withObject :: Storable a => a -> (Ptr a -> IO b) -> IO b @@ -84,16 +85,16 @@ withObject val f = return res --- marshalling of Boolean values (non-zero corresponds to `True') +-- marshalling of Boolean values (non-zero corresponds to 'True') -- ----------------------------- --- convert a Haskell Boolean to its numeric representation +-- |Convert a Haskell 'Bool' to its numeric representation -- fromBool :: Num a => Bool -> a fromBool False = 0 fromBool True = 1 --- convert a Boolean in numeric representation to a Haskell value +-- |Convert a Boolean in numeric representation to a Haskell value -- toBool :: Num a => a -> Bool toBool = (/= 0) @@ -102,23 +103,23 @@ toBool = (/= 0) -- marshalling of Maybe values -- --------------------------- --- allocate storage and marshall a storable value wrapped into a `Maybe' +-- |Allocate storage and marshall a storable value wrapped into a 'Maybe' -- --- * the `nullPtr' is used to represent `Nothing' +-- * the 'nullPtr' is used to represent 'Nothing' -- maybeNew :: ( a -> IO (Ptr a)) -> (Maybe a -> IO (Ptr a)) maybeNew = maybe (return nullPtr) --- converts a withXXX combinator into one marshalling a value wrapped into a --- `Maybe' +-- |Converts a @withXXX@ combinator into one marshalling a value wrapped into a +-- 'Maybe' -- maybeWith :: ( a -> (Ptr b -> IO c) -> IO c) -> (Maybe a -> (Ptr b -> IO c) -> IO c) maybeWith = maybe ($ nullPtr) --- convert a peek combinator into a one returning `Nothing' if applied to a --- `nullPtr' +-- |Convert a peek combinator into a one returning 'Nothing' if applied to a +-- 'nullPtr' -- maybePeek :: (Ptr a -> IO b) -> Ptr a -> IO (Maybe b) maybePeek peek ptr | ptr == nullPtr = return Nothing @@ -128,7 +129,7 @@ maybePeek peek ptr | ptr == nullPtr = return Nothing -- marshalling lists of storable objects -- ------------------------------------- --- replicates a withXXX combinator over a list of objects, yielding a list of +-- |Replicates a @withXXX@ combinator over a list of objects, yielding a list of -- marshalled objects -- withMany :: (a -> (b -> res) -> res) -- withXXX combinator for one object @@ -143,14 +144,14 @@ withMany withFoo (x:xs) f = withFoo x $ \x' -> -- Haskellish interface to memcpy and memmove -- ------------------------------------------ --- copies the given number of bytes from the second area (source) into the --- first (destination); the copied areas may *not* overlap +-- |Copies the given number of bytes from the second area (source) into the +-- first (destination); the copied areas may /not/ overlap -- copyBytes :: Ptr a -> Ptr a -> Int -> IO () copyBytes dest src size = memcpy dest src (fromIntegral size) --- copies the given number of elements from the second area (source) into the --- first (destination); the copied areas *may* overlap +-- |Copies the given number of elements from the second area (source) into the +-- first (destination); the copied areas /may/ overlap -- moveBytes :: Ptr a -> Ptr a -> Int -> IO () moveBytes dest src size = memmove dest src (fromIntegral size) @@ -159,7 +160,7 @@ moveBytes dest src size = memmove dest src (fromIntegral size) -- auxilliary routines -- ------------------- --- basic C routines needed for memory copying +-- |Basic C routines needed for memory copying -- foreign import ccall unsafe memcpy :: Ptr a -> Ptr a -> CSize -> IO () foreign import ccall unsafe memmove :: Ptr a -> Ptr a -> CSize -> IO () diff --git a/Foreign/Ptr.hs b/Foreign/Ptr.hs index 0544486..4cf8700 100644 --- a/Foreign/Ptr.hs +++ b/Foreign/Ptr.hs @@ -9,25 +9,26 @@ -- Stability : provisional -- Portability : portable -- --- Pointer types. +-- The "Ptr" module provides typed pointers to foreign data. It is part +-- of the Foreign Function Interface (FFI) and will normally be +-- imported via the "Foreign" module. -- ----------------------------------------------------------------------------- module Foreign.Ptr ( - -------------------------------------------------------------------- - -- Data pointers. + + -- * Data pointers - Ptr(..), -- data Ptr a + Ptr, -- data Ptr a nullPtr, -- :: Ptr a castPtr, -- :: Ptr a -> Ptr b plusPtr, -- :: Ptr a -> Int -> Ptr b alignPtr, -- :: Ptr a -> Int -> Ptr a minusPtr, -- :: Ptr a -> Ptr b -> Int - -------------------------------------------------------------------- - -- Function pointers. + -- * Function pointers - FunPtr(..), -- data FunPtr a + FunPtr, -- data FunPtr a nullFunPtr, -- :: FunPtr a castFunPtr, -- :: FunPtr a -> FunPtr b castFunPtrToPtr, -- :: FunPtr a -> Ptr b diff --git a/Foreign/StablePtr.hs b/Foreign/StablePtr.hs index 1b169d0..9b1bb9b 100644 --- a/Foreign/StablePtr.hs +++ b/Foreign/StablePtr.hs @@ -9,20 +9,40 @@ -- Stability : provisional -- Portability : portable -- --- Stable pointers. +-- This module is part of the Foreign Function Interface (FFI) and will usually +-- be imported via the module "Foreign". -- ----------------------------------------------------------------------------- + module Foreign.StablePtr - ( StablePtr, -- abstract + ( -- * Stable references to Haskell values + StablePtr, -- abstract , newStablePtr -- :: a -> IO (StablePtr a) , deRefStablePtr -- :: StablePtr a -> IO a , freeStablePtr -- :: StablePtr a -> IO () , castStablePtrToPtr -- :: StablePtr a -> Ptr () , castPtrToStablePtr -- :: Ptr () -> StablePtr a + , -- ** The C-side interface + + -- $cinterface ) where #ifdef __GLASGOW_HASKELL__ import GHC.Stable import GHC.Err #endif + + +-- $cinterface +-- +-- The following definition is available to C programs inter-operating with +-- Haskell code when including the header @HsFFI.h@. +-- +-- > typedef void *HsStablePtr; /* C representation of a StablePtr */ +-- +-- Note that no assumptions may be made about the values representing stable +-- pointers. In fact, they need not even be valid memory addresses. The only +-- guarantee provided is that if they are passed back to Haskell land, the +-- function 'deRefStablePtr' will be able to reconstruct the +-- Haskell value refereed to by the stable pointer. diff --git a/Foreign/Storable.hs b/Foreign/Storable.hs index 90b655d..9286e9c 100644 --- a/Foreign/Storable.hs +++ b/Foreign/Storable.hs @@ -9,12 +9,16 @@ -- Stability : provisional -- Portability : portable -- --- A class for primitive marshaling +-- The module "Storable" provides most elementary support for +-- marshalling and is part of the language-independent portion of the +-- Foreign Function Interface (FFI), and will normally be imported via +-- the "Foreign" module. -- ----------------------------------------------------------------------------- module Foreign.Storable - ( Storable( + ( -- * The 'Storable' class + Storable( sizeOf, -- :: a -> Int alignment, -- :: a -> Int peekElemOff, -- :: Ptr a -> Int -> IO a diff --git a/GHC/Ptr.lhs b/GHC/Ptr.lhs index 5c6191f..ab0e6e1 100644 --- a/GHC/Ptr.lhs +++ b/GHC/Ptr.lhs @@ -22,22 +22,41 @@ import GHC.Base -- Data pointers. data Ptr a = Ptr Addr# deriving (Eq, Ord) +-- ^ A value of type @'Ptr' a@ represents a pointer to an object, or an +-- array of objects, which may be marshalled to or from Haskell values +-- of type @a@. +-- +-- The type @a@ will normally be an instance of class +-- 'Storable' which provides the marshalling operations. + +-- |The constant 'nullPtr' contains a distinguished value of 'Ptr' +-- that is not associated with a valid memory location. nullPtr :: Ptr a nullPtr = Ptr nullAddr# +-- |The 'castPtr' function casts a pointer from one type to another. castPtr :: Ptr a -> Ptr b castPtr (Ptr addr) = Ptr addr +-- |Advances the given address by the given offset in bytes. plusPtr :: Ptr a -> Int -> Ptr b plusPtr (Ptr addr) (I# d) = Ptr (plusAddr# addr d) +-- |Given an arbitrary address and an alignment constraint, +-- 'alignPtr' yields the next higher address that fulfills the +-- alignment constraint. An alignment constraint @x@ is fulfilled by +-- any address divisible by @x@. This operation is idempotent. alignPtr :: Ptr a -> Int -> Ptr a alignPtr addr@(Ptr a) (I# i) = case remAddr# a i of { 0# -> addr; n -> Ptr (plusAddr# a (i -# n)) } +-- |Computes the offset required to get from the first to the second +-- argument. We have +-- +-- > p2 == p1 \`'plusPtr'\` (p2 \`'minusPtr'\` p1) minusPtr :: Ptr a -> Ptr b -> Int minusPtr (Ptr a1) (Ptr a2) = I# (minusAddr# a1 a2) @@ -48,16 +67,30 @@ instance CReturnable (Ptr a) -- Function pointers for the default calling convention. data FunPtr a = FunPtr Addr# deriving (Eq, Ord) +-- ^ A value of type @'FunPtr' a@ is a pointer to a piece of code. It +-- may be the pointer to a C function or to a Haskell function created +-- using @foreign export dynamic@. A @foreign export +-- dynamic@ should normally be declared to produce a +-- 'FunPtr' of the correct type. For example: +-- +-- > type Compare = 'Int' -> 'Int' -> 'Bool' +-- > foreign export dynamic mkCompare :: Compare -> 'IO' ('FunPtr' Compare) +-- |The constant 'nullFunPtr' contains a +-- distinguished value of 'Ptr' that is not +-- associated with a valid memory location nullFunPtr :: FunPtr a nullFunPtr = FunPtr nullAddr# +-- |Casts a 'FunPtr' to a 'FunPtr' of a different type castFunPtr :: FunPtr a -> FunPtr b castFunPtr (FunPtr addr) = FunPtr addr +-- |Casts a 'FunPtr' to a 'Ptr' castFunPtrToPtr :: FunPtr a -> Ptr b castFunPtrToPtr (FunPtr addr) = Ptr addr +-- |Casts a 'Ptr' to a 'FunPtr' castPtrToFunPtr :: Ptr a -> FunPtr b castPtrToFunPtr (Ptr addr) = FunPtr addr diff --git a/GHC/Storable.lhs b/GHC/Storable.lhs index 7ffadf8..7441272 100644 --- a/GHC/Storable.lhs +++ b/GHC/Storable.lhs @@ -54,24 +54,95 @@ Minimal complete definition: sizeOf, alignment, and one definition in each of the peek/poke families. \begin{code} +{- | +The member functions of this class facilitate writing values of +primitive types to raw memory (which may have been allocated with the +above mentioned routines) and reading values from blocks of raw +memory. The class, furthermore, includes support for computing the +storage requirements and alignment restrictions of storable types. + +Memory addresses are represented as values of type @'Ptr' a@, for some +@a@ which is an instance of class 'Storable'. The type argument to +'Ptr' helps provide some valuable type safety in FFI code (you can\'t +mix pointers of different types without an explicit cast), while +helping the Haskell type system figure out which marshalling method is +needed for a given pointer. + +All marshalling between Haskell and a foreign language ultimately +boils down to translating Haskell data structures into the binary +representation of a corresponding data structure of the foreign +language and vice versa. To code this marshalling in Haskell, it is +necessary to manipulate primtive data types stored in unstructured +memory blocks. The class 'Storable' facilitates this manipulation on +all types for which it is instantiated, which are the standard basic +types of Haskell, the fixed size @Int@ types ('Int8', 'Int16', +'Int32', 'Int64'), the fixed size @Word@ types ('Word8', 'Word16', +'Word32', 'Word64'), 'StablePtr', all types from "CTypes" and +"CTypesISO", as well as 'Ptr'. + +Minimal complete definition: 'sizeOf', 'alignment', one of 'peek', +'peekElemOff' and 'peekByteOff', and one of 'poke', 'pokeElemOff' and +'pokeByteOff'. +-} + class Storable a where - -- sizeOf/alignment *never* use their first argument sizeOf :: a -> Int + -- ^ Computes the storage requirements (in bytes) of the argument. + -- The value of the argument is not used. + alignment :: a -> Int + -- ^ Computes the alignment constraint of the argument. An + -- alignment constraint @x@ is fulfilled by any address divisible + -- by @x@. The value of the argument is not used. - -- replacement for read-/write???OffAddr peekElemOff :: Ptr a -> Int -> IO a + -- ^ Read a value from a memory area regarded as an array + -- of values of the same kind. The first argument specifies + -- the start address of the array and the second the index into + -- the array (the first element of the array has index + -- @0@). The following equality holds, + -- + -- > peekElemOff addr idx = IOExts.fixIO $ \result -> + -- > peek (addr \`plusPtr\` (idx * sizeOf result)) + -- + -- Note that this is only a specification, not + -- necessarily the concrete implementation of the + -- function. + pokeElemOff :: Ptr a -> Int -> a -> IO () + -- ^ Write a value to a memory area regarded as an array of + -- values of the same kind. The following equality holds: + -- + -- > pokeElemOff addr idx x = + -- > poke (addr \`plusPtr\` (idx * sizeOf x)) x - -- the same with *byte* offsets peekByteOff :: Ptr b -> Int -> IO a - pokeByteOff :: Ptr b -> Int -> a -> IO () + -- ^ Read a value from a memory location given by a base + -- address and offset. The following equality holds: + -- + -- > peekByteOff addr off = peek (addr \`plusPtr\` off) - -- ... and with no offsets at all + pokeByteOff :: Ptr b -> Int -> a -> IO () + -- ^ Write a value to a memory location given by a base + -- address and offset. The following equality holds: + -- + -- > pokeByteOff addr off x = poke (addr \`plusPtr\` off) x + peek :: Ptr a -> IO a - poke :: Ptr a -> a -> IO () + -- ^ Read a value from the given memory location. + -- + -- Note that the peek and poke functions might require properly + -- aligned addresses to function correctly. This is architecture + -- dependent; thus, portable code should ensure that when peeking or + -- poking values of some type @a@, the alignment + -- constraint for @a@, as given by the function + -- 'alignment' is fulfilled. + poke :: Ptr a -> a -> IO () + -- ^ Write the given value to the given memory location. Alignment + -- restrictions might apply; see 'peek'. + -- circular default instances peekElemOff = peekElemOff_ undefined where peekElemOff_ :: a -> Ptr a -> Int -> IO a