module Data.Packed.TH.Unpackable (genUnpackableInstance) where

import Data.Packed.TH.Flag (PackingFlag)
import Data.Packed.TH.Read
import Data.Packed.TH.Utils (resolveAppliedType)
import Data.Packed.Unpackable
import Language.Haskell.TH

-- | Generates an instance of 'Unpackable' for the given type
--
-- All the parameters of each constructor should be instances of 'Unpackable'
--
-- Note: The unpack function simply calls the function generated by 'genRead'
--
--
-- __Example__
--
-- For the 'Tree' data type, it generates the following instance:
--
-- @
-- instance ('Unpackable' a) => 'Unpackable' (Tree a) where
--    reader = readTree
-- @
genUnpackableInstance :: [PackingFlag] -> Name -> Q [Dec]
genUnpackableInstance :: [PackingFlag] -> Name -> Q [Dec]
genUnpackableInstance [PackingFlag]
flags Name
tyName = do
    (resolvedType, typeParameterNames) <- Name -> Q (Type, [Name])
resolveAppliedType Name
tyName
    constraints <- mapM (\Name
t -> [t|Unpackable $(Name -> Q Type
forall (m :: * -> *). Quote m => Name -> m Type
varT Name
t)|]) typeParameterNames
    instanceType <- [t|Unpackable $(return resolvedType)|]
    readerD <- genRead flags tyName
    readerMethod <- funD 'reader [clause [] (normalB [|$(varE $ readFName tyName)|]) []]
    return $
        readerD
            ++ [ InstanceD
                    (Just Overlapping)
                    constraints
                    instanceType
                    [readerMethod]
               ]