serialization: implement serialization for classes of `core::queue`
[nit.git] / lib / serialization / serialization.nit
index 7ecc7d2..597ae98 100644 (file)
@@ -49,6 +49,9 @@ module serialization is
        new_annotation serialize_as
 end
 
        new_annotation serialize_as
 end
 
+intrude import core::queue
+import meta
+
 # Abstract serialization service to be sub-classed by specialized services.
 interface Serializer
        # Entry point method of this service, serialize the `object`
 # Abstract serialization service to be sub-classed by specialized services.
 interface Serializer
        # Entry point method of this service, serialize the `object`
@@ -57,6 +60,11 @@ interface Serializer
        # use double dispatch to customize the bahavior per serializable objects.
        fun serialize(object: nullable Serializable) is abstract
 
        # use double dispatch to customize the bahavior per serializable objects.
        fun serialize(object: nullable Serializable) is abstract
 
+       # The object currently serialized by `serialized`
+       #
+       # Can be used by a custom serializer to add domain-specific serialization behavior.
+       protected fun current_object: nullable Object is abstract
+
        # Serialize an object, with full serialization or a simple reference
        protected fun serialize_reference(object: Serializable) is abstract
 
        # Serialize an object, with full serialization or a simple reference
        protected fun serialize_reference(object: Serializable) is abstract
 
@@ -81,6 +89,15 @@ interface Serializer
                return true
        end
 
                return true
        end
 
+       # The method is called when a standard `value` is serialized
+       #
+       # The default behavior is to call `value.core_serialize_to(self)` but it
+       # can be redefined by a custom serializer to add domain-specific serialization behavior.
+       fun serialize_core(value: Serializable)
+       do
+               value.core_serialize_to(self)
+       end
+
        # Warn of problems and potential errors (such as if an attribute
        # is not serializable)
        fun warn(msg: String) do print "Serialization warning: {msg}"
        # Warn of problems and potential errors (such as if an attribute
        # is not serializable)
        fun warn(msg: String) do print "Serialization warning: {msg}"
@@ -92,17 +109,24 @@ end
 abstract class Deserializer
        # Deserialize and return an object, storing errors in the attribute `errors`
        #
 abstract class Deserializer
        # Deserialize and return an object, storing errors in the attribute `errors`
        #
+       # If a `static_type` is given, only subtypes of the `static_type` are accepted.
+       #
        # This method behavior varies according to the implementation engines.
        # This method behavior varies according to the implementation engines.
-       fun deserialize: nullable Object is abstract
+       fun deserialize(static_type: nullable String): nullable Object is abstract
 
        # Deserialize the attribute with `name` from the object open for deserialization
        #
 
        # Deserialize the attribute with `name` from the object open for deserialization
        #
-       # The `static_type` can be used as last resort if the deserialized object
-       # desn't have any metadata declaring the dynamic type.
+       # The `static_type` restricts what kind of object can be deserialized.
+       #
+       # Return the deserialized value or null on error, and set
+       # `deserialize_attribute_missing` to whether the attribute was missing.
        #
        # Internal method to be implemented by the engines.
        fun deserialize_attribute(name: String, static_type: nullable String): nullable Object is abstract
 
        #
        # Internal method to be implemented by the engines.
        fun deserialize_attribute(name: String, static_type: nullable String): nullable Object is abstract
 
+       # Was the attribute queried by the last call to `deserialize_attribute` missing?
+       var deserialize_attribute_missing = false
+
        # Register a newly allocated object (even if not completely built)
        #
        # Internal method called by objects in creation, to be implemented by the engines.
        # Register a newly allocated object (even if not completely built)
        #
        # Internal method called by objects in creation, to be implemented by the engines.
@@ -148,17 +172,22 @@ abstract class Deserializer
        var errors = new Array[Error]
 end
 
        var errors = new Array[Error]
 end
 
-# Deserialization got wrong attribute names
-class AttributeTypeError
+# Deserialization error related to an attribute of `receiver`
+abstract class AttributeError
        super Error
 
        super Error
 
