# ~~~
module serialization
-import ::serialization
+import ::serialization::caching
private import ::serialization::engine_tools
private import static
# Serializer of Nit objects to Json string.
class JsonSerializer
- super Serializer
+ super CachingSerializer
# Target writing stream
var stream: Writer
redef fun serialize_reference(object)
do
- if not plain_json and refs_map.has_key(object) then
+ if not plain_json and cache.has_object(object) then
# if already serialized, add local reference
- var id = ref_id_for(object)
+ var id = cache.id_for(object)
stream.write "\{\"__kind\": \"ref\", \"__id\": "
stream.write id.to_s
stream.write "\}"
serialize object
end
end
-
- # Map of references to already serialized objects.
- private var refs_map = new StrictHashMap[Serializable,Int]
-
- # Get the internal serialized reference for this `object`.
- private fun ref_id_for(object: Serializable): Int
- do
- if refs_map.has_key(object) then
- return refs_map[object]
- else
- var id = refs_map.length
- refs_map[object] = id
- return id
- end
- end
end
# Deserializer from a Json string.
class JsonDeserializer
- super Deserializer
+ super CachingDeserializer
# Json text to deserialize from.
private var text: Text
# Depth-first path in the serialized object tree.
private var path = new Array[JsonObject]
- # Map of references to already deserialized objects.
- private var id_to_object = new StrictHashMap[Int, Object]
-
# Last encountered object reference id.
#
# See `id_to_object`.
do
var id = just_opened_id
if id == null then return # Register `new_object` only once
- id_to_object[id] = new_object
+ cache[id] = new_object
end
# Convert from simple Json object to Nit object
var id = object["__id"]
assert id isa Int
- assert id_to_object.has_key(id)
- return id_to_object[id]
+ assert cache.has_id(id)
+ return cache.object_for(id)
end
# obj?
var class_name = object["__class"]
assert class_name isa String
- assert not id_to_object.has_key(id) else print "Error: Object with id '{id}' of {class_name} is deserialized twice."
+ assert not cache.has_id(id) else print "Error: Object with id '{id}' of {class_name} is deserialized twice."
# advance on path
path.push object
redef class Serializable
private fun serialize_to_json(v: JsonSerializer)
do
- var id = v.ref_id_for(self)
+ var id = v.cache.new_id_for(self)
v.stream.write "\{"
if not v.plain_json then
v.stream.write "\"__kind\": \"obj\", \"__id\": "
do
# Register as pseudo object
if not v.plain_json then
- var id = v.ref_id_for(self)
+ var id = v.cache.new_id_for(self)
v.stream.write """{"__kind": "obj", "__id": """
v.stream.write id.to_s
v.stream.write """, "__class": """"
redef fun serialize_to_json(v)
do
# Register as pseudo object
- var id = v.ref_id_for(self)
+ var id = v.cache.new_id_for(self)
if v.plain_json then
v.stream.write "\{"
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Services for caching serialization engines
+module caching
+
+import serialization
+private import engine_tools
+
+# A `Serializer` with a `cache`
+abstract class CachingSerializer
+ super Serializer
+
+ # Cache of known objects
+ var cache = new SerializerCache is lazy, writable
+end
+
+# A `Deserializer` with a `cache`
+abstract class CachingDeserializer
+ super Deserializer
+
+ # Cache of known objects
+ var cache = new DeserializerCache is lazy, writable
+end
+
+# Cache of sent objects
+#
+# Used by `Serializer` to avoid duplicating objects, by serializing them once,
+# then using a reference.
+class SerializerCache
+ # Map of already serialized objects to the reference id
+ private var sent: Map[Serializable, Int] = new StrictHashMap[Serializable, Int]
+
+ # Is `object` known?
+ fun has_object(object: Serializable): Bool do return sent.keys.has(object)
+
+ # Get the id for `object`
+ #
+ # Require: `has_object(object)`
+ fun id_for(object: Serializable): Int
+ do
+ assert sent.keys.has(object)
+ return sent[object]
+ end
+
+ # Get a new id for `object` and store it
+ #
+ # Require: `not has_object(object)`
+ fun new_id_for(object: Serializable): Int
+ do
+ var id = sent.length
+ sent[object] = id
+ return id
+ end
+end
+
+# Cache of received objects sorted by there reference id
+#
+# Used by `Deserializer` to find already deserialized objects by their reference.
+class DeserializerCache
+ # Map of references to already deserialized objects.
+ private var received: Map[Int, Object] = new StrictHashMap[Int, Object]
+
+ # Is there an object associated to `id`?
+ fun has_id(id: Int): Bool do return received.keys.has(id)
+
+ # Get the object associated to `id`
+ fun object_for(id: Int): nullable Object do return received[id]
+
+ # Associate `object` to `id`
+ fun []=(id: Int, object: Object) do received[id] = object
+end