# The serialized data format uses a dictionary structure similar to BSON:
#
# ~~~raw
-# object = 0x01 # null
-# | 0x02 id attributes # New object
-# | 0x03 id # Ref to object
-# | 0x04 int64 # Int
-# | 0x05 int8 # Bool (int8 != 0)
-# | 0x06 int8 # Char
-# | 0x07 double(64 bits) # Float
-# | 0x08 block # String
-# | 0x09 block # NativeString
-# | 0x0A flat_array; # Array[nullable Object]
+# object = 0x01 # null
+# | 0x02 id attributes # New object
+# | 0x03 id # Ref to object
+# | 0x04 int64 # Int
+# | 0x05 int8 # Bool (int8 != 0)
+# | 0x06 utf8 byte sequence # Char
+# | 0x07 double(64 bits) # Float
+# | 0x08 block # String
+# | 0x09 block # CString
+# | 0x0A flat_array; # Array[nullable Object]
#
# block = int64 int8*;
# cstring = int8* 0x00;
private fun kind_char: Byte do return 0x06u8
private fun kind_float: Byte do return 0x07u8
private fun kind_string: Byte do return 0x08u8
-private fun kind_native_string: Byte do return 0x09u8
+private fun kind_c_string: Byte do return 0x09u8
private fun kind_flat_array: Byte do return 0x0Au8
private fun new_object_end: Byte do return 0x00u8
# Target writing stream
var stream: Writer is writable
+ redef var current_object = null
+
redef fun serialize(object)
do
if object == null then
stream.write_int64 id
else
# serialize here
+ var last_object = current_object
+ current_object = object
object.serialize_to_binary self
+ current_object = last_object
end
end
# Tree of attributes, deserialized but not yet claimed
private var unclaimed_attributes = new UnrolledList[HashMap[String, nullable Object]]
+ # Buffer for one char
+ private var char_buf: CString is lazy do return new CString(4)
+
# Read and deserialize the next attribute name and value
#
# A `peeked_char` can suffix the next attribute name.
return new Couple[String, nullable Object](next_attribute_name, next_object)
end
- redef fun deserialize_attribute(name)
+ redef fun deserialize_attribute(name, static_type)
do
if unclaimed_attributes.last.keys.has(name) then
# Pick in already deserialized attributes
# An invalid attribute name is an heuristic for invalid data.
# Hitting an object end marker will result in an empty string.
- assert next_attribute_name.is_valid_id else
+ if not next_attribute_name.is_valid_id then
var error
if next_attribute_name.is_empty then
if kind == kind_bool then return stream.read_bool
if kind == kind_float then return stream.read_double
if kind == kind_char then
+ var bf = char_buf
var b = stream.read_byte
- if b == null then return 0
- return b.to_i.ascii
+ if b == null then return '�'
+ var ln = b.u8len
+ bf[0] = b
+ for i in [1 .. ln[ do
+ b = stream.read_byte
+ if b == null then return '�'
+ bf[i] = b
+ end
+ return bf.to_s_unsafe(ln, copy=false)[0]
end
if kind == kind_string then return stream.read_block
- if kind == kind_native_string then return stream.read_block.to_cstring
+ if kind == kind_c_string then return stream.read_block.to_cstring
if kind == kind_flat_array then
# An array
return null
end
- redef fun deserialize
+ redef fun deserialize(static_type)
do
errors.clear
return true
end
+
+ redef fun serialize_to_binary(v)
+ do
+ v.stream.write_byte kind_string
+ v.stream.write_block to_s
+ end
end
# ---
private fun serialize_to_binary(v: BinarySerializer)
do
serialize_header_to_binary v
- core_serialize_to v
+ v.serialize_core self
v.stream.write_byte new_object_end
end
end
redef fun serialize_to_binary(v)
do
v.stream.write_byte kind_char
- # Fix when UTF-8
- v.stream.write_byte self.ascii.to_b
- end
-end
-
-redef class String
- redef fun serialize_to_binary(v)
- do
- v.stream.write_byte kind_string
- v.stream.write_block self
+ for i in bytes do v.stream.write_byte i
end
end
-redef class NativeString
+redef class CString
redef fun serialize_to_binary(v)
do
- v.stream.write_byte kind_native_string
+ v.stream.write_byte kind_c_string
v.stream.write_block to_s
end
end
do
serialize_header_to_binary v
- core_serialize_to v
+ v.serialize_core self
v.stream.write_string "keys"
v.serialize_flat_array keys