lib: intro the json serialization module
authorAlexis Laferrière <alexis.laf@xymus.net>
Sat, 1 Feb 2014 18:49:35 +0000 (13:49 -0500)
committerAlexis Laferrière <alexis.laf@xymus.net>
Fri, 7 Feb 2014 19:44:41 +0000 (14:44 -0500)
Signed-off-by: Alexis Laferrière <alexis.laf@xymus.net>

lib/json_serialization.nit [new file with mode: 0644]

diff --git a/lib/json_serialization.nit b/lib/json_serialization.nit
new file mode 100644 (file)
index 0000000..4b15e88
--- /dev/null
@@ -0,0 +1,108 @@
+# 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.
+
+module json_serialization
+
+import serialization
+
+class JsonSerializer
+       super Serializer
+
+       # Target writing stream
+       var stream: OStream
+
+       init(stream: OStream) do self.stream = stream
+
+       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.keys.has(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
+       var refs_map = new HashMap[Serializable,Int]
+
+       private fun ref_id_for(object: Serializable): Int
+       do
+               if refs_map.keys.has(object) then
+                       return refs_map[object]
+               else
+                       var id = refs_map.length
+                       refs_map[object] = id
+                       return id
+               end
+       end
+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("'{to_s}'")
+end
+
+redef class String
+       redef fun serialize_to_json(v) do v.stream.write("\"{to_json_s}\"")
+
+       private fun to_json_s: String do return self.replace("\\", "\\\\").
+               replace("\"", "\\\"").replace("\b", "\\b").replace("/", "\\/").
+               replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t")
+               # FIXME add support for unicode char when supported by Nit strings
+               # FIXME add support for \f! # .replace("\f", "\\f")
+end
+
+redef class NativeString
+       redef fun serialize_to_json(v) do to_s.serialize_to_json(v)
+end
+