packed-data-0.2.0.0: src/Data/Packed/TH/RepackCon.hs
module Data.Packed.TH.RepackCon (genConstructorRepackers) where
import Data.Packed.FieldSize
import Data.Packed.Needs (Needs, applyNeeds)
import qualified Data.Packed.Needs as N
import Data.Packed.Packed (Packed)
import Data.Packed.TH.Flag
import Data.Packed.TH.Start (startFName)
import Data.Packed.TH.Utils
import Language.Haskell.TH
-- | Generates a function that builds back data using already serialised fields
--
-- __Example:__
--
-- For the 'Tree' data type, it generates the following functions
--
-- @
-- repackLeaf :: 'Data.Packed.Needs' '[] a -> ('Data.Packed.Packed' '[Tree a])
-- repackLeaf pval = withEmptyNeeds (startLeaf N.>> 'Data.Packed.Needs.concatNeeds' pval)
--
-- repackNode :: 'Data.Packed.Needs' '[] (Tree a) -> 'Data.Packed.Needs' '[] (Tree a) -> ('Data.Packed.Packed '[Tree a])
-- repackNode lval rval needs = N.runBuilder (startNode needs N.>>= 'Data.Packed.Needs.concatNeeds' lval N.>>= 'concatNeeds' rval)
-- @
genConstructorRepackers :: [PackingFlag] -> Name -> Q [Dec]
genConstructorRepackers flags tyName = do
(TyConI (DataD _ _ _ _ cs _)) <- reify tyName
packers <- genConstructorRepacker flags `mapM` cs
return $ concat packers
repackConFName :: Name -> Name
repackConFName conName = mkName $ "repack" ++ sanitizeConName conName
genConstructorRepacker :: [PackingFlag] -> Con -> Q [Dec]
genConstructorRepacker flags con = do
let conName = fst $ getNameAndBangTypesFromCon con
fieldTypes = getConFieldsIdxAndNeedsFS con flags
needsName = mkName "needs"
varNames <- mapM (\_ -> newName "t") fieldTypes
writeExp <-
let concated =
foldl
( \rest ((_, _, needsFieldSize), varName) ->
if needsFieldSize
then [|($rest) N.>>= applyNeedsWithFieldSize $(varE varName)|]
else [|($rest) N.>>= applyNeeds $(varE varName)|]
)
[|$(varE $ startFName conName) $(varE needsName)|]
(zip fieldTypes varNames)
in [|N.runBuilder $ \($(varP needsName)) -> $concated|]
signature <- genConstructorPackerSig flags conName ((\(t, _, _) -> t) <$> fieldTypes)
return
[ signature
, FunD (repackConFName conName) [Clause (VarP <$> varNames) (NormalB writeExp) []]
]
genConstructorPackerSig :: [PackingFlag] -> Name -> [Type] -> Q Dec
genConstructorPackerSig _ conName argTypes = do
(DataConI _ _ tyName) <- reify conName
(ty, _) <- resolveAppliedType tyName
signature <- foldr (\p rest -> [t|Needs '[] '[$(return p)] -> $rest|]) [t|Packed '[$(return ty)]|] argTypes
return $ SigD (repackConFName conName) $ ForallT [] [] signature