@@ -17,6 +17,7 @@ module Streamly.Internal.Data.Serialize.TH
1717-- Imports
1818--------------------------------------------------------------------------------
1919
20+import Data.List (foldl')
2021import Data.Word (Word16, Word32, Word64, Word8)
2122
2223import Language.Haskell.TH
@@ -40,6 +41,9 @@ type Field = (Maybe Name, Type)
4041_x :: Name
4142_x = mkName "x"
4243
44+_acc :: Name
45+_acc = mkName "acc"
46+
4347_arr :: Name
4448_arr = mkName "arr"
4549
@@ -72,22 +76,10 @@ matchConstructor cname numFields exp0 =
7276 (normalB exp0)
7377 []
7478
75−exprGetSize :: Int -> Type -> Q Exp
76−exprGetSize i ty =
77− caseE
78− (sigE (varE 'size) (appT (conT ''Size) (pure ty)))
79− [ match
80− (conP 'VarSize [varP _f])
81− (normalB (appE (varE _f) (varE (mkFieldName i))))
82− []
83− , match (conP 'ConstSize [varP _sz]) (normalB (varE _sz)) []
84− ]
85−
86− where
87−
88− _f = mkName $ "f"
89− _sz = mkName $ "sz"
90−
79+exprGetSize :: Q Exp -> (Int, Type) -> Q Exp
80+exprGetSize acc (i, ty) =
81+ [|case size :: Size $(pure ty) of
82+ Size f -> f $(acc) $(varE (mkFieldName i))|]
9183
9284getTagSize :: Int -> Int
9385getTagSize numConstructors
@@ -123,16 +115,23 @@ mkSizeOfExpr headTy constructors =
123115 ("Attempting to get size with no constructors (" ++
124116 $(lift (pprint headTy)) ++ ")")|]
125117 -- One constructor with no fields is a unit type. Size of a unit type is
126− -- 1.
118+ -- 1. XXX Use isUnitType?
127119 [constructor@(DataCon _ _ _ fields)] ->
128120 case fields of
129− [] -> appE (conE 'ConstSize) (litE (IntegerL 1))
121+ -- Unit type
122+ [] ->
123+ appE
124+ (conE 'Size)
125+ (lamE [varP _acc, wildP] [| $(varE _acc) + 1 |])
126+ -- Product type
130127 _ ->
131128 appE
132− (conE 'VarSize)
129+ (conE 'Size)
133130 (lamE
134− [varP _x]
135− (caseE (varE _x) [matchCons constructor]))
131+ [varP _acc, varP _x]
132+ (caseE (varE _x)
133+ [matchCons (varE _acc) constructor]))
134+ -- Sum type
136135 _ -> sizeOfHeadDt
137136
138137 where
@@ -140,22 +139,30 @@ mkSizeOfExpr headTy constructors =
140139 tagSizeExp =
141140 litE (IntegerL (fromIntegral (getTagSize (length constructors))))
142141
143− sizeOfField (i, (_, ty)) = exprGetSize i ty
144−
145− sizeOfFields fields =
146− appE (varE 'sum) (listE (map sizeOfField (zip [0..] fields)))
147−
148− matchCons (DataCon cname _ _ fields) =
149− matchConstructor cname (length fields) (sizeOfFields fields)
142+ -- XXX fields of the same type can be folded together, will reduce the code
143+ -- size when there are many fields of the same type.
144+ -- XXX const size fields can be calculated statically.
145+ -- XXX This can result in large compilation times due to nesting when there
146+ -- are many constructors. We can create a list and sum the list at run time
147+ -- to avoid that depending on the number of constructors. Or using a let
148+ -- statement for each case may help?
149+ -- appE (varE 'sum) (listE (acc : map (exprGetSize (litE (IntegerL 0))) (zip [0..] fields)))
150+ sizeOfFields acc fields =
151+ foldl' exprGetSize acc $ zip [0..] fields
152+
153+ matchCons acc (DataCon cname _ _ fields) =
154+ let expr = sizeOfFields acc (map snd fields)
155+ in matchConstructor cname (length fields) expr
150156
151157 -- XXX We fix VarSize for simplicity. Should be changed later.
152158 sizeOfHeadDt =
153− appE
154− (conE 'VarSize)
155− (lamE
156− [varP _x]
157− [|$(tagSizeExp)
158− + $(caseE (varE _x) (fmap matchCons constructors))|])
159+ let acc = [|$(varE _acc) + $(tagSizeExp)|]
160+ f =
161+ (lamE
162+ [varP _acc, varP _x]
163+ (caseE (varE _x) (fmap (matchCons acc) constructors))
164+ )
165+ in appE (conE 'Size) f
159166
160167--------------------------------------------------------------------------------
161168-- Peek
@@ -328,7 +335,7 @@ deriveSerializeInternal preds headTy cons = do
328335 let methods =
329336 -- INLINE on sizeOf actually worsens some benchmarks, and improves
330337 -- none
331− [ -- PragmaD (InlineP 'size Inline FunLike AllPhases)
338+ [ -- PragmaD (InlineP 'size Inlinable FunLike AllPhases)
332339 FunD 'size [Clause [] (NormalB sizeOfMethod) []]
333340 , PragmaD (InlineP 'deserialize Inline FunLike AllPhases)
334341 , FunD