{-# LANGUAGE ScopedTypeVariables #-}
module Foreign.Storable.Asymmetric
where
  
import Foreign.Storable
import Foreign.Ptr
import Control.Applicative

-- | Used as a placeholder for no data.
data NoData = NoData

instance Storable NoData where
  sizeOf _ = 0
  alignment _ = 1
  peek _ = return NoData
  poke _ _ = return ()

-- | A data structure where peek reads one structure, and poke writes another.
data DifferentPeekPoke a b = PeekOut b | PokeIn a

-- | Retrieves the 'peek' structure from a DifferentPeekPoke.
getPeek (PeekOut b) = b
getPeek (PokeIn a) = error "Attempt to call getPeek on poke input"

instance (Storable a, Storable b) => Storable (DifferentPeekPoke a b) where
  sizeOf _ = max (sizeOf (undefined :: a)) (sizeOf (undefined :: b))
  alignment _ = max (alignment (undefined :: a)) (alignment (undefined :: b))
  peek ptr = liftA PeekOut $ peek (castPtr ptr)
  poke ptr (PokeIn a) = poke (castPtr ptr) a
  poke ptr (PeekOut b) = poke (castPtr ptr) b