{-# LANGUAGE CPP #-}
#ifdef SAFE_HASKELL
{-# LANGUAGE Trustworthy #-}
#endif

-----------------------------------------------------------------------------
-- |
-- Module      :  Data.SafeCopy
-- Copyright   :  PublicDomain
--
-- Maintainer  :  lemmih@gmail.com
-- Portability :  non-portable (uses GHC extensions)
--
-- SafeCopy extends the parsing and serialization capabilities of Data.Serialize
-- to include nested version control. Nested version control means that you
-- can change the definition and binary format of a type nested deep within
-- other types without problems.
--
-- Consider this scenario. You want to store your contact list on disk
-- and so write the following code:
--
-- @
--type Name     = String
--type Address  = String
--data Contacts = Contacts [(Name, Address)]
--instance SafeCopy Contacts where
--     putCopy (Contacts list) = contain $ safePut list
--     getCopy = contain $ Contacts \<$\> safeGet
-- @
--
-- At this point, everything is fine. You get the awesome speed of Data.Serialize
-- together with Haskell's ease of use. However, things quickly take a U-turn for the worse
-- when you realize that you want to keep phone numbers as well as names and
-- addresses. Being the experienced coder that you are, you see that using a 3-tuple
-- isn't very pretty and you'd rather use a record. At first you fear that this
-- change in structure will invalidate all your old data. Those fears are quickly quelled,
-- though, when you remember how nifty SafeCopy is. With renewed enthusiasm,
-- you set out and write the following code:
--
-- @
--type Name = String
--type Address = String
--type Phone = String
--
--{- We rename our old Contacts structure -}
--data Contacts_v0 = Contacts_v0 [(Name, Address)]
--instance SafeCopy Contacts_v0 where
--     putCopy (Contacts_v0 list) = contain $ safePut list
--     getCopy = contain $ Contacts_v0 \<$\> safeGet
--
--data Contact = Contact { name    :: Name
--                       , address :: Address
--                       , phone   :: Phone }
--instance SafeCopy Contact where
--    putCopy Contact{..} = contain $ do safePut name; safePut address; safePut phone
--    getCopy = contain $ Contact \<$\> safeGet \<*\> safeGet \<*\> safeGet
--
--data Contacts = Contacts [Contact]
--instance SafeCopy Contacts where
--     version = 2
--     kind = extension
--     putCopy (Contacts contacts) = contain $ safePut contacts
--     getCopy = contain $ Contacts \<$\> safeGet
--
--{- Here the magic happens: -}
--instance Migrate Contacts where
--     type MigrateFrom Contacts = Contacts_v0
--     migrate (Contacts_v0 contacts) = Contacts [ Contact{ name    = name
--                                                        , address = address
--                                                        , phone   = \"\" }
--                                               | (name, address) <- contacts ]
-- @
--
-- With this, you reflect on your code and you are happy. You feel confident in the safety of
-- your data and you know you can remove @Contacts_v0@ once you no longer wish to support
-- that legacy format.
module Data.SafeCopy
    (
      safeGet
    , safePut
    , SafeCopy(version, kind, getCopy, putCopy, objectProfile, errorTypeName)
    , SafeCopy'
    , Profile(..)
    , Prim(..)
    , Migrate(..)
    , Reverse(..)
    , Kind
    , extension
    , extended_extension
    , extended_base
    , base
    , Contained
    , contain
    , Version

      -- * Template haskell functions
    , deriveSafeCopy
    , deriveSafeCopyIndexedType
    , deriveSafeCopySimple
    , deriveSafeCopySimpleIndexedType
    , deriveSafeCopyHappstackData
    , deriveSafeCopyHappstackDataIndexedType

      -- * Rarely used functions
    , getSafeGet
    , getSafePut
    , primitive
    ) where

import Data.SafeCopy.Instances ()
import Data.SafeCopy.SafeCopy
import Data.SafeCopy.Derive