serialization: implement serialization for classes of `core::queue`
[nit.git] / lib / serialization / serialization.nit
index 435f8df..597ae98 100644 (file)
@@ -49,6 +49,9 @@ module serialization is
        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`
@@ -57,6 +60,11 @@ interface Serializer
        # 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
 
@@ -81,6 +89,15 @@ interface Serializer
                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}"
@@ -92,13 +109,23 @@ end
 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.
-       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
        #
+       # 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): nullable Object is abstract
+       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)
        #
@@ -145,17 +172,22 @@ abstract class Deserializer
        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
 
-       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
+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
@@ -172,6 +204,17 @@ class AttributeTypeError
        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`
@@ -228,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 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
@@ -288,3 +331,71 @@ redef class Error
                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