-       autoinit receiver, attribute_name, attribute, expected_type
-
        # Parent object of the problematic attribute
        var receiver: Object
 
        # Name of the problematic attribute in `receiver`
        var attribute_name: String
        # Parent object of the problematic attribute
        var receiver: Object
 
        # Name of the problematic attribute in `receiver`
        var attribute_name: String
+end
+
+# Invalid dynamic type for a deserialized attribute
+class AttributeTypeError
+       super AttributeError
+
+       autoinit receiver, attribute_name, attribute, expected_type
 
        # Deserialized object that isn't of the `expected_type`
        var attribute: nullable Object
 
        # Deserialized object that isn't of the `expected_type`
        var attribute: nullable Object
@@ -175,6 +204,17 @@ class AttributeTypeError
        end
 end
 
        end
 end
 
+# Missing attribute at deserialization
+class AttributeMissingError
+       super AttributeError
+
+       autoinit receiver, attribute_name
+
+       redef var message is lazy do
+               return "Deserialization Error: Missing attribute `{receiver.class_name}::{attribute_name}`"
+       end
+end
+
 # Instances of this class can be passed to `Serializer::serialize`
 interface Serializable
        # Serialize `self` to `serializer`
 # Instances of this class can be passed to `Serializer::serialize`
 interface Serializable
        # Serialize `self` to `serializer`
@@ -231,7 +271,7 @@ redef class Bool super DirectSerializable end
 redef class Char super DirectSerializable end
 redef class Int super DirectSerializable end
 redef class Float super DirectSerializable end
 redef class Char super DirectSerializable end
 redef class Int super DirectSerializable end
 redef class Float super DirectSerializable end
-redef class NativeString super DirectSerializable end
+redef class CString super DirectSerializable end
 redef class Text super DirectSerializable end
 redef class SimpleCollection[E] super Serializable end
 redef class Map[K, V] super Serializable end
 redef class Text super DirectSerializable end
 redef class SimpleCollection[E] super Serializable end
 redef class Map[K, V] super Serializable end
@@ -291,3 +331,71 @@ redef class Error
                v.serialize_attribute("cause", cause)
        end
 end
                v.serialize_attribute("cause", cause)
        end
 end
+
+# ---
+# core::queue classes
+
+redef abstract class ProxyQueue[E]
+
+       redef init from_deserializer(v)
+       do
+               v.notify_of_creation self
+
+               var seq = v.deserialize_attribute("seq", (new GetName[Sequence[E]]).to_s)
+               if not seq isa Sequence[E] then seq = new Array[E]
+               if v.deserialize_attribute_missing then
+                       v.errors.add new AttributeMissingError(self, "seq")
+               end
+
+               init seq
+       end
+
+       redef fun core_serialize_to(v) do v.serialize_attribute("seq", seq)
+end
+
+redef class RandQueue[E]
+
+       redef init from_deserializer(v)
+       do
+               v.notify_of_creation self
+
+               var seq = v.deserialize_attribute("seq", (new GetName[SimpleCollection[E]]).to_s)
+               if not seq isa SimpleCollection[E] then seq = new Array[E]
+               if v.deserialize_attribute_missing then
+                       v.errors.add new AttributeMissingError(self, "seq")
+               end
+
+               init seq
+       end
+
+       redef fun core_serialize_to(v) do v.serialize_attribute("seq", seq)
+end
+
+redef class MinHeap[E]
+
+       redef init from_deserializer(v)
+       do
+               v.notify_of_creation self
+
+               var items = v.deserialize_attribute("items", (new GetName[SimpleCollection[E]]).to_s)
+               if not items isa Array[E] then items = new Array[E]
+               if v.deserialize_attribute_missing then
+                       v.errors.add new AttributeMissingError(self, "items")
+               end
+
+               var comparator = v.deserialize_attribute("comparator", "Comparator")
+               if not comparator isa Comparator then comparator = default_comparator
+               if v.deserialize_attribute_missing then
+                       v.errors.add new AttributeMissingError(self, "comparator")
+               end
+
+               init comparator
+               self.items.add_all items
+       end
+
+       redef fun core_serialize_to(v)
+       do
+               v.serialize_attribute("items", items)
+               v.serialize_attribute("comparator", comparator)
+       end
+end