# 機能設計書 79-エンコーディング

## 概要

本ドキュメントは、mrubyにおけるエンコーディング機能の設計について記述する。UTF-8文字列エンコーディングのサポートとして、Stringクラスへのエンコーディング関連メソッドおよびEncodingモジュールを提供する。

### 本機能の処理概要

mruby-encodingは、Stringクラスにencoding、force_encoding、valid_encoding?メソッドを追加し、簡易的なエンコーディング管理を提供する。CRubyの完全なEncodingクラスとは異なり、mrubyではUTF-8とASCII-8BIT（BINARY）の2つのエンコーディングのみをサポートする簡易実装である。

**業務上の目的・背景**：mrubyで文字列を扱う際、バイナリデータとテキストデータを区別する必要がある。UTF-8エンコーディングの妥当性チェックやバイナリ/テキストの明示的な切り替えにより、文字列操作の安全性を確保する。

**機能の利用シーン**：外部からのバイナリデータ読み込み時のエンコーディング設定、文字列のUTF-8妥当性検証、バイナリ文字列とUTF-8文字列の明示的な変換。

**主要な処理内容**：
1. String#encoding: 文字列のエンコーディングを取得
2. String#force_encoding: 文字列のエンコーディングを変更（内容は変更しない）
3. String#valid_encoding?: 文字列が有効なエンコーディングか判定
4. Encodingモジュール: エンコーディング名定数の提供

**関連システム・外部連携**：特になし。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | ライブラリとして利用。画面なし |

## 機能種別

文字列操作拡張 / エンコーディング管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| encoding | String | Yes(force_encoding) | エンコーディング名（"UTF-8"/"ASCII-8BIT"/"BINARY"） | 大文字小文字無視、対応エンコーディングのみ |

### 入力データソース

- Rubyコードからの文字列操作

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| エンコーディング名 | String | "UTF-8"または"ASCII-8BIT" |
| 妥当性 | Boolean | valid_encoding?の結果 |
| 文字列 | String | force_encodingの戻り値（self） |

### 出力先

Rubyオブジェクトとして返却。

## 処理フロー

### 処理シーケンス

```
1. gem初期化（mrb_mruby_encoding_gem_init）
   ├─ Stringクラスにvalid_encoding?/encoding/force_encodingメソッド追加
   └─ Encodingモジュール定義（ASCII_8BIT/BINARY/UTF_8定数）

2. String#valid_encoding?
   ├─ SINGLE_BYTE_Pフラグ → true
   ├─ BINARY_Pフラグ → true
   └─ mrb_utf8lenで各バイトのUTF-8妥当性チェック
      ├─ 全バイト有効 → true（SINGLE_BYTE_FLAG設定）
      └─ 不正バイト検出 → false

3. String#encoding
   ├─ BINARY_Pフラグ → Encoding::BINARY
   └─ それ以外 → Encoding::UTF_8

4. String#force_encoding(enc)
   ├─ "ASCII-8BIT"/"BINARY" → MRB_STR_BINARYフラグセット
   ├─ "UTF-8" → MRB_STR_BINARYフラグクリア
   └─ その他 → ArgumentError
```

### フローチャート

