lib/json: move `json_serialization` to `json::serialization`
[nit.git] / lib / json_serialization.nit
diff --git a/lib/json_serialization.nit b/lib/json_serialization.nit
deleted file mode 100644 (file)
index b9667db..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
-#
-# 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.
-
-# Handles serialization and deserialization of objects to/from Json.
-module json_serialization
-
-import serialization
-import json::static
-
-# Serializer of Nit objects to Json string.
-class JsonSerializer
-       super Serializer
-
-       # Target writing stream
-       var stream: Writer
-
-       redef fun serialize(object)
-       do
-               if object == null then
-                       stream.write "null"
-               else object.serialize_to_json(self)
-       end
-
-       redef fun serialize_attribute(name, value)
-       do
-               stream.write ", \"{name}\": "
-               super
-       end
-
-       redef fun serialize_reference(object)
-       do
-               if refs_map.has_key(object) then
-                       # if already serialized, add local reference
-                       var id = ref_id_for(object)
-                       stream.write "\{\"__kind\": \"ref\", \"__id\": {id}\}"
-               else
-                       # serialize here
-                       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
-
-       # Json text to deserialize from.
-       private var text: Text
-
-       # Root json object parsed from input text.
-       var root: nullable Jsonable is noinit
-
-       # Depth-first path in the serialized object tree.
-       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`.
-       var just_opened_id: nullable Int = null
-
-       init do
-               var root = text.parse_json
-               if root isa JsonObject then path.add(root)
-               self.root = root
-       end
-
-       redef fun deserialize_attribute(name)
-       do
-               assert not path.is_empty
-               var current = path.last
-
-               assert current.keys.has(name)
-               var value = current[name]
-
-               return convert_object(value)
-       end
-
-       # This may be called multiple times by the same object from constructors
-       # in different nclassdef
-       redef fun notify_of_creation(new_object)
-       do
-               var id = just_opened_id
-               if id == null then return # Register `new_object` only once
-               id_to_object[id] = new_object
-       end
-
-       # Convert from simple Json object to Nit object
-       private fun convert_object(object: nullable Object): nullable Object
-       do
-               if object isa JsonObject then
-                       assert object.keys.has("__kind")
-                       var kind = object["__kind"]
-
-                       # ref?
-                       if kind == "ref" then
-                               assert object.keys.has("__id")
-                               var id = object["__id"]
-                               assert id isa Int
-
-                               assert id_to_object.has_key(id)
-                               return id_to_object[id]
-                       end
-
-                       # obj?
-                       if kind == "obj" then
-                               assert object.keys.has("__id")
-                               var id = object["__id"]
-                               assert id isa Int
-
-                               assert object.keys.has("__class")
-                               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."
-
-                               # advance on path
-                               path.push object
-
-                               just_opened_id = id
-                               var value = deserialize_class(class_name)
-                               just_opened_id = null
-
-                               # revert on path
-                               path.pop
-
-                               return value
-                       end
-
-                       # char?
-                       if kind == "char" then
-                               assert object.keys.has("__val")
-                               var val = object["__val"]
-                               assert val isa String
-
-                               if val.length != 1 then print "Error: expected a single char when deserializing '{val}'."
-
-                               return val.chars.first
-                       end
-
-                       print "Malformed Json string: unexpected Json Object kind '{kind or else "null"}'"
-                       abort
-               end
-
-               if object isa Array[nullable Object] then
-                       # special case, isa Array[nullable Serializable]
-                       var array = new Array[nullable Serializable]
-                       for e in object do array.add e.as(nullable Serializable)
-                       return array
-               end
-
-               return object
-       end
-
-       redef fun deserialize do return convert_object(root)
-end
-
-redef class Serializable
-       private fun serialize_to_json(v: JsonSerializer)
-       do
-               var id = v.ref_id_for(self)
-               v.stream.write "\{\"__kind\": \"obj\", \"__id\": {id}, \"__class\": \"{class_name}\""
-               core_serialize_to(v)
-               v.stream.write "\}"
-       end
-end
-
-redef class Int
-       redef fun serialize_to_json(v) do v.stream.write(to_s)
-end
-
-redef class Float
-       redef fun serialize_to_json(v) do v.stream.write(to_s)
-end
-
-redef class Bool
-       redef fun serialize_to_json(v) do v.stream.write(to_s)
-end
-
-redef class Char
-       redef fun serialize_to_json(v) do v.stream.write "\{\"__kind\": \"char\", \"__val\": {to_s.to_json}\}"
-end
-
-redef class String
-       redef fun serialize_to_json(v) do v.stream.write(to_json)
-end
-
-redef class NativeString
-       redef fun serialize_to_json(v) do to_s.serialize_to_json(v)
-end
-
-redef class Collection[E]
-       # Utility to serialize a normal Json array
-       private fun serialize_to_pure_json(v: JsonSerializer)
-       do
-                       v.stream.write "["
-                       var is_first = true
-                       for e in self do
-                               if is_first then
-                                       is_first = false
-                               else v.stream.write ", "
-
-                               if not v.try_to_serialize(e) then
-                                       v.warn("element of type {e.class_name} is not serializable.")
-                               end
-                       end
-                       v.stream.write "]"
-       end
-end
-
-redef class SimpleCollection[E]
-       redef fun serialize_to_json(v)
-       do
-               # Register as pseudo object
-               var id = v.ref_id_for(self)
-               v.stream.write """{"__kind": "obj", "__id": """
-               v.stream.write id.to_s
-               v.stream.write """, "__class": """"
-               v.stream.write class_name
-               v.stream.write """", "__length": """
-               v.stream.write length.to_s
-               v.stream.write """, "__items": """
-               serialize_to_pure_json v
-               v.stream.write "\}"
-       end
-
-       redef init from_deserializer(v: Deserializer)
-       do
-               if v isa JsonDeserializer then
-                       v.notify_of_creation self
-                       init
-
-                       var length = v.deserialize_attribute("__length").as(Int)
-                       var arr = v.path.last["__items"].as(SequenceRead[nullable Object])
-                       for i in length.times do
-                               var obj = v.convert_object(arr[i])
-                               self.add obj
-                       end
-               end
-       end
-end
-
-redef class Array[E]
-       redef fun serialize_to_json(v)
-       do
-               if class_name == "Array[nullable Serializable]" then
-                       # Using class_name to get the exact type,
-                       # we do not want Array[Int] or anything else here.
-
-                       serialize_to_pure_json v
-               else super
-       end
-end
-
-redef class Map[K, V]
-       redef fun serialize_to_json(v)
-       do
-               # Register as pseudo object
-               var id = v.ref_id_for(self)
-
-               v.stream.write """{"__kind": "obj", "__id": """
-               v.stream.write id.to_s
-               v.stream.write """, "__class": """"
-               v.stream.write class_name
-               v.stream.write """", "__length": """
-               v.stream.write length.to_s
-               v.stream.write """, "__keys": """
-
-               keys.serialize_to_pure_json v
-
-               v.stream.write """, "__values": """
-               values.serialize_to_pure_json v
-               v.stream.write "\}"
-       end
-
-       # Instantiate a new `Array` from its serialized representation.
-       redef init from_deserializer(v: Deserializer)
-       do
-               init
-
-               if v isa JsonDeserializer then
-                       v.notify_of_creation self
-
-                       var length = v.deserialize_attribute("__length").as(Int)
-                       var keys = v.path.last["__keys"].as(SequenceRead[nullable Object])
-                       var values = v.path.last["__values"].as(SequenceRead[nullable Object])
-                       for i in length.times do
-                               var key = v.convert_object(keys[i])
-                               var value = v.convert_object(values[i])
-                               self[key] = value
-                       end
-               end
-       end
-end
-
-# Maps instances to a value, uses `is_same_instance`
-#
-# Warning: This class does not implement all the services from `Map`.
-private class StrictHashMap[K, V]
-       super Map[K, V]
-
-       # private
-       var map = new HashMap[K, Array[Couple[K, V]]]
-
-       redef var length = 0
-
-       redef fun is_empty do return length == 0
-
-       # private
-       fun node_at(key: K): nullable Couple[K, V]
-       do
-               if not map.keys.has(key) then return null
-
-               var arr = map[key]
-               for couple in arr do
-                       if couple.first.is_same_serialized(key) then
-                               return couple
-                       end
-               end
-
-               return null
-       end
-
-       redef fun [](key)
-       do
-               var node = node_at(key)
-               assert node != null
-               return node.second
-       end
-
-       redef fun []=(key, value)
-       do
-               var node = node_at(key)
-               if node != null then
-                       node.second = value
-                       return
-               end
-
-               var arr
-               if not map.keys.has(key) then
-                       arr = new Array[Couple[K, V]]
-                       map[key] = arr
-               else arr = map[key]
-
-               arr.add new Couple[K, V](key, value)
-               self.length += 1
-       end
-
-       redef fun has_key(key) do return node_at(key) != null
-end