3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

MessagePack 仕様 和訳

Last updated at Posted at 2023-11-03

MessagePack 仕様

このドキュメントは、MessagePackの仕様(MessagePack specification)の和訳です。

MessagePackは、JSONのようなオブジェクトをシリアライズするデータ交換フォーマットです。
MessagePackには、型システムフォーマットの2つの概念があります。

シリアライズとは、MessagePack型システムを介してアプリケーションオブジェクトからMessagePack形式へ変換することを指します。
デシリアライズとは、MessagePack型システムを介してMessagePack形式からアプリケーションオブジェクトへ変換することを指します。

シリアライズ:
    アプリケーションオブジェクト
    --> MessagePack型システム
    --> MessagePack形式(バイト配列)

デシリアライズ:
    MessagePack形式(バイト配列)
    --> MessagePack型システム
    --> アプリケーションオブジェクト

このドキュメントでは、MessagePack型システム、フォーマット、およびそれらの変換について説明します。

型システム

  • Integerは整数を表します。
  • Nilはnilを表します。
  • Booleanは真または偽を表します。
  • FloatはNaNとInfinityを含むIEEE 754倍精度浮動小数点数を表します。
  • Raw
    • Raw型を拡張したStringはUTF-8文字列を表します。
    • Raw型を拡張したBinaryはバイト配列を表します。
  • Arrayはオブジェクトのシーケンスを表します。
  • Mapはオブジェクトのキーと値のペアを表します。
  • ExtensionはアプリケーションやMessagePack仕様で定義される整数です。
    • Timestampは、タイムゾーンやカレンダーに依存しない、世界の時間軸上の時刻を表します。最大精度はナノ秒です。

TimestampUNIX時間のことです。

制限

  • Integerオブジェクトの値は -(2^63) から (2^64)-1 までです。
  • Binaryオブジェクトの最大長は (2^32)-1 です。
  • Stringオブジェクトの最大バイトサイズは (2^32)-1 です。
  • Stringオブジェクトは無効なバイト列を含む可能性があり、無効なバイト列を受け取ったときのデシリアライザの動作は実際の実装に依存します。
    • デシリアライザは、アプリケーションがオブジェクトをどのように扱うかを決定できるように、元のバイト配列を取得する機能を提供すべきです。
  • Arrayオブジェクトの最大要素数は (2^32)-1 です。
  • Mapオブジェクトのキーと値の関連付けの最大数は (2^32)-1 です。

拡張タイプ

MessagePackでは、Extension型を使用してアプリケーション固有のタイプを定義できます。
拡張タイプは整数とバイト配列で構成され、整数は型の種類を、バイト配列はデータを表します。

アプリケーションは、アプリケーション固有の型情報を0から127に割り当てることが出来ます。使い方の例として、アプリケーションが type = 0 をアプリケーション独自の型システムとして定義し、ペイロードに型の名前と型の値を格納します。

MessagePack は -1 から -128 を将来の拡張のために予約し、定義済みの型を追加します。これらの型は、異なるプログラミング環境間で事前に共有された静的に型付けされたスキーマを使用することなく、より多くの型を交換するために追加される予定です。

   0 - 127: アプリケーション固有の型
-128 -  -1: 定義済み型のために予約されている。

拡張型は追加されることを意図しているため、古いアプリケーションはそのすべてを実装していないかもしれません。しかし、そのような型でも拡張型の1つとして扱うことができます。そのため、アプリケーションは未知のExtension型を拒否するか、不透明なデータとして受け入れるか、ペイロードに触れずに他のアプリケーションに転送するかを決定することができます。

以下は、定義済みの拡張タイプのリストです。これらの型のフォーマットは、フォーマットセクションで定義されています。

名前
Timestamp -1

フォーマット

概要

フォーマット名 先頭バイト (2進数) 先頭バイト (16進数)
positive fixint 0xxxxxxx 0x00 - 0x7f
fixmap 1000xxxx 0x80 - 0x8f
fixarray 1001xxxx 0x90 - 0x9f
fixstr 101xxxxx 0xa0 - 0xbf
nil 11000000 0xc0
(利用不可) 11000001 0xc1
false 11000010 0xc2
true 11000011 0xc3
bin 8 11000100 0xc4
bin 16 11000101 0xc5
bin 32 11000110 0xc6
ext 8 11000111 0xc7
ext 16 11001000 0xc8
ext 32 11001001 0xc9
float 32 11001010 0xca
float 64 11001011 0xcb
uint 8 11001100 0xcc
uint 16 11001101 0xcd
uint 32 11001110 0xce
uint 64 11001111 0xcf
int 8 11010000 0xd0
int 16 11010001 0xd1
int 32 11010010 0xd2
int 64 11010011 0xd3
fixext 1 11010100 0xd4
fixext 2 11010101 0xd5
fixext 4 11010110 0xd6
fixext 8 11010111 0xd7
fixext 16 11011000 0xd8
str 8 11011001 0xd9
str 16 11011010 0xda
str 32 11011011 0xdb
array 16 11011100 0xdc
array 32 11011101 0xdd
map 16 11011110 0xde
map 32 11011111 0xdf
negative fixint 111xxxxx 0xe0 - 0xff

