msgpack: intro entrypoint and package doc
authorAlexis Laferrière <alexis.laf@xymus.net>
Wed, 26 Jul 2017 02:36:32 +0000 (22:36 -0400)
committerAlexis Laferrière <alexis.laf@xymus.net>
Mon, 18 Sep 2017 19:28:29 +0000 (15:28 -0400)
Signed-off-by: Alexis Laferrière <alexis.laf@xymus.net>

lib/msgpack/msgpack.nit [new file with mode: 0644]
lib/msgpack/package.ini [new file with mode: 0644]

diff --git a/lib/msgpack/msgpack.nit b/lib/msgpack/msgpack.nit
new file mode 100644 (file)
index 0000000..929c330
--- /dev/null
@@ -0,0 +1,164 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# 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.
+
+# MessagePack, an efficient binary serialization format
+#
+# This modules provides services at different levels:
+#
+# * Serialize Nit objects using either the quick and easy `Serializable::serialize_msgpack`
+#   and `Write::serialize_msgpack`, or the extensible `MsgPackSerializer`.
+#
+# * Deserialize MessagePack to Nit objects using the quick and easy methods
+#   `Reader|Bytes::deserialize_msgpack`, or inspect errors with the extensible
+#   `MsgPackDeserializer`.
+#
+# * Read and write MessagePack data at a low-level (for engines and the likes)
+#   by importing `msgpack::read` or `msgpack::write`. These services support
+#   only which support only core Nit types with a corresponding MessagePack type.
+#   See `Reader::read_msgpack` and services on `Writer` including `write_msgpack_ext`.
+#
+# Here we discuss the recommended serialization services supporting core
+# Nit and MessagePack types as well as full Nit objects.
+#
+# ## Primitive MessagePack types
+#
+# Most Nit core types are serialized to the smallest corresponding MessagePack type.
+#
+# ~~~
+# assert false.serialize_msgpack == b"\xC2"
+# assert b"\xC2".deserialize_msgpack == false
+#
+# assert true.serialize_msgpack  == b"\xC3"
+# assert b"\xC3".deserialize_msgpack == true
+#
+# assert 1.234.serialize_msgpack == b"\xCB\x3F\xF3\xBE\x76\xC8\xB4\x39\x58"
+# assert b"\xCB\x3F\xF3\xBE\x76\xC8\xB4\x39\x58".deserialize_msgpack == 1.234
+#
+# assert "ABC".serialize_msgpack == b"\xA3ABC"
+# assert b"\xA3ABC".deserialize_msgpack == "ABC"
+#
+# assert [0x11, 0x22, 0x33].serialize_msgpack(plain=true) == b"\x93\x11\x22\x33"
+# assert b"\x93\x11\x22\x33".deserialize_msgpack == [0x11, 0x22, 0x33]
+#
+# var map = new Map[String, nullable Object]
+# map["i"] = 1
+# map["o"] = null
+# assert map.serialize_msgpack(plain=true) == b"\x82\xA1\x69\x01\xA1\x6F\xC0"
+# ~~~
+#
+# Ints are serialized to the smallest MessagePack type, so a small integer fits
+# in a single byte and larger integers take more bytes as needed.
+#
+# ~~~
+# assert 1.serialize_msgpack            == b"\x01"
+# assert (-32).serialize_msgpack        == b"\xE0"
+# assert 0x7F.serialize_msgpack         == b"\x7F"
+# assert 0x80.serialize_msgpack         == b"\xCC\x80"
+# assert 0x1234.serialize_msgpack       == b"\xCD\x12\x34"
+# assert (-0x1234).serialize_msgpack    == b"\xD1\xED\xCC"
+# assert 0x12345678.serialize_msgpack   == b"\xCE\x12\x34\x56\x78"
+# assert 0x0123456789.serialize_msgpack == b"\xCF\x00\x00\x00\x01\x23\x45\x67\x89"
+#
+# assert b"\x01".deserialize_msgpack                 == 1
+# assert b"\xE0".deserialize_msgpack                 == -32
+# assert b"\x7F".deserialize_msgpack                 == 0x7F
+# assert b"\xCC\x80".deserialize_msgpack             == 0x80
+# assert b"\xCD\x12\x34".deserialize_msgpack         == 0x1234
+# assert b"\xD1\xED\xCC".deserialize_msgpack         == -0x1234
+# assert b"\xCE\x12\x34\x56\x78".deserialize_msgpack == 0x12345678
+# assert b"\xCF\x00\x00\x00\x01\x23\x45\x67\x89".deserialize_msgpack == 0x0123456789
+# ~~~
+#
+# ## Primitive Nit type without a MessagePack equivalent
+#
+# Chars are serialized as a string in plain mode.
+#
+# ~~~
+# assert 'A'.serialize_msgpack(plain=true)      == b"\xA1\x41"
+# assert b"\xA1\x41".deserialize_msgpack == "A" # Not a Char
+# ~~~
+#
+# Or, with metadata, chars are serialized to an ext with id 0x7C.
+#
+# ~~~
+# assert 'A'.serialize_msgpack                      == b"\xD4\x7C\x41"
+# assert b"\xD4\x7C\x41".deserialize_msgpack == 'A'
+# ~~~
+#
+# Byte instances are serialized as an integer in plain mode.
+#
+# ~~~
+# assert 0x01u8.serialize_msgpack(plain=true) == b"\x01"
+# assert b"\x01".deserialize_msgpack   == 1 # Not a Byte
+# ~~~
+#
+# Or, with metadata, byte instances are serialized to an ext with id 0x7E.
+#
+# ~~~
+# assert 0x01u8.serialize_msgpack                   == b"\xD4\x7E\x01"
+# assert b"\xD4\x7E\x01".deserialize_msgpack == 0x01u8
+# ~~~
+#
+# ## Full objects
+#
+# Objects are serialized to a map in plain mode, replacing cycles by `null` values.
+# This creates plain MessagePack easy to read for other non-Nit programs,
+# but cycles and the dynamic type information are lost.
+#
+# ~~~
+# class A
+#     serialize
+#
+#     var i = 1
+#     var o: nullable A = self
+#
+#     redef fun ==(o) do return o isa A and o.i == i # Skip the cyclic `o`
+# end
+#
+# var a = new A
+# var bytes = a.serialize_msgpack(plain=true)
+# assert bytes == b"\x82\xA1\x69\x01\xA1\x6F\xC0"
+# assert bytes.deserialize_msgpack isa Map[nullable Serializable, nullable Serializable] # Not an A
+# ~~~
+#
+# Or, with metadata, the same object is serialized with information on object
+# uniqueness (with an id and references) and its dynamic type.
+# The whole object is contained in a MessagePack array:
+#
+# * The array holds the metadata and attributes or each object,
+#   here it is a fixarray of 3 items: 0x93
+# * Define an object (ext type 0x7B) with the id 0, here a fixext1: 0xD47B00
+# * The dynamic type name, here a fixstr with the letter 'A': 0xA141
+# * The attributes as a map, here a fixmap of 2 items: 0x82
+# * First attribute name, here a fixstr for "i": 0xA169
+# * First attribute value, here a fixint for 1: 0x01
+# * Second attribute name, here a fixstr for "o": 0xA16F
+# * Second attribute value, a reference (ext type 0x7D) to object id 0,
+#   here a fixext1: 0xD47D00
+#
+# ~~~
+# bytes = a.serialize_msgpack
+# assert bytes == b"\x93\xD4\x7B\x00\xA1\x41\x82\xA1\x69\x01\xA1\x6F\xD4\x7D\x00"
+# assert bytes.deserialize_msgpack == a
+# ~~~
+#
+# ## References
+#
+# Format description and other implementations: http://msgpack.org/
+#
+# Format specification: https://github.com/msgpack/msgpack/blob/master/spec.md
+module msgpack
+
+import serialization_write
+import serialization_read
diff --git a/lib/msgpack/package.ini b/lib/msgpack/package.ini
new file mode 100644 (file)
index 0000000..2820571
--- /dev/null
@@ -0,0 +1,11 @@
+[package]
+name=msgpack
+tags=format,lib
+maintainer=Alexis Laferrière <alexis.laf@xymus.net>
+license=Apache-2.0
+[upstream]
+browse=https://github.com/nitlang/nit/tree/master/lib/msgpack/
+git=https://github.com/nitlang/nit.git
+git.directory=lib/msgpack/
+homepage=http://nitlanguage.org
+issues=https://github.com/nitlang/nit/issues