on master help sign in
Add the crux of the algorithm used in recordSyntaxWithHeader
2f2101eAdithya Kumar
core/src/Streamly/Internal/Data/Serialize/TH/RecHeader.hs+49−5
@@ -39,9 +39,49 @@ import Streamly.Internal.Data.Serialize.TH.Common
39-- Notes
39-- Notes
40--------------------------------------------------------------------------------
40--------------------------------------------------------------------------------
41
41
42−-- Encoding the header length is required to check if we want to compare the
42+-- Compatibility Algorithm
43−-- header. We should not compare the headers if the lengths of the headers are
43+-- =======================
44−-- not equal as this might lead to a runtime error.
44+--
45+-- The algorithm is written without any low level implementation details. See
46+-- the code for any low level implementation details.
47+--
48+-- Serialization:
49+-- --------------
50+--
51+-- To serialize the data,
52+--
53+-- * Get the list of keys for the record as @keyList@.
54+-- * Serialize the @keyList@.
55+-- * Serialize the @fields@ one-by-one after serializing the @keyList@.
56+--
57+-- Deserialization:
58+-- ----------------
59+--
60+-- To deserialize the data to type @T@,
61+--
62+-- __Checking for type match__:
63+--
64+-- * Get the list of keys for type @T@ as @targetKeyList@.
65+-- * Get the list of keys encoded as @encodedKeyList@.
66+-- * If @targetKeyList == encodedKeyList@ see the __Type Match__ section else
67+-- see the __No Type Match__ section.
68+--
69+-- __Type Match__:
70+--
71+-- * Decode the fields one-by-one and construct the type @T@ in the end.
72+--
73+-- __No Type Match__:
74+--
75+-- * Decode the list of keys encoded into @encodedKeyList@.
76+-- * Get the list of keys for type @T@ as @targetKeyList@.
77+-- * Loop through @encodedKeyList@ and start deserializing the encoded data.
78+-- * If the key is present in @encodedKeyList@ and not in @targetKeyList@
79+-- then skip parsing the corresponding value.
80+-- * If the key is present in @targetKeyList@ and not in @encodedKeyList@
81+-- then set the value for that key as @Nothing@.
82+-- * If the key is present in both @encodedKeyList@ and in @targetKeyList@
83+-- parse the value.
84+-- * Construct @T@ after parsing all the data.
45
85
46--------------------------------------------------------------------------------
86--------------------------------------------------------------------------------
47-- Compact lists
87-- Compact lists
@@ -170,8 +210,9 @@ headerValue (SimpleDataCon _ fields) =
170-- Peek
210-- Peek
171--------------------------------------------------------------------------------
211--------------------------------------------------------------------------------
172
212
173−-- Encoding the size is required if we want to skip the field.
213+-- Encoding the size is required if we want to skip the field without knowing
174−-- We encode the size as 'Word32' hence there is a 4 bytes increase in size.
214+-- its type. We encode the size as 'Word32' hence there is a 4 bytes increase
215+-- in size.
175{-# INLINE serializeWithSize #-}
216{-# INLINE serializeWithSize #-}
176serializeWithSize :: Serialize a => Int -> MutableByteArray -> a -> IO Int
217serializeWithSize :: Serialize a => Int -> MutableByteArray -> a -> IO Int
177serializeWithSize off arr val = do
218serializeWithSize off arr val = do
@@ -182,6 +223,9 @@ serializeWithSize off arr val = do
182mkSerializeExpr :: Name -> SimpleDataCon -> Q Exp
223mkSerializeExpr :: Name -> SimpleDataCon -> Q Exp
183mkSerializeExpr initialOffset (con@(SimpleDataCon cname fields)) = do
224mkSerializeExpr initialOffset (con@(SimpleDataCon cname fields)) = do
184 afterHLen <- newName "afterHLen"
225 afterHLen <- newName "afterHLen"
226+ -- Encoding the header length is required.
227+ -- We first compare the header length encoded and the current header
228+ -- length. Only if the header lengths match, we compare the headers.
185 [|do $(varP afterHLen) <-
229 [|do $(varP afterHLen) <-
186 serialize
230 serialize
187 ($(varE initialOffset) + 4)
231 ($(varE initialOffset) + 4)