-- (c) The FFI task force, [2000..2001]
--
-- Basic marshalling support for elementary types

module Storable (
  Storable(
    sizeOf,         -- :: a -> Int
    alignment,      -- :: a -> Int
    peekElemOff,    -- :: Ptr a -> Int      -> IO a
    pokeElemOff,    -- :: Ptr a -> Int -> a -> IO ()
    peekByteOff,    -- :: Ptr b -> Int      -> IO a
    pokeByteOff,    -- :: Ptr b -> Int -> a -> IO ()
    peek,           -- :: Ptr a             -> IO a
    poke)           -- :: Ptr a        -> a -> IO ()
) where

import Int        (Int8, Int16, Int32, Int64)
import Word       (Word8, Word16, Word32, Word64)
import Ptr        (Ptr, plusPtr)
import StablePtr  (StablePtr)
import CTypes
import CTypesISO

class Storable a where

   -- Yields the storage requirements (in bytes) of the argument
   --
   --  * Never uses its argument
   --
   sizeOf      :: a -> Int

   -- Yields the alignment constraint of the argument
   --
   --  * An alignment constraint "x" is fulfilled by any address divisible by
   --   "x" 
   --
   --  * Never uses its argument
   --
   alignment   :: a -> Int

   -- Read/write elements from an array of elements of the given type
   --
   peekElemOff :: Ptr a -> Int      -> IO a
   pokeElemOff :: Ptr a -> Int -> a -> IO ()

   -- The same with *byte* offsets
   --
   peekByteOff :: Ptr b -> Int      -> IO a
   pokeByteOff :: Ptr b -> Int -> a -> IO ()

   -- ... and with no offsets at all
   --
   peek        :: Ptr a      -> IO a
   poke        :: Ptr a -> a -> IO ()

   -- circular default instances
   peekElemOff = peekElemOff_ undefined
      where peekElemOff_ :: a -> Ptr a -> Int -> IO a
            peekElemOff_ undef ptr off = peekByteOff ptr (off * sizeOf undef)
   pokeElemOff ptr off val = pokeByteOff ptr (off * sizeOf val) val

   peekByteOff ptr off = peek (ptr `plusPtr` off)
   pokeByteOff ptr off = poke (ptr `plusPtr` off)

   peek ptr = peekElemOff ptr 0
   poke ptr = pokeElemOff ptr 0

-- Note that the various `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.

-- system-dependent instances

instance Storable Char          where ...
instance Storable Bool          where ...
instance Storable Int           where ...
instance Storable Float         where ...
instance Storable Double        where ...
instance Storable Word8         where ...
instance Storable Word16        where ...
instance Storable Word32        where ...
instance Storable Word64        where ...
instance Storable Int8          where ...
instance Storable Int16         where ...
instance Storable Int32         where ...
instance Storable Int64         where ...
instance Storable (Ptr a)       where ...
instance Storable (FunPtr a)    where ...
instance Storable (StablePtr a) where ...

instance Storable CChar      where ...
instance Storable CSChar     where ...
instance Storable CUChar     where ...
instance Storable CShort     where ...
instance Storable CUShort    where ...
instance Storable CInt       where ...
instance Storable CUInt      where ...
instance Storable CLong      where ...
instance Storable CULong     where ...
instance Storable CLLong     where ...
instance Storable CULLong    where ...
instance Storable CPtrdiff   where ...
instance Storable CSize      where ...
instance Storable CWchar     where ...
instance Storable CSigAtomic where ...
instance Storable CClock     where ...
instance Storable CTime      where ...
