MessagePack 仕様 和訳

# MessagePack 仕様

> このドキュメントは、[MessagePack](https://msgpack.org/)の仕様([MessagePack specification](https://github.com/msgpack/msgpack/blob/9aa092d6ca81f12005bd7dcbeb6488ad319e5133/spec.md))の和訳です。

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

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

```plaintext
シリアライズ：
    アプリケーションオブジェクト
    --> 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**は、タイムゾーンやカレンダーに依存しない、世界の時間軸上の時刻を表します。最大精度はナノ秒です。

> **Timestamp**は[UNIX時間](https://ja.wikipedia.org/wiki/UNIX%E6%99%82%E9%96%93)のことです。

### 制限

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

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

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

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

|名前|型|
|:--|:--|
|**Timestamp**|-1|

## フォーマット

### 概要

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

### 図の表記法

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

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

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

`X`、`Y`、`Z`、`A`は実際のビットに置き換えられる記号です。

### `nil`

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

```plaintext
+--------+
|  0xc0  |
+--------+
```

### boolフォーマットファミリ

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

#### `false`

```plaintext
+--------+
|  0xc2  |
+--------+
```

#### `true`

```plaintext
+--------+
|  0xc3  |
+--------+
```

### intフォーマットファミリ

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

#### `positive fixint`

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

```plaintext
+--------+
|0XXXXXXX|
+--------+
```

#### `negative fixint`

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

```plaintext
+--------+
|111YYYYY|
+--------+
```

#### `uint 8`

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

```plaintext
+--------+--------+
|  0xcc  |ZZZZZZZZ|
+--------+--------+
```

#### `uint 16`

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

```plaintext
+--------+--------+--------+
|  0xcd  |ZZZZZZZZ|ZZZZZZZZ|
+--------+--------+--------+
```

#### `uint 32`

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

```plaintext
+--------+--------+--------+--------+--------+
|  0xce  |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|
+--------+--------+--------+--------+--------+
```

#### `uint 64`

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

```plaintext
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|  0xcf  |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
```

#### `int 8`

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

```plaintext
+--------+--------+
|  0xd0  |ZZZZZZZZ|
+--------+--------+
```

#### `int 16`

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

```plaintext
+--------+--------+--------+
|  0xd1  |ZZZZZZZZ|ZZZZZZZZ|
+--------+--------+--------+
```

#### `int 32`

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

```plaintext
+--------+--------+--------+--------+--------+
|  0xd2  |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|
+--------+--------+--------+--------+--------+
```

#### `int 64`

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

```plaintext
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|  0xd3  |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
```

### floatフォーマットファミリ

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

#### `float 32`

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

```plaintext
+--------+--------+--------+--------+--------+
|  0xca  |XXXXXXXX|XXXXXXXX|XXXXXXXX|XXXXXXXX|
+--------+--------+--------+--------+--------+
```

#### `float 64`

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

```plaintext
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|  0xcb  |YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
```

### strフォーマットファミリ

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

#### `fixstr`

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

```plaintext
+--------+========+
|101XXXXX|  data  |
+--------+========+
```

#### `str 8`

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

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

#### `str 16`

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

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

#### `str 32`

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

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

### binフォーマットファミリ

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

#### `bin 8`

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

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

#### `bin 16`

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

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

#### `bin 32`

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

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

### arrayフォーマットファミリ

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

#### `fixarray`

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

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

#### `array 16`

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

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

#### `array 32`

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

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

### mapフォーマットファミリ

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

#### `fixmap`

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

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

#### `map 16`

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

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

#### `map 32`

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

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

### extフォーマットファミリ

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

#### `fixext 1`

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

```plaintext
+--------+--------+--------+
|  0xd4  |  type  |  data  |
+--------+--------+--------+
```

#### `fixext 2`

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

```plaintext
+--------+--------+--------+--------+
|  0xd5  |  type  |       data      |
+--------+--------+--------+--------+
```

#### `fixext 4`

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

```plaintext
+--------+--------+--------+--------+--------+--------+
|  0xd6  |  type  |                data               |
+--------+--------+--------+--------+--------+--------+
```

#### `fixext 8`

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

```plaintext
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|  0xd7  |  type  |                                  data                                 |
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
```

#### `fixext 16`

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

```plaintext
--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|  0xd8  |  type  |                                  data
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+--------+--------+--------+--------+--------+--------+--------+--------+
                                 data                                   |
+--------+--------+--------+--------+--------+--------+--------+--------+
```

#### `ext 8`

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

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

#### `ext 16`

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

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

#### `ext 32`

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

```plaintext
+--------+--------+--------+--------+--------+--------+========+
|  0xc9  |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|  type  |  data  |
+--------+--------+--------+--------+--------+--------+========+
```

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

#### `timestamp`

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

##### `timestamp 32`

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

```plaintext
+--------+--------+--------+--------+--------+--------+
|  0xd6  |   -1   |   seconds in 32-bit unsigned int  |
+--------+--------+--------+--------+--------+--------+
```

##### `timestamp 64`

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

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

##### `timestamp 96`

`timestamp 96`は`1970-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`まで範囲のタイムスタンプを表すことができます。

```plaintext
+--------+--------+--------+--------+--------+--------+--------+
|  0xc7  |   12   |   -1   |nanoseconds in 32-bit unsigned int |
+--------+--------+--------+--------+--------+--------+--------+
+--------+--------+--------+--------+--------+--------+--------+--------+
                    seconds in 64-bit signed int                        |
+--------+--------+--------+--------+--------+--------+--------+--------+
```

- `timestamp 64`および`timestamp 96`フォーマットでは、ナノ秒は最大9999999です。

<details>
<summary>シリアライズの疑似コード</summary>

```c++
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)
}
```

</details>

<details>
<summary>デシリアライズの疑似コード</summary>

```c++
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
}
```
</details>

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

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

| 入力型 | 出力フォーマット  |
|:---|:---|
| **Integer**    | [intフォーマットファミリ](#intフォーマットファミリ) (`positive fixint`, `negative fixint`, `int 8/16/32/64` または `uint 8/16/32/64`) |
| **Nil**        | `nil` |
| **Boolean**    | [boolフォーマットファミリ](#boolフォーマットファミリ) (`false`または`true`) |
| **Float**      | [floatフォーマットファミリ](#floatフォーマットファミリ) (`float 32/64`) |
| **String**     | [strフォーマットファミリ](#strフォーマットファミリ) (`fixstr`または`str 8/16/32`) |
| **Binary**     | [binフォーマットファミリ](#binフォーマットファミリ) (`bin 8/16/32`) |
| **Array**      | [arrayフォーマットファミリ](#arrayフォーマットファミリ) (`fixarray`または`array 16/32`) |
| **Map**        | [mapフォーマットファミリ](#mapフォーマットファミリ) (`fixmap`または`map 16/32`) |
| **Extension**  | [extフォーマットファミリ](#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実装をアップグレードするためのガイドラインです。

- マイナーリリースでは、デシリアライザは[binフォーマットファミリー](#binフォーマットファミリ)と[`str 8`](#str-8)フォーマットをサポートします。デシリアライズされるオブジェクトの型は `raw 16` (== [`str 16`](#str-16)) または `raw 32` (== [`str 32`](#str-32)) と同じでなければなりません。
- メジャーリリースでは、デシリアライザは[binフォーマットファミリー](#binフォーマットファミリ)と[strフォーマットファミリー](#strフォーマットファミリ)を使用して**Binary**型と**String**型を区別します。
  - 同時に、シリアライザは[binフォーマットファミリー](#binフォーマットファミリ)と[`str 8`](#str-8)フォーマットを使用しない "互換モード"を提供すべきである。