@@ -9,8 +9,17 @@
99-- Portability : GHC
1010--
1111module Streamly.Internal.Data.Serialize.TH.Bottom
12− ( Config(..)
12+ (
13+ -- ** Config
14+ Config(..)
1315 , defaultConfig
16+ , inlineSize
17+ , inlineSerialize
18+ , inlineDeserialize
19+ , encodeConstrNames
20+ , encodeRecordFields
21+
22+ -- ** Other Utilities
1423 , TypeOfType(..)
1524 , typeOfType
1625 , SimpleDataCon(..)
@@ -65,48 +74,118 @@ import Streamly.Internal.Data.Unbox.TH (DataCon(..))
6574-- Config
6675--------------------------------------------------------------------------------
6776
68−-- | Config to control how the 'Serialize' instance is generated.
77+-- XXX Need to make it (Maybe Inline) so that we can use Nothing as default.
78+
79+-- | Configuration to control how the 'Serialize' instance is generated. Use
80+-- 'defaultConfig' and config setter functions to generate desired Config. For
81+-- example:
82+--
83+-- >>> (inlineSize Inline) . (inlineSerialize Inlinable) defaultConfig
84+--
6985data Config =
7086 Config
71− { inlineSize :: Inline
72− -- ^ Inline value for 'size'. Default is Inline.
73− , inlineSerialize :: Inline
74− -- ^ Inline value for 'serialize'. Default is Inline.
75− , inlineDeserialize :: Inline
76− -- ^ Inline value for 'deserialize'. Default is Inline.
77− , constructorTagAsString :: Bool
78− -- ^ __Experimental__
79− --
80− -- If True, encode constructors using the constructor names as Latin-1
81− -- byte sequence.
82− , recordSyntaxWithHeader :: Bool
83− -- ^ __Experimental__
84− --
85− -- If True, encode the keys of the record as a header and then
86− -- serialize the data. Multiple constructors are not supported with
87− -- @recordSyntaxWithHeader@ enabled.
88− --
89− -- __Performance Notes:__
90− --
91− -- There is a constant regression proportional to
92− -- @sum (map length keyList) + length keyList@ where @keyList@ is the
93− -- list of keys of that record as strings.
94− --
95− -- As an example, @keyList@ of,
96− -- @
97− -- data RecordType = RecordType { field0 :: Int, field2 :: Char }
98− -- @
99− -- is @["field0", "field1"]@
87+ { cfgInlineSize :: Inline
88+ , cfgInlineSerialize :: Inline
89+ , cfgInlineDeserialize :: Inline
90+ , cfgConstructorTagAsString :: Bool
91+ , cfgRecordSyntaxWithHeader :: Bool
10092 }
10193
94+-- | How should we inline the 'size' function? The default in 'defaultConfig'
95+-- is 'Inline'. However, aggressive inlining can bloat the code and increase
96+-- compilation times in when there are big functions and too many nesting
97+-- levels so you can change it accordingly.
98+inlineSize :: Inline -> Config -> Config
99+inlineSize v cfg = cfg {cfgInlineSize = v}
100+
101+-- | How should we inline the 'serialize' function? See guidelines in
102+-- 'inlineSize'.
103+inlineSerialize :: Inline -> Config -> Config
104+inlineSerialize v cfg = cfg {cfgInlineSerialize = v}
105+
106+-- | How should we inline the 'deserialize' function? See guidelines in
107+-- 'inlineSize'.
108+inlineDeserialize :: Inline -> Config -> Config
109+inlineDeserialize v cfg = cfg {cfgInlineDeserialize = v}
110+
111+-- | __Experimental__
112+--
113+-- In sum types, use Latin-1 encoded original constructor names rather than
114+-- binary values to identify constructors. This option is not useful on a
115+-- product type.
116+--
117+-- This option enables the following backward compatible behavior:
118+--
119+-- * __Reordering__: Order of the fields can be changed without affecting
120+-- serialization.
121+-- * __Addition__: If a field is added in the new version, the old version of
122+-- the data type can still be deserialized by the new version. The new value
123+-- would never occur in the old one.
124+-- * __Deletion__: If a field is deleted in the new version and deserialization
125+-- of the old version will result in an error. TBD: We can possibly designate a
126+-- catch-all field to handle this case.
127+--
128+-- Note that if you change a type, change the semantics of a type, or delete a
129+-- field and add a new field with the same name, deserialization of old data
130+-- may result in silent unexpected behavior.
131+--
132+-- This option has to be the same on both encoding and decoding side.
133+-- The default is 'False'.
134+--
135+encodeConstrNames :: Bool -> Config -> Config
136+encodeConstrNames v cfg = cfg {cfgConstructorTagAsString = v}
137+
138+-- XXX We can deserialize each field to Either, so if there is a
139+-- deserialization error in any field it can handled independently. Also, a
140+-- unique type/version identifier of the field (based on the versions of the
141+-- packages, full module name space + type identifier) can be serialized along
142+-- with the value for stricter compatibility, semantics checking. Or we can
143+-- store a type hash.
144+
145+-- | __Experimental__
146+--
147+-- In explicit record types, use Latin-1 encoded record field names rather than
148+-- binary values to identify the record fields. Note that this option cannot be
149+-- used on a sum type. Also, it does not work on a product type which is not a
150+-- record, because there are no field names to begin with.
151+--
152+-- This option enables the following backward compatible behavior:
153+--
154+-- * __Reordering__: Order of the fields can be changed without affecting
155+-- serialization.
156+-- * __Addition__: If a 'Maybe' type field is added in the new version, the old
157+-- version of the data type can still be deserialized by the new version, the
158+-- field value in the older version is assumed to be 'Nothing'. If any other
159+-- type of field is added, deserialization of the older version results in an
160+-- error but only when that field is accessed in the deserialized record.
161+-- * __Deletion__: If a field is deleted in the new version and it is
162+-- encountered in a previously serialized version then the field is discarded.
163+-- TBD: We can possibly designate a catch-all field to handle this case.
164+--
165+-- This option has to be the same on both encoding and decoding side.
166+--
167+-- There is a constant performance overhead proportional to the total length of
168+-- the record field names and the number of record fields.
169+--
170+-- The default is 'False'.
171+--
172+encodeRecordFields :: Bool -> Config -> Config
173+encodeRecordFields v cfg = cfg {cfgRecordSyntaxWithHeader = v}
174+
175+-- | The default configuration settings are:
176+--
177+-- * 'inlineSize' 'Inline'
178+-- * 'inlineSerialize' 'Inline'
179+-- * 'inlineDeserialize' 'Inline'
180+--
102181defaultConfig :: Config
103182defaultConfig =
104183 Config
105− { inlineSize = Inline
106− , inlineSerialize = Inline
107− , inlineDeserialize = Inline
108− , constructorTagAsString = False
109− , recordSyntaxWithHeader = False
184+ { cfgInlineSize = Inline
185+ , cfgInlineSerialize = Inline
186+ , cfgInlineDeserialize = Inline
187+ , cfgConstructorTagAsString = False
188+ , cfgRecordSyntaxWithHeader = False
110189 }
111190
112191--------------------------------------------------------------------------------