図の表記法

1バイト:
+--------+
|        |
+--------+

可変長のバイト:
+========+
|        |
+========+

可変長の、MessagePack形式で保存されるオブジェクト:
+~~~~~~~~~~~~~~~~~+
|                 |
+~~~~~~~~~~~~~~~~~+

XYZAは実際のビットに置き換えられる記号です。

nil

nilは1バイトにnilを格納します。

+--------+
|  0xc0  |
+--------+

boolフォーマットファミリ

boolフォーマットファミリは、1バイトにfalseまたはtrueを格納します。

false

+--------+
|  0xc2  |
+--------+

true

+--------+
|  0xc3  |
+--------+

intフォーマットファミリ

intフォーマットファミリは整数を1、2、3、5、または9バイトで格納します。

positive fixint

positive fixintは 7 ビットの正の整数を格納します
0XXXXXXXは8ビット符号なし整数です。

+--------+
|0XXXXXXX|
+--------+

negative fixint

negative fixintは5ビットの負の整数を格納します。
111YYYY は8ビット符号付き整数です。

+--------+
|111YYYYY|
+--------+

uint 8

uint 8は8ビット符号なし整数を格納します。

+--------+--------+
|  0xcc  |ZZZZZZZZ|
+--------+--------+

uint 16

uint 16は16ビットのビッグエンディアン符号なし整数を格納します。

+--------+--------+--------+
|  0xcd  |ZZZZZZZZ|ZZZZZZZZ|
+--------+--------+--------+

uint 32

uint 32は32ビットのビッグエンディアン符号なし整数を格納します。

+--------+--------+--------+--------+--------+
|  0xce  |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|
+--------+--------+--------+--------+--------+

uint 64

uint 64は64ビットのビッグエンディアン符号なし整数を格納します。

+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|  0xcf  |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|
+--------+--------+--------+--------+--------+--------+--------+--------+--------+

int 8

int 8は8ビットの符号付き整数を格納します。

+--------+--------+
|  0xd0  |ZZZZZZZZ|
+--------+--------+

int 16

int 16は16ビットのビッグエンディアン符号付き整数を格納します。

+--------+--------+--------+
|  0xd1  |ZZZZZZZZ|ZZZZZZZZ|
+--------+--------+--------+

int 32

int 32は32ビットのビッグエンディアン符号付き整数を格納します。

+--------+--------+--------+--------+--------+
|  0xd2  |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|
+--------+--------+--------+--------+--------+

int 64

int 64は64ビットのビッグエンディアン符号付き整数を格納します。

+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|  0xd3  |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|
+--------+--------+--------+--------+--------+--------+--------+--------+--------+

floatフォーマットファミリ

floatフォーマットファミリは、浮動小数点数を5バイトまたは9バイトで格納します。

float 32

float 32は、IEEE 754単精度浮動小数点数フォーマットで浮動小数点数を格納します。
XXXXXXXX_XXXXXXXX_XXXXXXXXはビッグエンディアンのIEEE 754単精度浮動小数点数です。単精度から倍精度に精度を拡張しても精度は落ちません。

+--------+--------+--------+--------+--------+
|  0xca  |XXXXXXXX|XXXXXXXX|XXXXXXXX|XXXXXXXX|
+--------+--------+--------+--------+--------+

float 64

float 64は、IEEE 754倍精度浮動小数点数フォーマットで浮動小数点数を格納します。
YYYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYYはビッグエンディアンのIEEE 754倍精度浮動小数点数です。

+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|  0xcb  |YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|
+--------+--------+--------+--------+--------+--------+--------+--------+--------+

strフォーマットファミリ

strフォーマットファミリは、バイト配列のサイズに加えて、1、2、3、または5バイトの追加バイトでバイト配列を格納します。

fixstr