```mermaid
flowchart TD
    A[valid_encoding?] --> B{SINGLE_BYTE_P?}
    B -->|Yes| C[true]
    B -->|No| D{BINARY_P?}
    D -->|Yes| C
    D -->|No| E[UTF-8バイト列検証]
    E --> F{不正バイト?}
    F -->|Yes| G[false]
    F -->|No| H{byte_len == utf8_len?}
    H -->|Yes| I[SINGLE_BYTE_FLAG設定]
    I --> C
    H -->|No| C
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-79-1 | 2エンコーディング | UTF-8とASCII-8BIT（BINARY）の2種類のみサポート | 常時 |
| BR-79-2 | 簡易Encoding | Encodingはクラスではなくモジュール、各エンコーディングはStringオブジェクト | 常時 |
| BR-79-3 | force_encoding大文字小文字無視 | エンコーディング名は大文字小文字を区別しない | MRB_STR_CASECMP_P使用 |
| BR-79-4 | SINGLE_BYTE最適化 | 全バイトがASCIIの場合SINGLE_BYTE_FLAGを設定して以降の判定を高速化 | valid_encoding?呼び出し後 |

### 計算ロジック

- valid_encoding?はmrb_utf8lenを使用してUTF-8のマルチバイトシーケンスを検証する
- 1バイト文字が0x80ビットを持つ場合は不正（UTF-8では0x80-0xBFは継続バイト）

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ArgumentError | force_encodingに未知のエンコーディング名を指定 | "unknown encoding name - %v" |

### リトライ仕様

リトライは不要。

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

該当なし。

## パフォーマンス要件

- valid_encoding?はSINGLE_BYTE_PフラグとBINARY_Pフラグによる早期リターンで最適化
- SINGLE_BYTE_FLAGの設定により2回目以降の呼び出しはO(1)

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

- UTF-8の不正なバイトシーケンスを検出する機能を提供

## 備考

- CRubyのEncodingクラスとは大幅に異なる簡易実装（"Poorman's Encoding"とコメントあり）
- Encodingの各値はEncodingオブジェクトではなくString（"UTF-8"/"ASCII-8BIT"）
- BINARY定数はASCII_8BITのエイリアス（同一オブジェクト参照）

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | encoding.c | `mrbgems/mruby-encoding/src/encoding.c` | エンコーディング名定数（7-9行目） |

**読解のコツ**: ENC_ASCII_8BIT = "ASCII-8BIT"、ENC_BINARY = "BINARY"、ENC_UTF8 = "UTF-8"の3定数がエンコーディング名として使用される。RStringのflagsフィールドのMRB_STR_BINARYビットでエンコーディングを管理。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | encoding.c | `mrbgems/mruby-encoding/src/encoding.c` | mrb_mruby_encoding_gem_init関数（102-123行目） |

**主要処理フロー**:
1. **107-109行目**: Stringクラスに3メソッド登録
2. **118行目**: Encodingモジュール定義
3. **119-122行目**: ASCII_8BIT/BINARY/UTF_8定数定義（BINARYはASCII_8BITと同一オブジェクト）

#### Step 3: 各メソッドの実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | encoding.c | `mrbgems/mruby-encoding/src/encoding.c` | str_valid_enc_p関数（18-40行目） |
| 3-2 | encoding.c | `mrbgems/mruby-encoding/src/encoding.c` | str_encoding関数（59-67行目） |
| 3-3 | encoding.c | `mrbgems/mruby-encoding/src/encoding.c` | str_force_encoding関数（81-100行目） |

**主要処理フロー**:
- **24行目**: RSTR_SINGLE_BYTE_P早期リターン
- **25行目**: RSTR_BINARY_P早期リターン
- **31-37行目**: UTF-8バイト列の各バイト検証ループ
- **34行目**: 1バイト文字の0x80ビットチェック
- **89-95行目**: force_encodingのエンコーディング名マッチとフラグ操作

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

```
mrb_mruby_encoding_gem_init
    ├─ mrb_define_method_id (valid_encoding?)
    ├─ mrb_define_method_id (encoding)
    ├─ mrb_define_method_id (force_encoding)
    └─ mrb_define_module_id (Encoding)
        ├─ mrb_define_const_id (ASCII_8BIT)
        ├─ mrb_define_const_id (BINARY) ← ASCII_8BITと同一
        └─ mrb_define_const_id (UTF_8)

str_valid_enc_p
    └─ mrb_utf8len (各バイト検証)

str_encoding
    └─ get_encoding
        └─ mrb_const_get (Encoding定数取得)

str_force_encoding
    └─ MRB_STR_CASECMP_P (エンコーディング名比較)
```

### データフロー図

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

String ──────────▶ str_valid_enc_p ──────▶ true/false
                     └─ mrb_utf8len

String ──────────▶ str_encoding ─────────▶ "UTF-8" / "ASCII-8BIT"
                     └─ BINARY_Pフラグ判定

String + "UTF-8" ──▶ str_force_encoding ──▶ self (フラグ変更済み)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| encoding.c | `mrbgems/mruby-encoding/src/encoding.c` | ソース | メインC実装 |
| mrbgem.rake | `mrbgems/mruby-encoding/mrbgem.rake` | 設定 | gem定義 |
| string.rb | `mrbgems/mruby-encoding/test/string.rb` | テスト | Stringエンコーディングテスト |
| numeric.rb | `mrbgems/mruby-encoding/test/numeric.rb` | テスト | Numericエンコーディングテスト |
