929c330a59251dcb336d21a223a0453192def309
[nit.git] / lib / msgpack / msgpack.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # MessagePack, an efficient binary serialization format
16 #
17 # This modules provides services at different levels:
18 #
19 # * Serialize Nit objects using either the quick and easy `Serializable::serialize_msgpack`
20 # and `Write::serialize_msgpack`, or the extensible `MsgPackSerializer`.
21 #
22 # * Deserialize MessagePack to Nit objects using the quick and easy methods
23 # `Reader|Bytes::deserialize_msgpack`, or inspect errors with the extensible
24 # `MsgPackDeserializer`.
25 #
26 # * Read and write MessagePack data at a low-level (for engines and the likes)
27 # by importing `msgpack::read` or `msgpack::write`. These services support
28 # only which support only core Nit types with a corresponding MessagePack type.
29 # See `Reader::read_msgpack` and services on `Writer` including `write_msgpack_ext`.
30 #
31 # Here we discuss the recommended serialization services supporting core
32 # Nit and MessagePack types as well as full Nit objects.
33 #
34 # ## Primitive MessagePack types
35 #
36 # Most Nit core types are serialized to the smallest corresponding MessagePack type.
37 #
38 # ~~~
39 # assert false.serialize_msgpack == b"\xC2"
40 # assert b"\xC2".deserialize_msgpack == false
41 #
42 # assert true.serialize_msgpack == b"\xC3"
43 # assert b"\xC3".deserialize_msgpack == true
44 #
45 # assert 1.234.serialize_msgpack == b"\xCB\x3F\xF3\xBE\x76\xC8\xB4\x39\x58"
46 # assert b"\xCB\x3F\xF3\xBE\x76\xC8\xB4\x39\x58".deserialize_msgpack == 1.234
47 #
48 # assert "ABC".serialize_msgpack == b"\xA3ABC"
49 # assert b"\xA3ABC".deserialize_msgpack == "ABC"
50 #
51 # assert [0x11, 0x22, 0x33].serialize_msgpack(plain=true) == b"\x93\x11\x22\x33"
52 # assert b"\x93\x11\x22\x33".deserialize_msgpack == [0x11, 0x22, 0x33]
53 #
54 # var map = new Map[String, nullable Object]
55 # map["i"] = 1
56 # map["o"] = null
57 # assert map.serialize_msgpack(plain=true) == b"\x82\xA1\x69\x01\xA1\x6F\xC0"
58 # ~~~
59 #
60 # Ints are serialized to the smallest MessagePack type, so a small integer fits
61 # in a single byte and larger integers take more bytes as needed.
62 #
63 # ~~~
64 # assert 1.serialize_msgpack == b"\x01"
65 # assert (-32).serialize_msgpack == b"\xE0"
66 # assert 0x7F.serialize_msgpack == b"\x7F"
67 # assert 0x80.serialize_msgpack == b"\xCC\x80"
68 # assert 0x1234.serialize_msgpack == b"\xCD\x12\x34"
69 # assert (-0x1234).serialize_msgpack == b"\xD1\xED\xCC"
70 # assert 0x12345678.serialize_msgpack == b"\xCE\x12\x34\x56\x78"
71 # assert 0x0123456789.serialize_msgpack == b"\xCF\x00\x00\x00\x01\x23\x45\x67\x89"
72 #
73 # assert b"\x01".deserialize_msgpack == 1
74 # assert b"\xE0".deserialize_msgpack == -32
75 # assert b"\x7F".deserialize_msgpack == 0x7F
76 # assert b"\xCC\x80".deserialize_msgpack == 0x80
77 # assert b"\xCD\x12\x34".deserialize_msgpack == 0x1234
78 # assert b"\xD1\xED\xCC".deserialize_msgpack == -0x1234
79 # assert b"\xCE\x12\x34\x56\x78".deserialize_msgpack == 0x12345678
80 # assert b"\xCF\x00\x00\x00\x01\x23\x45\x67\x89".deserialize_msgpack == 0x0123456789
81 # ~~~
82 #
83 # ## Primitive Nit type without a MessagePack equivalent
84 #
85 # Chars are serialized as a string in plain mode.
86 #
87 # ~~~
88 # assert 'A'.serialize_msgpack(plain=true) == b"\xA1\x41"
89 # assert b"\xA1\x41".deserialize_msgpack == "A" # Not a Char
90 # ~~~
91 #
92 # Or, with metadata, chars are serialized to an ext with id 0x7C.
93 #
94 # ~~~
95 # assert 'A'.serialize_msgpack == b"\xD4\x7C\x41"
96 # assert b"\xD4\x7C\x41".deserialize_msgpack == 'A'
97 # ~~~
98 #
99 # Byte instances are serialized as an integer in plain mode.
100 #
101 # ~~~
102 # assert 0x01u8.serialize_msgpack(plain=true) == b"\x01"
103 # assert b"\x01".deserialize_msgpack == 1 # Not a Byte
104 # ~~~
105 #
106 # Or, with metadata, byte instances are serialized to an ext with id 0x7E.
107 #
108 # ~~~
109 # assert 0x01u8.serialize_msgpack == b"\xD4\x7E\x01"
110 # assert b"\xD4\x7E\x01".deserialize_msgpack == 0x01u8
111 # ~~~
112 #
113 # ## Full objects
114 #
115 # Objects are serialized to a map in plain mode, replacing cycles by `null` values.
116 # This creates plain MessagePack easy to read for other non-Nit programs,
117 # but cycles and the dynamic type information are lost.
118 #
119 # ~~~
120 # class A
121 # serialize
122 #
123 # var i = 1
124 # var o: nullable A = self
125 #
126 # redef fun ==(o) do return o isa A and o.i == i # Skip the cyclic `o`
127 # end
128 #
129 # var a = new A
130 # var bytes = a.serialize_msgpack(plain=true)
131 # assert bytes == b"\x82\xA1\x69\x01\xA1\x6F\xC0"
132 # assert bytes.deserialize_msgpack isa Map[nullable Serializable, nullable Serializable] # Not an A
133 # ~~~
134 #
135 # Or, with metadata, the same object is serialized with information on object
136 # uniqueness (with an id and references) and its dynamic type.
137 # The whole object is contained in a MessagePack array:
138 #
139 # * The array holds the metadata and attributes or each object,
140 # here it is a fixarray of 3 items: 0x93
141 # * Define an object (ext type 0x7B) with the id 0, here a fixext1: 0xD47B00
142 # * The dynamic type name, here a fixstr with the letter 'A': 0xA141
143 # * The attributes as a map, here a fixmap of 2 items: 0x82
144 # * First attribute name, here a fixstr for "i": 0xA169
145 # * First attribute value, here a fixint for 1: 0x01
146 # * Second attribute name, here a fixstr for "o": 0xA16F
147 # * Second attribute value, a reference (ext type 0x7D) to object id 0,
148 # here a fixext1: 0xD47D00
149 #
150 # ~~~
151 # bytes = a.serialize_msgpack
152 # assert bytes == b"\x93\xD4\x7B\x00\xA1\x41\x82\xA1\x69\x01\xA1\x6F\xD4\x7D\x00"
153 # assert bytes.deserialize_msgpack == a
154 # ~~~
155 #
156 # ## References
157 #
158 # Format description and other implementations: http://msgpack.org/
159 #
160 # Format specification: https://github.com/msgpack/msgpack/blob/master/spec.md
161 module msgpack
162
163 import serialization_write
164 import serialization_read