fixstrは、最大31バイトのバイト配列を格納します。
XXXXXは5ビットの符号なし整数で、データの長さを表します。

+--------+========+
|101XXXXX|  data  |
+--------+========+

str 8

str 8は、最大(2^8)-1バイト(256バイト未満)のバイト配列を格納します。
YYYYYYYは8ビットの符号なし整数で、データの長さを表します。

+--------+--------+========+
|  0xd9  |YYYYYYYY|  data  |
+--------+--------+========+

str 16

str 16は、最大(2^16)-1バイト(64kB未満)のバイト配列を格納します。
ZZZZZZ_ZZZZZZZZは16ビットのビッグエンディアン符号なし整数で、データの長さを表します。

+--------+--------+--------+========+
|  0xda  |ZZZZZZZZ|ZZZZZZZZ|  data  |
+--------+--------+--------+========+

str 32

str 32は、最大(2^32)-1バイト(4GB未満)のバイト配列を格納します。
AAAAAAAAAA_AAAAAAAA_AAAAAAAAは32ビットのビッグエンディアン符号なし整数で、データの長さを表します。

+--------+--------+--------+--------+--------+========+
|  0xdb  |AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA|  data  |
+--------+--------+--------+--------+--------+========+

binフォーマットファミリ

binフォーマットファミリは、バイト配列のサイズに加えて、2バイト、3バイト、または5バイトの余分なバイトでバイト配列を格納します。

bin 8

bin 8は、最大(2^8)-1バイトのバイト配列を格納します。
XXXXXXXXはデータの長さを表す8ビットの符号なし整数です。

+--------+--------+========+
|  0xc4  |XXXXXXXX|  data  |
+--------+--------+========+

bin 16

bin 16は、最大(2^16)-1バイトのバイト配列を格納します。
YYYYYYY_YYYYYYYはデータの長さを表す16ビットのビッグエンディアン符号なし整数です。

+--------+--------+--------+========+
|  0xc5  |YYYYYYYY|YYYYYYYY|  data  |
+--------+--------+--------+========+

bin 32

bin 32は、最大(2^32)-1バイトのバイト配列を格納します。
ZZZZZZZZ_ZZZZZZZZ_ZZZZZZZZ_ZZZZZZZZはデータの長さを表す32ビットのビッグエンディアン符号なし整数です。

+--------+--------+--------+--------+--------+========+
|  0xc6  |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|  data  |
+--------+--------+--------+--------+--------+========+

arrayフォーマットファミリ

arrayフォーマットファミリは、要素に加えて1、3、または5バイトの余分なバイトに要素のシーケンスを格納します。

fixarray

fixarrayは、最大15要素の配列を格納します。
XXXXは配列のサイズ(N)を表す4ビットの符号なし整数です。

+--------+~~~~~~~~~~~~~~~~~+
|1001XXXX|    N objects    |
+--------+~~~~~~~~~~~~~~~~~+

array 16

array 16は、最大(2^16)-1要素の長さの配列を格納します。
YYYYYY_YYYYYYYは配列のサイズ(N)を表す16ビットのビッグエンディアン符号なし整数です。

+--------+--------+--------+~~~~~~~~~~~~~~~~~+
|  0xdc  |YYYYYYYY|YYYYYYYY|    N objects    |
+--------+--------+--------+~~~~~~~~~~~~~~~~~+

array 32

array 32は、最大(2^32)-1要素の長さの配列を格納します。
ZZZZZZZZ_ZZZZZZZZ_ZZZZZZZZ_ZZZZZZZZは配列のサイズ(N)を表す32ビットのビッグエンディアン符号なし整数です。

+--------+--------+--------+--------+--------+~~~~~~~~~~~~~~~~~+
|  0xdd  |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|    N objects    |
+--------+--------+--------+--------+--------+~~~~~~~~~~~~~~~~~+

mapフォーマットファミリ

mapフォーマットファミリは、キーと値のペアのシーケンスに加え、1、3、または5バイトの余分なバイトを格納します。
オブジェクトの奇数要素はマップのキーで、キーの次の要素に対応する値が格納されます。

fixmap

fixmapは、15要素までの長さのマップを格納します。
XXXXはマップのサイズ(N)を表す4ビットの符号なし整数です。

+--------+~~~~~~~~~~~~~~~~~+
|1000XXXX|   N*2 objects   |
+--------+~~~~~~~~~~~~~~~~~+

map 16

