lib/serialization: prepare to collect errors and customize reactions to them
[nit.git] / lib / serialization / serialization.nit
index aa8da21..d120254 100644 (file)
@@ -16,7 +16,7 @@
 
 # Abstract services to serialize Nit objects to different formats
 #
-# This module declares the `auto_serializable` annotation to mark Nit classes as serializable.
+# This module declares the `serialize` annotation to mark Nit classes as serializable.
 # For an introduction to this service, refer to the documentation of the `serialization` group.
 # This documentation provides more technical information on interesting entitie of this module.
 #
@@ -44,6 +44,8 @@
 #   `notify_of_creation` must be redefined.
 module serialization is
        new_annotation auto_serializable
+       new_annotation serialize
+       new_annotation noserialize
 end
 
 # Abstract serialization service to be sub-classed by specialized services.
@@ -86,7 +88,7 @@ end
 # Abstract deserialization service
 #
 # After initialization of one of its sub-classes, call `deserialize`
-interface Deserializer
+abstract class Deserializer
        # Main method of this class, returns a Nit object
        fun deserialize: nullable Object is abstract
 
@@ -108,6 +110,48 @@ interface Deserializer
                print "Error: doesn't know how to deserialize class \"{class_name}\""
                abort
        end
+
+       # Should `self` keep trying to deserialize an object after an error?
+       #
+       # This behavior takes effect after each attribute deserialization with
+       # errors such as a missing attribute or the value is of the wrong type.
+       # If `keep_going`, the attribute will be skipped but the engine will
+       # deserialize the next attribute.
+       # If `not keep_going`, the engine stops deserializing right away.
+       #
+       # When at `true`, this may cause the accumulation of a lot of entries in `errors`.
+       #
+       # Default at `true`.
+       var keep_going: nullable Bool is writable
+
+       # Errors encountered in the last call to `deserialize`
+       var errors = new Array[Error]
+end
+
+# Deserialization got wrong attribute names
+class AttributeTypeError
+       super Error
+
+       # Parent object of the problematic attribute
+       var receiver: Object
+
+       # Name of the problematic attribute in `receiver`
+       var attribute_name: String
+
+       # Deserialized object that isn't of the `expected_type`
+       var attribute: nullable Object
+
+       # Name of the type expected for `attribute`
+       var expected_type: String
+
+       redef fun to_s
+       do
+               var attribute = attribute
+               var found_type = if attribute != null then attribute.class_name else "null"
+
+               return "Deserialization Error: {
+               }Wrong type on `{receiver.class_name}::{attribute_name}` expected `{expected_type}`, got `{found_type}`"
+       end
 end
 
 # Instances of this class can be passed to `Serializer::serialize`
@@ -141,6 +185,19 @@ interface Serializable
        init from_deserializer(deserializer: Deserializer) do end
 end
 
+redef interface Object
+       # Is `self` the same as `other` in a serialization context?
+       #
+       # Used to determine if an object has already been serialized.
+       fun is_same_serialized(other: nullable Object): Bool do return is_same_instance(other)
+
+       # Hash value use for serialization
+       #
+       # Used in combination with `is_same_serialized`. If two objects are the same
+       # in a serialization context, they must have the same `serialization_hash`.
+       fun serialization_hash: Int do return object_id
+end
+
 # Instances of this class are not delayed and instead serialized immediately
 # This applies mainly to `universal` types
 interface DirectSerializable
@@ -155,4 +212,39 @@ redef class Int super DirectSerializable end
 redef class Float super DirectSerializable end
 redef class NativeString super DirectSerializable end
 redef class String super DirectSerializable end
-redef class Array[E] super Serializable end
+redef class SimpleCollection[E] super Serializable end
+redef class Map[K, V] super Serializable end
+
+redef class Couple[F, S]
+       super Serializable
+
+       redef init from_deserializer(v)
+       do
+               v.notify_of_creation self
+               var first = v.deserialize_attribute("first")
+               var second = v.deserialize_attribute("second")
+               init(first, second)
+       end
+
+       redef fun core_serialize_to(v)
+       do
+               v.serialize_attribute("first", first)
+               v.serialize_attribute("second", second)
+       end
+end
+
+redef class Container[E]
+       super Serializable
+
+       redef init from_deserializer(v)
+       do
+               v.notify_of_creation self
+               var item = v.deserialize_attribute("item")
+               init item
+       end
+
+       redef fun core_serialize_to(v)
+       do
+               v.serialize_attribute("item", first)
+       end
+end