{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-- | Types to avoid source destination confusion while copying.
module Raaz.Core.Types.Copying
       (
         -- * Copying.
         -- $copyconvention$
         Src(..), Dest(..), source, destination
       ) where

import Foreign.Storable ( Storable )

-- $copyconvention$
--
-- Consider a copy operation that involves copying data between two
-- entities of the same type. If the source and target is confused
-- this can lead to bugs. The types `Src` and `Dest` helps in avoiding
-- this confusion. The convention that we follow is that copy function
-- mark its destination and source explicitly at the type level. The
-- actual constructors for the type `Src` and `Dest` are not available
-- to users of the library. Instead they use the smart constructors
-- `source` and `destination` when passing arguments to these
-- functions.
--
-- The developers of the raaz library do have access to the
-- constructors. However, it is unlikely one would need it. Since both
-- `Src` and `Dest` derive the underlying `Storable` instance, one can
-- mark `Src` and `Dest` in calls to `FFI` functions as well.


-- | The source of a copy operation.
newtype Src  a = Src { unSrc :: a } deriving Storable

-- | smart constructor for source
source :: a -> Src a
source = Src

instance Functor Src where
  fmap f = Src . f . unSrc

-- | The destination of a copy operation.
--
-- Note to Developers of Raaz: Since the `Dest` type inherits the
-- Storable instance of the base type, one can use this type in
-- foreign functions.
newtype Dest a = Dest { unDest :: a } deriving Storable

-- | smart constructor for destionation.
destination :: a -> Dest a
destination = Dest

instance Functor Dest where
  fmap f = Dest . f . unDest