map 16は、(2^16)-1要素までの長さのマップを格納します。
YYYYYYY_YYYYYYYはマップのサイズ(N)を表す16ビットのビッグエンディアン符号なし整数です。

+--------+--------+--------+~~~~~~~~~~~~~~~~~+
|  0xde  |YYYYYYYY|YYYYYYYY|   N*2 objects   |
+--------+--------+--------+~~~~~~~~~~~~~~~~~+

map 32

map 32は、(2^32)-1要素までの長さのマップを格納します。
ZZZZZZZZ_ZZZZZZZZ_ZZZZZZZZ_ZZZZZZZZはマップのサイズ(N)を表す32ビットのビッグエンディアン符号なし整数です。

+--------+--------+--------+--------+--------+~~~~~~~~~~~~~~~~~+
|  0xdf  |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|   N*2 objects   |
+--------+--------+--------+--------+--------+~~~~~~~~~~~~~~~~~+

extフォーマットファミリ

extフォーマットファミリは、整数とバイト配列のタプルを格納します。

fixext 1

fixext 1は、整数と1バイトのバイト配列を格納します。

+--------+--------+--------+
|  0xd4  |  type  |  data  |
+--------+--------+--------+

fixext 2

fixext 2は、整数と2バイトのバイト配列を格納します。

+--------+--------+--------+--------+
|  0xd5  |  type  |       data      |
+--------+--------+--------+--------+

fixext 4

fixext 4は、整数と4バイトのバイト配列が格納します。

+--------+--------+--------+--------+--------+--------+
|  0xd6  |  type  |                data               |
+--------+--------+--------+--------+--------+--------+

fixext 8

fixext 8は、整数と8バイトのバイト配列を格納します。

+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|  0xd7  |  type  |                                  data                                 |
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+

fixext 16

fixext 16は、整数と16バイトのバイト配列を格納します。

--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|  0xd8  |  type  |                                  data
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+--------+--------+--------+--------+--------+--------+--------+--------+
                                 data                                   |
+--------+--------+--------+--------+--------+--------+--------+--------+

ext 8

ext 8は、整数と、長さが最大(2^8)-1バイトまでのバイト配列を格納します。
XXXXXXXXはデータの長さ(N)を表す8ビットの符号なし整数です。

+--------+--------+--------+========+
|  0xc7  |XXXXXXXX|  type  |  data  |
+--------+--------+--------+========+

ext 16

ext 16は、整数と、長さが最大(2^16)-1バイトまでのバイト配列を格納します。
YYYYYYY_YYYYYYYYはデータの長さ(N)を表す16ビットのビッグエンディアン符号なし整数です。

+--------+--------+--------+--------+========+
|  0xc8  |YYYYYYYY|YYYYYYYY|  type  |  data  |
+--------+--------+--------+--------+========+

ext 32

ext 32は、整数と、長さが最大(2^32)-1バイトまでのバイト配列を格納します。
ZZZZZZZZ_ZZZZZZZZ_ZZZZZZZZ_ZZZZZZZZはデータの長さ(N)を表すビッグエンディアンの32ビット符号なし整数です。

+--------+--------+--------+--------+--------+--------+========+
|  0xc9  |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|  type  |  data  |
+--------+--------+--------+--------+--------+--------+========+
  • typeは符号付き8ビット整数です。
  • 負のtypeは2バイトの型情報であり、将来の拡張のために予約されています。

timestamp

timestampは、拡張タイプ-1に割り当てられています。32ビット形式、64ビット形式、96ビット形式があります。

timestamp 32

timestamp 321970-01-01 00:00:00UTCからの経過秒数をを32ビットの符号なし整数に格納します
timestamp 321970-01-01 00:00:00 UTCから2106-02-07 06:28:16 UTCまで範囲のタイムスタンプを表すことができます。ナノ秒の部分は0です。

+--------+--------+--------+--------+--------+--------+
|  0xd6  |   -1   |   seconds in 32-bit unsigned int  |
+--------+--------+--------+--------+--------+--------+
timestamp 64

timestamp 641970-01-01 00:00:00 UTCからの経過秒数とナノ秒数を64ビットの符号なし整数に格納します
timestamp 641970-01-01 00:00:00.000000000 UTCから2514-05-30 01:53:04.000000000 UTCまで範囲のタイムスタンプを表すことができます。

+--------+--------+--------+--------+--------+------|-+--------+--------+--------+--------+
|  0xd7  |   -1   | nanosec. in 30-bit unsigned int |   seconds in 34-bit unsigned int    |
+--------+--------+--------+--------+--------+------^-+--------+--------+--------+--------+
timestamp 96

