# be deserialized to their original form using `JsonDeserializer`.
# * Use references when an object has already been serialized so to not duplicate it.
# * Support cycles in references.
- # * Preserve the Nit `Char` type as an object because it does not exist in JSON.
+ # * Preserve the Nit `Char` and `Byte` types as special objects.
# * The generated JSON is standard and can be read by non-Nit programs.
# However, some Nit types are not represented by the simplest possible JSON representation.
# With the added metadata, it can be complex to read.
# Used only when `plain_json == true`.
private var first_attribute = false
+ redef var current_object = null
+
redef fun serialize(object)
do
if object == null then
end
first_attribute = true
+ var last_object = current_object
+ current_object = object
object.accept_json_serializer self
first_attribute = false
+ current_object = last_object
if plain_json then open_objects.pop
end
do
if not plain_json or not first_attribute then
stream.write ","
- first_attribute = false
end
+ first_attribute = false
new_line_and_indent
stream.write "\""
redef fun accept_json_serializer(v)
do
v.stream.write "\""
+
+ var start_i = 0
+ var escaped = null
for i in [0 .. self.length[ do
var char = self[i]
if char == '\\' then
- v.stream.write "\\\\"
+ escaped = "\\\\"
else if char == '\"' then
- v.stream.write "\\\""
+ escaped = "\\\""
else if char < ' ' then
if char == '\n' then
- v.stream.write "\\n"
+ escaped = "\\n"
else if char == '\r' then
- v.stream.write "\\r"
+ escaped = "\\r"
else if char == '\t' then
- v.stream.write "\\t"
+ escaped = "\\t"
else
- v.stream.write char.escape_to_utf16
+ escaped = char.escape_to_utf16
+ end
+ end
+
+ if escaped != null then
+ # Write open non-escaped string
+ if start_i <= i then
+ v.stream.write substring(start_i, i-start_i)
end
+
+ # Write escaped character
+ v.stream.write escaped
+ escaped = null
+ start_i = i+1
+ end
+ end
+
+ # Write remaining non-escaped string
+ if start_i < length then
+ if start_i == 0 then
+ v.stream.write self
else
- v.stream.write char.to_s
+ v.stream.write substring(start_i, length-start_i)
end
end
+
v.stream.write "\""
end
end
# which is used by all the serialization engines, not just JSON.
protected fun accept_json_serializer(v: JsonSerializer)
do
- var id = v.cache.new_id_for(self)
v.stream.write "\{"
v.indent_level += 1
if not v.plain_json then
+ var id = v.cache.new_id_for(self)
v.new_line_and_indent
v.stream.write "\"__kind\": \"obj\", \"__id\": "
v.stream.write id.to_s
v.stream.write class_name
v.stream.write "\""
end
- core_serialize_to(v)
+ v.serialize_core(self)
v.indent_level -= 1
v.new_line_and_indent
end
end
-redef class NativeString
+redef class Byte
+ redef fun accept_json_serializer(v)
+ do
+ if v.plain_json then
+ to_i.accept_json_serializer v
+ else
+ v.stream.write "\{\"__kind\": \"byte\", \"__val\": "
+ to_i.accept_json_serializer v
+ v.stream.write "\}"
+ end
+ end
+end
+
+redef class CString
redef fun accept_json_serializer(v) do to_s.accept_json_serializer(v)
end
if not v.try_to_serialize(e) then
assert e != null # null would have been serialized
v.warn("element of type {e.class_name} is not serializable.")
+ v.stream.write "null"
end
end
v.stream.write "]"
redef class SimpleCollection[E]
redef fun accept_json_serializer(v)
do
- # Register as pseudo object
- if not v.plain_json then
+ if v.plain_json then
+ serialize_to_pure_json v
+ else
+ # Register as pseudo object
var id = v.cache.new_id_for(self)
v.stream.write """{"""
v.indent_level += 1
v.stream.write class_name
v.stream.write """","""
v.new_line_and_indent
+
v.stream.write """"__items": """
+ serialize_to_pure_json v
core_serialize_to v
- end
-
- serialize_to_pure_json v
- if not v.plain_json then
v.indent_level -= 1
v.new_line_and_indent
v.stream.write "\}"