Low-level read MessagePack format from Reader streams

Redefined classes

redef abstract class Reader

msgpack :: read $ Reader

A Stream that can be read from

All class definitions

redef abstract class Reader

msgpack :: read $ Reader

A Stream that can be read from
package_diagram msgpack::read read binary binary msgpack::read->binary msgpack::ext ext msgpack::read->msgpack::ext core core binary->core serialization serialization msgpack::ext->serialization ...core ... ...core->core ...serialization ... ...serialization->serialization msgpack::serialization_read serialization_read msgpack::serialization_read->msgpack::read msgpack::msgpack_to_json msgpack_to_json msgpack::msgpack_to_json->msgpack::read msgpack::msgpack msgpack msgpack::msgpack->msgpack::serialization_read msgpack::msgpack... ... msgpack::msgpack...->msgpack::msgpack a_star-m a_star-m a_star-m->msgpack::msgpack_to_json a_star-m... ... a_star-m...->a_star-m


module abstract_collection

core :: abstract_collection

Abstract collection classes and services.
module abstract_text

core :: abstract_text

Abstract class for manipulation of sequences of characters
module array

core :: array

This module introduces the standard array structure.
module bitset

core :: bitset

Services to handle BitSet
module bytes

core :: bytes

Services for byte streams and arrays
module caching

serialization :: caching

Services for caching serialization engines
module circular_array

core :: circular_array

Efficient data structure to access both end of the sequence.
module codec_base

core :: codec_base

Base for codecs to use with streams
module codecs

core :: codecs

Group module for all codec-related manipulations
module collection

core :: collection

This module define several collection classes.
module core

core :: core

Standard classes and methods used by default by Nit programs and libraries.
module engine_tools

serialization :: engine_tools

Advanced services for serialization engines
module environ

core :: environ

Access to the environment variables of the process
module error

core :: error

Standard error-management infrastructure.
module exec

core :: exec

Invocation and management of operating system sub-processes.
module file

core :: file

File manipulations (create, read, write, etc.)
module fixed_ints

core :: fixed_ints

Basic integers of fixed-precision
module fixed_ints_text

core :: fixed_ints_text

Text services to complement fixed_ints
module flat

core :: flat

All the array-based text representations
module gc

core :: gc

Access to the Nit internal garbage collection mechanism
module hash_collection

core :: hash_collection

Introduce HashMap and HashSet.
module inspect

serialization :: inspect

Refine Serializable::inspect to show more useful information
module iso8859_1

core :: iso8859_1

Codec for ISO8859-1 I/O
module kernel

core :: kernel

Most basic classes and methods.
module list

core :: list

This module handle double linked lists
module math

core :: math

Mathematical operations
module meta

meta :: meta

Simple user-defined meta-level to manipulate types of instances as object.
module native

core :: native

Native structures for text and bytes
module numeric

core :: numeric

Advanced services for Numeric types
module protocol

core :: protocol

module queue

core :: queue

Queuing data structures and wrappers
module range

core :: range

Module for range of discrete objects.
module re

core :: re

Regular expression support for all services based on Pattern
module ropes

core :: ropes

Tree-based representation of a String.
module serialization

serialization :: serialization

General serialization services
module serialization_core

serialization :: serialization_core

Abstract services to serialize Nit objects to different formats
module sorter

core :: sorter

This module contains classes used to compare things and sorts arrays.
module stream

core :: stream

Input and output streams of characters
module text

core :: text

All the classes and methods related to the manipulation of text entities
module time

core :: time

Management of time and dates
module union_find

core :: union_find

union–find algorithm using an efficient disjoint-set data structure
module utf8

core :: utf8

Codec for UTF-8 I/O


module binary

binary :: binary

Read and write binary data with any Reader and Writer
module ext

msgpack :: ext

Application specific MessagePack extension MsgPackExt


module msgpack_to_json

msgpack :: msgpack_to_json

Convert MessagePack format to JSON
module serialization_read

msgpack :: serialization_read

Deserialize full Nit objects from MessagePack format


module a_star-m


module client

gamnit :: client

Client-side network services for games and such
module common

gamnit :: common

Services common to the client and server modules
module msgpack

msgpack :: msgpack

MessagePack, an efficient binary serialization format
module network

gamnit :: network

Easy client/server logic for games and simple distributed applications
module server

gamnit :: server

Server-side network services for games and such
# Low-level read MessagePack format from `Reader` streams
module read

import serialization
private import binary

import ext

