serialization: implement serialization for classes of `core::queue`
[nit.git] / lib / serialization / serialization.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Abstract services to serialize Nit objects to different formats
18 #
19 # This module declares the `serialize` annotation to mark Nit classes as serializable.
20 # For an introduction to this service, refer to the documentation of the `serialization` group.
21 # This documentation provides more technical information on interesting entitie of this module.
22 #
23 # Interesting entities for end users of serializable classes:
24 #
25 # * Serialize an instance subclass of `Serializable` with either
26 # `Serializer::serializable` and `Serializable::serialize`.
27 # * Deserialize an object using `Deserializer::deserialize`.
28 # The object type must the be checked with an `assert` or otherwise.
29 #
30 # Interesting entities to create custom serializable classes:
31 #
32 # * Subclass `Serializable` to declare a class as serializable and to customize
33 # the serialization and deserialization behavior.
34 # * Redefine `Serializable::core_serialize_to` to customize the serialization
35 # of the receiver class.
36 # * Redefine `Deserializer::deserialize_class` to customize the deserialization
37 # of a specific class by name.
38 #
39 # Interesting entities for serialization format:
40 #
41 # * Subclass `Serializer` and `Deserializer` with custom serices.
42 # * In `Serializer`, `serialize` and `serialize_reference` must be redefined.
43 # * In `Deserializer`; `deserialize`, `deserialize_attribute and
44 # `notify_of_creation` must be redefined.
45 module serialization is
46 new_annotation auto_serializable
47 new_annotation serialize
48 new_annotation noserialize
49 new_annotation serialize_as
50 end
51
52 intrude import core::queue
53 import meta
54
55 # Abstract serialization service to be sub-classed by specialized services.
56 interface Serializer
57 # Entry point method of this service, serialize the `object`
58 #
59 # This method, and refinements, should handle `null` and probably
60 # use double dispatch to customize the bahavior per serializable objects.
61 fun serialize(object: nullable Serializable) is abstract
62
63 # The object currently serialized by `serialized`
64 #
65 # Can be used by a custom serializer to add domain-specific serialization behavior.
66 protected fun current_object: nullable Object is abstract
67
68 # Serialize an object, with full serialization or a simple reference
69 protected fun serialize_reference(object: Serializable) is abstract
70
71 # Serialize an attribute to compose a serializable object
72 #
73 # This method should be called from `Serializable::core_serialize_to`.
74 fun serialize_attribute(name: String, value: nullable Object)
75 do
76 if not try_to_serialize(value) then
77 warn("argument {name} of type {value.class_name} is not serializable.")
78 end
79 end
80
81 # Serialize `value` is possie, i.e. it is `Serializable` or `null`
82 fun try_to_serialize(value: nullable Object): Bool
83 do
84 if value isa Serializable then
85 value.serialize_to_or_delay(self)
86 else if value == null then
87 serialize value
88 else return false
89 return true
90 end
91
92 # The method is called when a standard `value` is serialized
93 #
94 # The default behavior is to call `value.core_serialize_to(self)` but it
95 # can be redefined by a custom serializer to add domain-specific serialization behavior.
96 fun serialize_core(value: Serializable)
97 do
98 value.core_serialize_to(self)
99 end
100
101 # Warn of problems and potential errors (such as if an attribute
102 # is not serializable)
103 fun warn(msg: String) do print "Serialization warning: {msg}"
104 end
105
106 # Abstract deserialization service
107 #
108 # The main service is `deserialize`.
109 abstract class Deserializer
110 # Deserialize and return an object, storing errors in the attribute `errors`
111 #
112 # If a `static_type` is given, only subtypes of the `static_type` are accepted.
113 #
114 # This method behavior varies according to the implementation engines.
115 fun deserialize(static_type: nullable String): nullable Object is abstract
116
117 # Deserialize the attribute with `name` from the object open for deserialization
118 #
119 # The `static_type` restricts what kind of object can be deserialized.
120 #
121 # Return the deserialized value or null on error, and set
122 # `deserialize_attribute_missing` to whether the attribute was missing.
123 #
124 # Internal method to be implemented by the engines.
125 fun deserialize_attribute(name: String, static_type: nullable String): nullable Object is abstract
126
127 # Was the attribute queried by the last call to `deserialize_attribute` missing?
128 var deserialize_attribute_missing = false
129
130 # Register a newly allocated object (even if not completely built)
131 #
132 # Internal method called by objects in creation, to be implemented by the engines.
133 fun notify_of_creation(new_object: Object) is abstract
134
135 # Deserialize the next available object as an instance of `class_name`
136 #
137 # Return the deserialized object on success and
138 # record in `errors` if `class_name` is unknown.
139 #
140 # This method should be redefined for each custom subclass of `Serializable`.
141 # All refinement should look for a precise `class_name` and call super
142 # on unsupported classes.
143 protected fun deserialize_class(class_name: String): nullable Object do
144 if class_name == "Error" then return new Error.from_deserializer(self)
145 return deserialize_class_intern(class_name)
146 end
147
148 # Generated service to deserialize the next available object as an instance of `class_name`
149 #
150 # Refinements to this method will be generated by the serialization phase.
151 # To avoid conflicts, there should not be any other refinements to this method.
152 # You can instead use `deserialize_class`.
153 protected fun deserialize_class_intern(class_name: String): nullable Object do
154 errors.add new Error("Deserialization Error: Doesn't know how to deserialize class \"{class_name}\"")
155 return null
156 end
157
158 # Should `self` keep trying to deserialize an object after an error?
159 #
160 # This behavior takes effect after each attribute deserialization with
161 # errors such as a missing attribute or the value is of the wrong type.
162 # If `keep_going`, the attribute will be skipped but the engine will
163 # deserialize the next attribute.
164 # If `not keep_going`, the engine stops deserializing right away.
165 #
166 # When at `true`, this may cause the accumulation of a lot of entries in `errors`.
167 #
168 # Default at `true`.
169 var keep_going: nullable Bool = null is writable
170
171 # Errors encountered in the last call to `deserialize`
172 var errors = new Array[Error]
173 end
174
175 # Deserialization error related to an attribute of `receiver`
176 abstract class AttributeError
177 super Error
178
179 # Parent object of the problematic attribute
180 var receiver: Object
181
182 # Name of the problematic attribute in `receiver`
183 var attribute_name: String
184 end
185
186 # Invalid dynamic type for a deserialized attribute
187 class AttributeTypeError
188 super AttributeError
189
190 autoinit receiver, attribute_name, attribute, expected_type
191
192 # Deserialized object that isn't of the `expected_type`
193 var attribute: nullable Object
194
195 # Name of the type expected for `attribute`
196 var expected_type: String
197
198 redef var message is lazy do
199 var attribute = attribute
200 var found_type = if attribute != null then attribute.class_name else "null"
201
202 return "Deserialization Error: {
203 }Wrong type on `{receiver.class_name}::{attribute_name}` expected `{expected_type}`, got `{found_type}`"
204 end
205 end
206
207 # Missing attribute at deserialization
208 class AttributeMissingError
209 super AttributeError
210
211 autoinit receiver, attribute_name
212
213 redef var message is lazy do
214 return "Deserialization Error: Missing attribute `{receiver.class_name}::{attribute_name}`"
215 end
216 end
217
218 # Instances of this class can be passed to `Serializer::serialize`
219 interface Serializable
220 # Serialize `self` to `serializer`
221 #
222 # This is a shortcut to `Serializer::serialize`.
223 fun serialize_to(serializer: Serializer) do serializer.serialize(self)
224
225 # Actual serialization of `self` to `serializer`
226 #
227 # This writes the full data of `self` to `serializer`.
228 #
229 # This method can be redefined in sub classes and refinements.
230 # It should use `Serializer::serialize_attribute` to to register real or
231 # logical attributes.
232 #
233 # Any refinement should have its equivalent refinement of
234 # `Deserializer::deserialize_class` to support this custom deserialization.
235 fun core_serialize_to(serializer: Serializer) do end
236
237 # Accept references or force direct serialization (using `serialize_to`)
238 #
239 # The subclass change the default behavior, which will accept references,
240 # to force to always serialize copies of `self`.
241 private fun serialize_to_or_delay(v: Serializer) do v.serialize_reference(self)
242
243 # Create an instance of this class from the `deserializer`
244 #
245 # This constructor is refined by subclasses to correctly build their instances.
246 init from_deserializer(deserializer: Deserializer) is nosuper do end
247 end
248
249 redef interface Object
250 # Is `self` the same as `other` in a serialization context?
251 #
252 # Used to determine if an object has already been serialized.
253 fun is_same_serialized(other: nullable Object): Bool do return is_same_instance(other)
254
255 # Hash value use for serialization
256 #
257 # Used in combination with `is_same_serialized`. If two objects are the same
258 # in a serialization context, they must have the same `serialization_hash`.
259 fun serialization_hash: Int do return object_id
260 end
261
262 # Instances of this class are not delayed and instead serialized immediately
263 # This applies mainly to `universal` types
264 interface DirectSerializable
265 super Serializable
266
267 redef fun serialize_to_or_delay(v) do serialize_to(v)
268 end
269
270 redef class Bool super DirectSerializable end
271 redef class Char super DirectSerializable end
272 redef class Int super DirectSerializable end
273 redef class Float super DirectSerializable end
274 redef class CString super DirectSerializable end
275 redef class Text super DirectSerializable end
276 redef class SimpleCollection[E] super Serializable end
277 redef class Map[K, V] super Serializable end
278
279 redef class Couple[F, S]
280 super Serializable
281
282 redef init from_deserializer(v)
283 do
284 v.notify_of_creation self
285 var first = v.deserialize_attribute("first")
286 var second = v.deserialize_attribute("second")
287 init(first, second)
288 end
289
290 redef fun core_serialize_to(v)
291 do
292 v.serialize_attribute("first", first)
293 v.serialize_attribute("second", second)
294 end
295 end
296
297 redef class Ref[E]
298 super Serializable
299
300 redef init from_deserializer(v)
301 do
302 v.notify_of_creation self
303 var item = v.deserialize_attribute("item")
304 init item
305 end
306
307 redef fun core_serialize_to(v)
308 do
309 v.serialize_attribute("item", first)
310 end
311 end
312
313 redef class Error
314 super Serializable
315
316 redef init from_deserializer(v)
317 do
318 v.notify_of_creation self
319
320 var message = v.deserialize_attribute("message")
321 if not message isa String then message = ""
322 init message
323
324 var cause = v.deserialize_attribute("cause")
325 if cause isa nullable Error then self.cause = cause
326 end
327
328 redef fun core_serialize_to(v)
329 do
330 v.serialize_attribute("message", message)
331 v.serialize_attribute("cause", cause)
332 end
333 end
334
335 # ---
336 # core::queue classes
337
338 redef abstract class ProxyQueue[E]
339
340 redef init from_deserializer(v)
341 do
342 v.notify_of_creation self
343
344 var seq = v.deserialize_attribute("seq", (new GetName[Sequence[E]]).to_s)
345 if not seq isa Sequence[E] then seq = new Array[E]
346 if v.deserialize_attribute_missing then
347 v.errors.add new AttributeMissingError(self, "seq")
348 end
349
350 init seq
351 end
352
353 redef fun core_serialize_to(v) do v.serialize_attribute("seq", seq)
354 end
355
356 redef class RandQueue[E]
357
358 redef init from_deserializer(v)
359 do
360 v.notify_of_creation self
361
362 var seq = v.deserialize_attribute("seq", (new GetName[SimpleCollection[E]]).to_s)
363 if not seq isa SimpleCollection[E] then seq = new Array[E]
364 if v.deserialize_attribute_missing then
365 v.errors.add new AttributeMissingError(self, "seq")
366 end
367
368 init seq
369 end
370
371 redef fun core_serialize_to(v) do v.serialize_attribute("seq", seq)
372 end
373
374 redef class MinHeap[E]
375
376 redef init from_deserializer(v)
377 do
378 v.notify_of_creation self
379
380 var items = v.deserialize_attribute("items", (new GetName[SimpleCollection[E]]).to_s)
381 if not items isa Array[E] then items = new Array[E]
382 if v.deserialize_attribute_missing then
383 v.errors.add new AttributeMissingError(self, "items")
384 end
385
386 var comparator = v.deserialize_attribute("comparator", "Comparator")
387 if not comparator isa Comparator then comparator = default_comparator
388 if v.deserialize_attribute_missing then
389 v.errors.add new AttributeMissingError(self, "comparator")
390 end
391
392 init comparator
393 self.items.add_all items
394 end
395
396 redef fun core_serialize_to(v)
397 do
398 v.serialize_attribute("items", items)
399 v.serialize_attribute("comparator", comparator)
400 end
401 end