# 機能設計書 47-MessagePack

## 概要

本ドキュメントは、NushellにおけるMessagePack形式のデータ変換機能（`from msgpack`および`to msgpack`コマンド）の詳細設計を記載する。MessagePackは効率的なバイナリシリアライズフォーマットであり、JSONより高速かつコンパクトなデータ交換を可能にする。

### 本機能の処理概要

MessagePack変換機能は、バイナリ形式のMessagePackデータとNushellのValue間の相互変換を提供する。日時はMessagePackのtimestamp拡張型を使用し、バイナリデータもネイティブにサポートされる。

**業務上の目的・背景**：MessagePackはJSONと同様の構造を持ちながら、バイナリ形式でより効率的なシリアライズ/デシリアライズが可能である。ネットワーク通信、キャッシュ、高速なデータ永続化などに使用される。

**機能の利用シーン**：
- 高速なデータシリアライズ/デシリアライズ
- バイナリプロトコルでのデータ交換
- キャッシュデータの保存
- ネットワーク通信でのペイロード圧縮

**主要な処理内容**：
1. `from msgpack`: MessagePackバイナリをNushell Valueに変換
2. `from msgpack --objects`: 複数オブジェクトを連続で読み込み
3. `to msgpack`: Nushell ValueをMessagePackバイナリに変換
4. `to msgpack --serialize`: クロージャ等を文字列化

**関連システム・外部連携**：rmpクレート（MessagePackライブラリ）を使用。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | CLI専用機能のため画面なし |

## 機能種別

データ変換 / フォーマット変換

## 入力仕様

### 入力パラメータ

#### from msgpack

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| input | Binary | Yes | MessagePackバイナリ（パイプライン入力） | 有効なMessagePack形式 |
| --objects | Switch | No | 複数オブジェクトを連続で読み込み | - |

#### to msgpack

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| input | Any | Yes | 変換対象データ（パイプライン入力） | - |
| --serialize / -s | Switch | No | 非シリアライズ可能型を文字列化 | - |

### 入力データソース

パイプライン入力（from: Binary型/ByteStream、to: Any型）

## 出力仕様

### 出力データ

#### from msgpack

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | Any | パースされたNushell Value |

対応データ型:
- int（u8/u16/u32/u64/i8/i16/i32/i64）
- float（f32/f64）
- bool, null
- string, binary
- array（list）, map（record）
- timestamp拡張型（datetime）

#### to msgpack

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | Binary | MessagePackバイナリデータ |

### 出力先

標準出力（パイプライン出力）。to msgpackはcontent_type: "application/x-msgpack"メタデータを付与。

## 処理フロー

### 処理シーケンス

```
from msgpack:
1. パイプライン入力を受け取る
   └─ Binary型またはByteStreamを期待
2. Optsを構築
   └─ objects, signals設定
3. read_msgpack関数を呼び出し
   └─ 単一/複数オブジェクトモード分岐
4. read_value関数で再帰的に変換
   └─ マーカーに基づいて型判定
5. 拡張型の処理
   └─ timestamp(-1)を日時に変換

to msgpack:
1. パイプライン入力を受け取る
   └─ Any型を期待
2. write_value関数で再帰的に変換
   └─ 型に応じてMessagePack形式で書き込み
3. 日時はtimestamp拡張型で出力
   └─ 32bit/96bit形式を選択
4. メタデータを付与
   └─ content_type: application/x-msgpack
```

### フローチャート