redef class Reader

	# Read the next MessagePack object and return it as a simple Nit object
	# The return value is composed of:
	# * the simple types `null`, `Bool`, `Int`, `Float`, `String` and `Bytes`,
	# * collections of simple Nit objects `Array[nullable Serializable]`
	#   and `Map[nullable Serializable, nullable Serializable]`,
	# * and `MsgPackExt` for custom MessagePack *ext* data.
	# This method reads plain MessagePack data, as written by `MsgPackSerializer`
	# when `plain_msgpack == true`. To deserialize full Nit objects from
	# MessagePack with metadata use `Reader::deserialize_msgpack`.
	fun read_msgpack: nullable Serializable
		if last_error != null then return 0

		var typ = read_byte
		if typ < 0 then
			# Error, return default `null`
			return null

		else if typ & 0b1000_0000 == 0 or typ & 0b1110_0000 == 0b1110_0000 then
			# fixint
			var bytes = new Bytes.with_capacity(1)
			bytes.add typ
			return bytes.to_i(signed=true)

		else if typ & 0b1111_0000 == 0b1000_0000 then
			# fixmap
			var len = typ & 0b0000_1111
			return read_msgpack_map_data(len.to_i)

		else if typ & 0b1111_0000 == 0b1001_0000 then
			# fixarray
			var len = typ & 0b0000_1111
			return read_msgpack_array_data(len.to_i)

		else if typ & 0b1110_0000 == 0b1010_0000 then
			# fixstr
			var len = typ & 0b0001_1111
			return read_bytes(len.to_i).to_s

		else if typ == 0xC0 then
			return null
		else if typ == 0xC2 then
			return false
		else if typ == 0xC3 then
			return true

		else if typ >= 0xCC and typ <= 0xCF then
			# uint8, 16, 32 and 64
			var len = 1 << (typ - 0xCC)
			return read_bytes(len).to_i

		else if typ >= 0xD0 and typ <= 0xD3 then
			# int8, 16, 32 and 64
			var len = 1 << (typ - 0xD0)
			return read_bytes(len).to_i(true)

		else if typ == 0xCA then
			return read_float
		else if typ == 0xCB then
			return read_double

		else if typ >= 0xD9 and typ <= 0xDB then
			# str8, 16 and 32
			var len_ln = 1 << (typ - 0xD9)
			var bf = read_bytes(len_ln)
			var len = bf.to_i
			if len < 0 then return null
			var rd_buf = read_bytes(len)
			if rd_buf.length != len then
				# Bad formatted message.
				return null
			return rd_buf.to_s

		else if typ >= 0xC4 and typ <= 0xC6 then
			# bin8, 16 or 32
			var len_ln = 1 << (typ - 0xC4)
			var bf = read_bytes(len_ln)
			var len = bf.to_i
			if len < 0 then return null
			var rd_buf = read_bytes(len)
			if rd_buf.length != len then
				# Bad formatted message.
				return null
			return rd_buf

		else if typ == 0xDC or typ == 0xDD then
			# array16 and array32
			var len_ln = 2 << (typ - 0xDC)
			var lenbuf = read_bytes(len_ln)
			return read_msgpack_array_data(lenbuf.to_i)

		else if typ == 0xDE or typ == 0xDF then
			# map16 and map32
			var len_ln = 2 << (typ - 0xDE)
			var lenbuf = read_bytes(len_ln)
			return read_msgpack_map_data(lenbuf.to_i)

		else if typ == 0xD4 then
			# fixext1
			return read_msgpack_fixext_data(1)
		else if typ == 0xD5 then
			# fixext2
			return read_msgpack_fixext_data(2)
		else if typ == 0xD6 then
			# fixext4
			return read_msgpack_fixext_data(4)
		else if typ == 0xD7 then
			# fixext8
			return read_msgpack_fixext_data(8)
		else if typ == 0xD8 then
			# fixext16
			return read_msgpack_fixext_data(16)

		else if typ == 0xC7 then
			# ext1
			return read_msgpack_ext_data(1)
		else if typ == 0xC8 then
			# ext2
			return read_msgpack_ext_data(2)
		else if typ == 0xC9 then
			# ext4
			return read_msgpack_ext_data(4)

		print_error "MessagePack Warning: Found no match for typ {typ.to_base(16)} / 0b{typ.to_base(2)}"
		return null

	# Read the content of a map, `len` keys and values
	private fun read_msgpack_map_data(len: Int): Map[nullable Serializable, nullable Serializable]
		var map = new Map[nullable Serializable, nullable Serializable]
		for i in [0..len.to_i[ do map[read_msgpack] = read_msgpack
		return map

	# Read the content of an array of `len` items
	private fun read_msgpack_array_data(len: Int): Array[nullable Serializable]
		return [for i in [0..len[ do read_msgpack]

	# Read the content of a *fixext* of `len` bytes
	# ~~~
	# var reader = new BytesReader(b"\xC7\x03\x0A\x0B\x0C\x0D")
	# var ext = reader.read_msgpack
	# assert ext isa MsgPackExt
	# assert ext.typ == 0x0a
	# assert ext.data == b"\x0B\x0C\x0D"
	# ~~~
	private fun read_msgpack_fixext_data(len: Int): MsgPackExt
		var exttyp = read_byte
		if exttyp < 0 then exttyp = 0
		var data = read_bytes(len)
		return new MsgPackExt(exttyp, data)

	# Read the content of a dynamic *ext* including the length on `len_len` bytes
	private fun read_msgpack_ext_data(len_len: Int): MsgPackExt
		var len = read_bytes(len_len).to_i
		return read_msgpack_fixext_data(len)