--
-- This file contains a multiparameter class with functional dependencies
-- to be used by every module generated by HSFFIG. This class contains
-- combinators to access members of C structures. Every type corresponding
-- to a C structure type will be an instance of this class.
--

{-# OPTIONS -fglasgow-exts -XForeignFunctionInterface #-}

module HSFFIG.FieldAccess (
  FieldAccess (..)
) where

import Foreign
import Foreign.C.Types

-- |A multi-parameter class with functional dependencies is declared to enable access 
-- to structures\/unions members. The functional dependencies @a b c | a c -> b@ specify 
-- that type of /b/ (type of the member) depends entirely on the types /a/ (phantom type
-- identifying structure\/union) and /c/ (phantom type identifying the member, a.k.a. member 
-- selector), and there may be only one type of /b/ for every possible combination of /a/ and /c/.
--
-- Indeed:
--
-- @
-- struct a {
--   int x;
-- };
-- struct b {
--   float x;
-- };
-- @
--
-- both structures contain a member with the same name, but different types.
-- 
-- HSFFIG will generate the following instances for the structures above:
--
-- @
-- instance HSFFIG.FieldAccess.FieldAccess S_a ((CInt)) V_x where
--   z --> V_x = (#peek __quote__(struct a), x) z
--   (z, V_x) <-- v = (#poke __quote__(struct a), x) z v
-- ...
-- instance HSFFIG.FieldAccess.FieldAccess S_b ((CFloat)) V_x where
--  z --> V_x = (#peek __quote__(struct b), x) z
--  (z, V_x) <-- v = (#poke __quote__(struct b), x) z v
-- @
--
-- That is, when the member identified by selector @V_x@ is fetched from 
-- @struct a@ (@S_a@), an integer value is returned. But when the member with
-- the same name is retrieved from @struct b@, a float value is returned.

class FieldAccess a b c | a c -> b where
  (==>) :: Ptr a -> c -> b    -- ^retrieves a function reference from a member of structure @a@
                              --  with name selector @c@ of type @b@ which in this case
                              --  is a function type (thus '==>' is called in non-monadic
                              --  context). Selector for @c@ may only be @X_@-prefixed.
  (-->) :: Ptr a -> c -> IO b -- ^retrieves a value (mutable, thus monadic context is required) 
                              --  from a member of structure @a@ with
                              --  name selector @c@ of type @b@. Selector for @c@ may only be
                              --  @V_@-prefixed.
  (<--) :: (Ptr a, c) -> b -> IO () -- ^destructively updates a member of structure @a@
                                    --  with name selector @c@ with value of type @b@.
                                    --  Selector for @c@ may only be @V_@-prefixed.
  (==>) _ _ = error " illegal context for ==>"
  (-->) _ _ = error " illegal context for -->"
  (<--) _ _ = error " illegal context for <--"