```mermaid
flowchart TD
    subgraph from_msgpack ["from msgpack"]
        A1[入力: Binary] --> B1{--objects?}
        B1 -->|Yes| C1[read_msgpack iter]
        B1 -->|No| D1[read_msgpack single]
        C1 --> E1[read_value再帰]
        D1 --> E1
        E1 --> F1{マーカー判定}
        F1 -->|Int| G1[Value::int]
        F1 -->|Float| H1[Value::float]
        F1 -->|Str| I1[Value::string]
        F1 -->|Bin| J1[Value::binary]
        F1 -->|Array| K1[read_array再帰]
        F1 -->|Map| L1[read_map再帰]
        F1 -->|Ext -1| M1[timestamp→datetime]
        G1 --> N1[Value出力]
        H1 --> N1
        I1 --> N1
        J1 --> N1
        K1 --> N1
        L1 --> N1
        M1 --> N1
    end

    subgraph to_msgpack ["to msgpack"]
        A2[入力: Value] --> B2[write_value]
        B2 --> C2{型判定}
        C2 -->|Bool| D2[write_bool]
        C2 -->|Int| E2[write_sint]
        C2 -->|Float| F2[write_f64]
        C2 -->|String| G2[write_str]
        C2 -->|Binary| H2[write_bin]
        C2 -->|Date| I2[write_ext timestamp]
        C2 -->|List| J2[write_array再帰]
        C2 -->|Record| K2[write_map再帰]
        C2 -->|Range| L2[リスト展開後write_array]
        D2 --> M2[Binary出力 + metadata]
        E2 --> M2
        F2 --> M2
        G2 --> M2
        H2 --> M2
        I2 --> M2
        J2 --> M2
        K2 --> M2
        L2 --> M2
    end
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-47-01 | 最大深度制限 | ネストは最大50レベルまで | from/to msgpack |
| BR-47-02 | timestamp拡張型 | type=-1をdatetimeとして処理 | from/to msgpack |
| BR-47-03 | timestamp形式選択 | ナノ秒なし+範囲内は32bit、それ以外は96bit | to msgpack |
| BR-47-04 | マップキー制約 | マップのキーは文字列のみ対応 | from msgpack |
| BR-47-05 | バイナリ入力 | Binary型またはByteStreamを受け付け | from msgpack |
| BR-47-06 | 複数オブジェクト | --objectsでEOFまで連続読み込み | from msgpack --objects |
| BR-47-07 | EOF検証 | 単一モードではEOF後の余剰データをエラー | from msgpack |
| BR-47-08 | Range展開 | Rangeはリストに展開して出力 | to msgpack |

### 計算ロジック

**timestamp拡張型のフォーマット**:
- **timestamp 32** (4バイト): u32秒のみ、ナノ秒なし、秒が0〜2^32-1の範囲
- **timestamp 64** (8バイト): u64にナノ秒(上位30bit)と秒(下位34bit)をパック
- **timestamp 96** (12バイト): u32ナノ秒 + i64秒

**型マッピング**:
| MessagePack | Nushell |
|-------------|---------|
| fixnum/int | int |
| float32/64 | float |
| nil | nothing |
| bool | bool |
| str | string |
| bin | binary |
| array | list |
| map | record |
| ext(-1) | datetime |
| other ext | エラー |

## データベース操作仕様

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| GenericError | MaxDepth | ネストが50を超えた | データ構造を浅くする |
| GenericError | InvalidMarker | 不正なマーカー | MessagePack形式を確認 |
| GenericError | u64オーバーフロー | u64がi64範囲外 | データ値を確認 |
| GenericError | 非文字列キー | マップに非文字列キー | 文字列キーのみ使用 |
| GenericError | 未知の拡張型 | timestamp以外の拡張型 | timestamp(-1)のみ対応 |
| NonUtf8Custom | UTF-8エラー | 文字列がUTF-8でない | UTF-8エンコーディング |
| UnsupportedInput | クロージャ | --serializeなしでクロージャ | --serializeを使用 |
| PipelineMismatch | 入力型不正 | Binary/ByteStream以外 | Binary入力を使用 |

### リトライ仕様

リトライは不要。

## トランザクション仕様

本機能はトランザクション処理を行わない。

## パフォーマンス要件

- バイナリ形式のためJSONより高速なパース/シリアライズ
- ByteStreamから直接読み込み可能（全体をメモリにロードしない）
- 最大深度制限によりスタックオーバーフローを防止

## セキュリティ考慮事項

- 深度制限（MAX_DEPTH=50）による再帰攻撃の防止
- 不正なマーカーや拡張型に対するエラーハンドリング

## 備考

- rmpクレートを使用したハンドクラフトなデシリアライズ実装
- serde非依存で直接Value型に変換
- 元のアイデアは nu_plugin_msgpack プラグインから

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: コマンドインターフェースを理解する

コマンドの定義とパラメータを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | msgpack.rs (from) | `crates/nu-command/src/formats/from/msgpack.rs` | FromMsgpack構造体（19-143行目） |
| 1-2 | msgpack.rs (to) | `crates/nu-command/src/formats/to/msgpack.rs` | ToMsgpack構造体（14-104行目） |

**読解のコツ**: from msgpackがBinary入力とByteStreamの両方に対応していること、--objectsフラグで複数オブジェクト読み込みモードになることを理解する。

#### Step 2: from msgpackのパース処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | msgpack.rs | `crates/nu-command/src/formats/from/msgpack.rs` | read_msgpack関数（236-274行目） |
| 2-2 | msgpack.rs | `crates/nu-command/src/formats/from/msgpack.rs` | read_value関数（276-390行目） |
| 2-3 | msgpack.rs | `crates/nu-command/src/formats/from/msgpack.rs` | read_ext関数（440-470行目） |

**主要処理フロー**:
1. **236-274行目**: 単一/複数オブジェクトモードの分岐
2. **282-284行目**: マーカーの読み取り
3. **290-388行目**: マーカーに基づく型判定と変換
4. **440-470行目**: timestamp拡張型の処理（32/64/96bit）

#### Step 3: to msgpackの変換処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | msgpack.rs | `crates/nu-command/src/formats/to/msgpack.rs` | write_value関数（161-299行目） |

**主要処理フロー**:
- **176-180行目**: bool型の書き込み
- **181-192行目**: 整数型（int, filesize, duration）
- **193-209行目**: 日時のtimestamp拡張型書き込み
- **210-219行目**: Rangeのリスト展開
- **227-233行目**: recordのmap書き込み
- **234-246行目**: listのarray書き込み
- **252-266行目**: クロージャの処理（--serialize）

### プログラム呼び出し階層図

```
from msgpack
    │
    ├─ FromMsgpack::run (103-142行目)
    │      └─ read_msgpack (236-274行目)
    │             ├─ [--objects] イテレータ生成
    │             │      └─ read_value (再帰)
    │             └─ [single] read_value + assert_eof
    │                    └─ read_value (276-390行目)
    │                           ├─ mp::read_marker
    │                           ├─ FixPos/FixNeg → Value::int
    │                           ├─ U8-U64/I8-I64 → Value::int
    │                           ├─ F32/F64 → Value::float
    │                           ├─ Null → Value::nothing
    │                           ├─ True/False → Value::bool
    │                           ├─ FixStr/Str8-32 → read_str → Value::string
    │                           ├─ Bin8-32 → read_bin → Value::binary
    │                           ├─ FixArray/Array16-32 → read_array (再帰)
    │                           ├─ FixMap/Map16-32 → read_map (再帰)
    │                           └─ FixExt/Ext → read_ext
    │                                  └─ type=-1: make_date → Value::date
    │