timestamp 961970-01-01 00:00:00 UTCからの経過秒数とナノ秒数を64ビット符号付き整数と32ビット符号なし整数に格納します
timestamp 96-292277022657-01-27 08:29:52 UTCから292277026596-12-04 15:30:08.000000000 UTCまで範囲のタイムスタンプを表すことができます。

+--------+--------+--------+--------+--------+--------+--------+
|  0xc7  |   12   |   -1   |nanoseconds in 32-bit unsigned int |
+--------+--------+--------+--------+--------+--------+--------+
+--------+--------+--------+--------+--------+--------+--------+--------+
                    seconds in 64-bit signed int                        |
+--------+--------+--------+--------+--------+--------+--------+--------+
  • timestamp 64およびtimestamp 96フォーマットでは、ナノ秒は最大9999999です。
シリアライズの疑似コード
struct timespec {
    long tv_sec;  // seconds
    long tv_nsec; // nanoseconds
} time;
if ((time.tv_sec >> 34) == 0) {
    uint64_t data64 = (time.tv_nsec << 34) | time.tv_sec;
    if (data64 & 0xffffffff00000000L == 0) {
        // timestamp 32
        uint32_t data32 = data64;
        serialize(0xd6, -1, data32)
    }
    else {
        // timestamp 64
        serialize(0xd7, -1, data64)
    }
}
else {
    // timestamp 96
    serialize(0xc7, 12, -1, time.tv_nsec, time.tv_sec)
}
デシリアライズの疑似コード
ExtensionValue value = deserialize_ext_type();
struct timespec result;
switch(value.length) {
case 4:
    uint32_t data32 = value.payload;
    result.tv_nsec = 0;
    result.tv_sec = data32;
case 8:
    uint64_t data64 = value.payload;
    result.tv_nsec = data64 >> 34;
    result.tv_sec = data64 & 0x00000003ffffffffL;
case 12:
    uint32_t data32 = value.payload;
    uint64_t data64 = value.payload + 4;
    result.tv_nsec = data32;
    result.tv_sec = data64;
default:
    // error
}

シリアライズ: 型からフォーマットへの変換

MessagePackシリアライザは、MessagePack型を以下のようなフォーマットに変換します。

入力型 出力フォーマット
Integer intフォーマットファミリ (positive fixint, negative fixint, int 8/16/32/64 または uint 8/16/32/64)
Nil nil
Boolean boolフォーマットファミリ (falseまたはtrue)
Float floatフォーマットファミリ (float 32/64)
String strフォーマットファミリ (fixstrまたはstr 8/16/32)
Binary binフォーマットファミリ (bin 8/16/32)
Array arrayフォーマットファミリ (fixarrayまたはarray 16/32)
Map mapフォーマットファミリ (fixmapまたはmap 16/32)
Extension extフォーマットファミリ (fixextまたはext 8/16/32)

オブジェクトが複数の出力フォーマットで表現できる場合、シリアライザーは最小のバイト数でデータを表現するフォーマットを使用すべきです(SHOULD)。

デシリアライズ: フォーマットから型への変換

MessagePackデシリアライザは MessagePackのフォーマットを以下のような型に変換します。

入力フォーマット 出力型
positive fixint, negative fixint, int 8/16/32/64 または uint 8/16/32/64 Integer
nil Nil
falseまたはtrue Boolean
float 32/64 Float
fixstrまたはstr 8/16/32 String
bin 8/16/32 Binary
fixarrayまたはarray 16/32 Array
fixmapまたはmap 16/32 Map
fixextまたはext 8/16/32 Extension

将来の議論

プロファイル

プロファイルとは、MessagePackを特定のユースケースに適応させるために、同じシンタックスを共有しながら、アプリケーションによって MessagePack のセマンティクスを制限するアイデアです。

例えば、アプリケーションはBinary型を削除し、mapオブジェクトのキーをString型に制限し、JSONとセマンティクスを互換にするためにいくつかの制限を加えることができます。スキーマを使用するアプリケーションでは、String型とBinary型を削除し、Raw型としてバイト配列を扱うことができます。直列化されたデータのハッシュ(ダイジェスト)を使用するアプリケーションは、直列化されたデータを確定的にするために、マップのキーをソートすることができる。

実装ガイドライン

MessagePack 仕様のアップグレード

現在、MessagePackの仕様が変更されています。
以下は既存のMessagePack実装をアップグレードするためのガイドラインです。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?