packages feed

fudgets-0.18.3: hsrc/ghc-dialogue/Marshall.hs

module Marshall where
import MyForeign
import Control.Monad(zipWithM_)
--import Ap

class HasAddr a where
   addrOf :: a -> Addr
   --atAddr :: Addr -> a

freePtr p = free (addrOf p)

class HasAddr a => IsPtr a where
   nullPtr :: a
   newPtr :: IO a
   newArray :: Int -> IO a

   newPtr = newArray 1

class (Storable h, HasAddr c) => CVar c h | c -> h where
  readCVar :: c -> IO h
  writeCVar :: c -> h -> IO ()
  indexCVar :: c -> Int -> IO h
  writeArray :: c -> [h] -> IO ()
  readArray :: c -> Int -> IO [h]

  readCVar = peek . addrOf
  writeCVar = poke . addrOf
  indexCVar = peekElemOff . addrOf
  writeArray arr = zipWithM_ (pokeElemOff (addrOf arr)) [0..]
  readArray arr n = mapM (indexCVar arr) [0..(n-1)]

toArray xs =
  do let n = length xs
     a <- newArray n
     writeArray a xs
     return (a,n)

{-
instance (Storable a,Storable b) => (Storable (a,b)) where
  sizeOf (a,b) = sizeOf a+sizeOf b
  alignment (a,b) = max (alignment a) (alignment b)
  poke p (a,b) = poke p a >> poke (p `plusAddr` sizeOf a) b
  peek p = do a <- peek p
	      b <- peek (p `plusAddr` sizeOf a) p
	      return (a,b)
-}

-------------------
class PrimArg ha pa r | ha->pa where
  --marshall :: haskell -> IO (prim,IO ())
  marshall :: (pa->r)->ha->r

-- marshallM x = marshall return x -- GHC generates buggy code, it seems

instance PrimArg Int Int c where marshall = id
instance PrimArg Int32 Int32 c where marshall = id
--instance PrimArg Char Char c where marshall = id
instance PrimArg Bool Bool c where marshall = id
--instance PrimArg () Int c where marshall f () = f 0
instance PrimArg Addr Addr c where marshall = id
instance PrimArg CLong CLong c where marshall = id
instance PrimArg CInt32 CInt32 c where marshall = id
instance PrimArg CString CString c where marshall = id

class    Bind f                where bind :: IO o->(o->f)->f
				     thn :: f->IO ()-> f
instance Bind (IO a)           where bind = (>>=)
				     thn f io = do r<-f;io;return r
instance Bind f => Bind (a->f) where bind ioo oaf = bind ioo . flip oaf
				     thn f io a = f a `thn` io

instance Bind f => PrimArg String CString f where
  marshall f str =
     marshallString str `bind` \ cstr ->
     f cstr `thn`
     freePtr cstr

class PrimResult prim haskell where
  unmarshall :: prim -> haskell

instance PrimResult () () where unmarshall = id
instance PrimResult Bool Bool where unmarshall = id
instance PrimResult Char Char where unmarshall = id
instance PrimResult Int Int where unmarshall = id
instance PrimResult Int32 Int32 where unmarshall = id

--instance PrimResult Int (IO Int) where unmarshall = return

instance PrimResult (IO ()) (IO ()) where unmarshall = id
instance PrimResult (IO Int) (IO Int) where unmarshall = id
instance PrimResult (IO Int32) (IO Int32) where unmarshall = id
instance PrimResult (IO Bool) (IO Bool) where unmarshall = id
instance PrimResult (IO CString) (IO CString) where unmarshall = id

unmarshallM m = unmarshall =<< m
unmarshallArray a n = mapM unmarshall =<< readArray a n

instance PrimResult (IO CString) (IO (Maybe String)) where
  unmarshall addrIO =
    do cstr <- addrIO
       if addrOf cstr==nullAddr
        then return Nothing
        else Just <$> unmarshall cstr

instance PrimResult CString (IO String) where unmarshall = unmarshallString
instance PrimResult (IO CString) (IO String) where unmarshall = unmarshallM

instance (PrimArg ha pa pb,PrimResult pb hb) => PrimResult (pa->pb) (ha->hb) where
    -- have: marshall      :: (pa->pb)->(ha->pb)
    -- have: unmarshall    :: pb->hb
    -- produce: unmarshall :: (pa->pb)->(ha->hb)
    unmarshall papb ha = unmarshall (marshall papb ha)

--- Primitive marshalling

newtype CString = CString Addr deriving (Eq)
instance HasAddr CString where addrOf (CString a) = a --; atAddr = CString
instance CVar CString CString
instance Storable CString where
  sizeOf (CString a) = sizeOf a
  alignment (CString a) = alignment a
  peek p = CString <$> peek p
  poke p (CString a) = poke p a

nullStr = CString nullAddr

marshallString :: String -> IO CString
marshallString s = marshallString' s (length s)

marshallString' :: String -> Int -> IO CString
marshallString' s n = 
  do a <- mallocElems (head s) (n+1)
     zipWithM_ (pokeElemOff a) [0..n-1] s
     pokeElemOff a n '\0'
     return (CString a)


unmarshallString :: CString -> IO String
unmarshallString (CString addr) = get 0
  where 
    get i =
      do c <- peekElemOff addr i
	 if c=='\0'
	  then return []
	  else (c:) <$> get (i+1)
              
unmarshallString' :: CString -> Int -> IO String
unmarshallString' (CString addr) n = get 0
  where
    get i =
      if i<n
      then (:) <$> peekElemOff addr i <*> get (i+1)
      else return []
     

---

-- | Pointer to long int (same size as pointers, 64 bits on 64-bit systems)
newtype CLong = CLong Addr
newtype CXID = CXID Addr

instance HasAddr CLong where addrOf (CLong a) = a --;atAddr = CLong
instance HasAddr CXID where addrOf (CXID a) = a --;atAddr = CLong

instance IsPtr CLong where
  nullPtr = CLong nullAddr
  newPtr = CLong <$> mallocElem (0::Int)
  newArray n = CLong <$> mallocElems (0::Int) n

instance IsPtr CXID where
  nullPtr = CXID nullAddr
  newPtr = CXID <$> mallocElem (0::Int)
  newArray n = CXID <$> mallocElems (0::Int) n

instance CVar CLong Int

-- | Pointer to C int (32 bits even on 64-bit system)
newtype CInt32 = CInt32 Addr

instance HasAddr CInt32 where addrOf (CInt32 a) = a --;atAddr = CInt

instance IsPtr CInt32 where
  nullPtr = CInt32 nullAddr
  newPtr = CInt32 <$> mallocElem (0::Int32)
  newArray n = CInt32 <$> mallocElems (0::Int32) n

instance CVar CInt32 Int32