to msgpack
    │
    ├─ ToMsgpack::run (75-103行目)
    │      └─ write_value (161-299行目)
    │             ├─ Value::Bool → mp::write_bool
    │             ├─ Value::Int → mp::write_sint
    │             ├─ Value::Float → mp::write_f64
    │             ├─ Value::Filesize/Duration → mp::write_sint
    │             ├─ Value::Date → mp::write_ext_meta (-1) + timestamp
    │             ├─ Value::Range → リスト展開 → write_value
    │             ├─ Value::String/Glob → mp::write_str
    │             ├─ Value::Record → mp::write_map_len + write_value (再帰)
    │             ├─ Value::List → mp::write_array_len + write_value (再帰)
    │             ├─ Value::Nothing → mp::write_nil
    │             ├─ Value::Closure → 文字列化 (--serialize) or エラー
    │             ├─ Value::Binary → mp::write_bin
    │             └─ Value::Custom → to_base_value → write_value
```

### データフロー図

```
[入力]               [処理]                    [出力]

from msgpack:
Binary/ByteStream ───▶ read_msgpack ───▶ read_value ───▶ Value
                             │                │
                             └── Opts ────────┤
                                  (objects)   └── 深度カウント (max 50)

to msgpack:
Value ───▶ write_value ───▶ Vec<u8> ───▶ Binary
                 │                          │
                 └── 型判定 ────────────────┤
                     (Date → timestamp ext) └── content_type:
                                                application/x-msgpack
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| msgpack.rs (from) | `crates/nu-command/src/formats/from/msgpack.rs` | ソース | from msgpackコマンド実装 |
| msgpack.rs (to) | `crates/nu-command/src/formats/to/msgpack.rs` | ソース | to msgpackコマンド実装 |
