@@ -19,18 +19,13 @@ module Streamly.Internal.Data.Serialize.TH
20--------------------------------------------------------------------------------
20--------------------------------------------------------------------------------
22−import Data.Char (ord)
23import Data.List (foldl')
22import Data.List (foldl')
24import Data.Word (Word16, Word32, Word64, Word8)
23import Data.Word (Word16, Word32, Word64, Word8)
25−import Data.Bits (Bits, (.|.), shiftL, zeroBits, xor)
26−import Streamly.Internal.System.IO (unsafeInlineIO)
28import Language.Haskell.TH
25import Language.Haskell.TH
29import Language.Haskell.TH.Syntax
26import Language.Haskell.TH.Syntax
30import Streamly.Internal.Data.Serialize.Type
27import Streamly.Internal.Data.Serialize.Type
32−import qualified Streamly.Internal.Data.Unbox as Unbox
34import Streamly.Internal.Data.Unbox.TH
29import Streamly.Internal.Data.Unbox.TH
35 ( DataCon(..)
30 ( DataCon(..)
36 , DataType(..)
31 , DataType(..)
@@ -38,130 +33,12 @@ import Streamly.Internal.Data.Unbox.TH
38 , plainInstanceD
33 , plainInstanceD
39 , reifyDataType
34 , reifyDataType
41−
36+import Streamly.Internal.Data.Serialize.TH.Bottom
42−--------------------------------------------------------------------------------
44−--------------------------------------------------------------------------------
46−-- | Config to control how the 'Serialize' instance is generated.
49− { unconstrained :: [String]
50− -- ^ Type variables that should not have the 'Serialize' constraint.
53− -- data CustomDataType a b c d = CustomDataType a c
57− -- conf = defaultConf {unconstrained = ["b", "d"]}
58− -- \$(deriveSerializeWith conf ''CustomDataType)
62− -- instance (Serialize a, Serialize c) => Serialize (CustomDataType a b c d) where
65− , specializations :: [(String, Type)]
66− -- ^ Specialize the type variable with the given type. All type
67− -- variables listed here will not have the 'Serialize' constriant as
68− -- they are specialized.
71− -- data CustomDataType f a = CustomDataType (f a)
75− -- conf = defaultConf {specializations = [("f", ''Identity)]}
76− -- \$(deriveSerializeWith conf ''CustomDataType)
80− -- instance (Serialize a) => Serialize (CustomDataType Identity a) where
84− -- @f@ is replaced with 'Identity' and becomes unconstrained.
85− , inlineSize :: Inline
86− -- ^ Inline value for 'size'. Default is Inline.
87− , inlineSerialize :: Inline
88− -- ^ Inline value for 'serialize'. Default is Inline.
89− , inlineDeserialize :: Inline
90− -- ^ Inline value for 'deserialize'. Default is Inline.
91− , constructorTagAsString :: Bool
92− -- ^ __Experimental__
94− -- If True, encode constructors using the constructor names as Latin-1
96− , recordSyntaxWithHeader :: Bool
97− -- ^ __Experimental__
99− -- If True, encode the keys of the record as a header and then
100− -- serialize the data.
103−defaultConfig :: Config
106− { unconstrained = []
107− , specializations = []
108− , inlineSize = Inline
109− , inlineSerialize = Inline
110− , inlineDeserialize = Inline
111− , constructorTagAsString = False
112− , recordSyntaxWithHeader = False
115−--------------------------------------------------------------------------------
117−--------------------------------------------------------------------------------
119−type Field = (Maybe Name, Type)
133−_initialOffset :: Name
134−_initialOffset = mkName "initialOffset"
137−_endOffset = mkName "endOffset"
142−mkFieldName :: Int -> Name
143−mkFieldName i = mkName ("field" ++ show i)
146−makeI i = mkName $ "i" ++ show i
149−makeN i = mkName $ "n" ++ show i
152−makeA i = mkName $ "a" ++ show i
154--------------------------------------------------------------------------------
38--------------------------------------------------------------------------------
155-- Domain specific helpers
39-- Domain specific helpers
156--------------------------------------------------------------------------------
40--------------------------------------------------------------------------------
158−matchConstructor :: Name -> Int -> Q Exp -> Q Match
159−matchConstructor cname numFields exp0 =
161− (conP cname (map varP (map mkFieldName [0 .. (numFields - 1)])))
165exprGetSize :: Q Exp -> (Int, Type) -> Q Exp
42exprGetSize :: Q Exp -> (Int, Type) -> Q Exp
166exprGetSize acc (i, _) = [|size $(acc) $(varE (mkFieldName i))|]
43exprGetSize acc (i, _) = [|size $(acc) $(varE (mkFieldName i))|]
@@ -183,182 +60,10 @@ getTagType numConstructors
183 | fromIntegral (maxBound :: Word64) >= numConstructors = ''Word64
60 | fromIntegral (maxBound :: Word64) >= numConstructors = ''Word64
184 | otherwise = error "Too many constructors"
61 | otherwise = error "Too many constructors"
186−--------------------------------------------------------------------------------
188−--------------------------------------------------------------------------------
191− SimpleDataCon Name [Field]
194−simplifyDataCon :: DataCon -> SimpleDataCon
195−simplifyDataCon (DataCon cname _ _ fields) = SimpleDataCon cname fields
198− = UnitType Name -- 1 constructor and 1 field
199− | TheType SimpleDataCon -- 1 constructor and 1+ fields
200− | MultiType [SimpleDataCon] -- 1+ constructors
203−typeOfType :: Type -> [DataCon] -> TypeOfType
204−typeOfType headTy [] =
206− ("Attempting to get size with no constructors (" ++
207− (pprint headTy) ++ ")")
208−typeOfType _ [DataCon cname _ _ []] = UnitType cname
209−typeOfType _ [con@(DataCon _ _ _ _)] = TheType $ simplifyDataCon con
210−typeOfType _ cons = MultiType $ map simplifyDataCon cons
212−isUnitType :: [DataCon] -> Bool
213−isUnitType [DataCon _ _ _ []] = True
216−--------------------------------------------------------------------------------
218−--------------------------------------------------------------------------------
221−int_w8 :: Int -> Word8
222−int_w8 = fromIntegral
225−w8_w16 :: Word8 -> Word16
226−w8_w16 = fromIntegral
228−w8_w32 :: Word8 -> Word32
229−w8_w32 = fromIntegral
231−w8_w64 :: Word8 -> Word64
232−w8_w64 = fromIntegral
235−w32_int :: Word32 -> Int
236−w32_int = fromIntegral
240−c2w = fromIntegral . ord
242−shiftAdd :: Bits a => (b -> a) -> [b] -> a
244− foldl' (.|.) zeroBits $
245− map (\(j, x) -> shiftL x (j * 8)) $ zip [0 ..] $ map conv xs
247−-- Note: This only works in little endian machines
249−-- Instead of generating this via TH can't we write it directly in Haskell and
250−-- use that? Creating one comparison function for each deserialization may be
251−-- too much code and may not be necessary.
252−-- Benchmark both the implementations and check.
253−xorCmp :: [Word8] -> Name -> Name -> Q Exp
256− x | x < 2 -> [|$(go8 0) == zeroBits|]
257− x | x < 4 -> [|$(go16 0) == zeroBits|]
258− x | x < 8 -> [|$(go32 0) == zeroBits|]
259− _ -> [|$(go64 0) == zeroBits|]
262− go8 i | i >= tagLen = [|zeroBits|]
264− let wIntegral = litIntegral i
265− [|xor (unsafeInlineIO
266− (Unbox.peekByteIndex
267− ($(varE off) + $(litIntegral i))
269− ($(wIntegral) :: Word8) .|.
272− | i >= tagLen = [|zeroBits|]
274− | tagLen - i < 2 = go16 (tagLen - 2)
278− (shiftAdd w8_w16 [tag !! i, tag !! (i + 1)] :: Word16)
279− [|xor (unsafeInlineIO
280− (Unbox.peekByteIndex
281− ($(varE off) + $(litIntegral i))
283− ($(wIntegral) :: Word16) .|.
286− | i >= tagLen = [|zeroBits|]
288− | tagLen - i < 4 = go32 (tagLen - 4)
299− [|xor (unsafeInlineIO
300− (Unbox.peekByteIndex
301− ($(varE off) + $(litIntegral i))
303− ($(wIntegral) :: Word32) .|.
306− | i >= tagLen = [|zeroBits|]
308− | tagLen - i < 8 = go64 (tagLen - 8)
323− [|xor (unsafeInlineIO
324− (Unbox.peekByteIndex
325− ($(varE off) + $(litIntegral i))
327− ($(wIntegral) :: Word64) .|.
330−--------------------------------------------------------------------------------
331−-- Primitive serialization
332−--------------------------------------------------------------------------------
335−-- Will this be too much of a code bloat?
336−-- Loop with the loop body unrolled?
337−-- Serialize this in batches similar to batch comparision in xorCmp?
338−serializeW8List :: Name -> Name -> [Word8] -> Q Exp
339−serializeW8List off arr w8List = do
340− [|let $(varP (makeN 0)) = $(varE off)
341− in $(doE (fmap makeBind [0 .. (lenW8List - 1)] ++
342− [noBindS ([|pure $(varE (makeN lenW8List))|])]))|]
346− lenW8List = length w8List
349− (varP (makeN (i + 1)))
350− [|$(varE 'serialize)
353− ($(litIntegral (w8List !! i)) :: Word8)|]
355--------------------------------------------------------------------------------
63--------------------------------------------------------------------------------
357--------------------------------------------------------------------------------
65--------------------------------------------------------------------------------
359−litIntegral :: Integral a => a -> Q Exp
360−litIntegral = litE . IntegerL . fromIntegral
362getNameBaseLen :: Name -> Word8
67getNameBaseLen :: Name -> Word8
363getNameBaseLen cname =
68getNameBaseLen cname =
364 let x = length (nameBase cname)
69 let x = length (nameBase cname)