# 機能設計書 2-Condition

## 概要

本ドキュメントは、Hack Standard Library (HSL) の非同期処理モジュール `HH\Lib\Async\Condition` クラスの機能設計書である。

### 本機能の処理概要

**業務上の目的・背景**：
非同期プログラミングにおいて、あるタスクが別のタスクの完了を待機し、完了時に結果を受け取るというパターンは頻繁に発生する。HHVMの`ConditionWaitHandle`は強力な待機メカニズムを提供するが、通知イベントが待機開始前に発生した場合に対応できないという制約がある。`Condition`クラスはこの制約を解消し、通知イベントが待機前に発生しても正しく動作する条件変数のラッパーを提供する。これにより、非同期処理間の同期をより柔軟に行うことができる。

**機能の利用シーン**：
- 非同期タスク間で完了通知と結果の受け渡しを行う場合
- プロデューサー/コンシューマーパターンの実装
- イベント駆動型の非同期処理で、イベント発生順序が不確定な場合
- Semaphoreなど他の同期プリミティブの内部実装

**主要な処理内容**：
1. `succeed()`メソッドで成功結果を設定し、待機中のタスクに通知
2. `fail()`メソッドで例外を設定し、待機中のタスクに失敗を通知
3. `waitForNotificationAsync()`メソッドで通知を非同期に待機
4. 通知が待機前に発生した場合は、即座に結果を返却

**関連システム・外部連携**：
- HHVMの`ConditionWaitHandle`を内部的に使用
- `Semaphore`クラスなど、他のHSL非同期プリミティブから利用される

**権限による制御**：該当なし（ライブラリ機能のため）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 画面なし | - | 本プロジェクトはUIを持たないライブラリのため該当なし |

## 機能種別

同期プリミティブ / イベント通知

## 入力仕様

### 入力パラメータ

#### succeed()メソッド

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| result | T | Yes | 成功時に待機側に渡す結果値 | 型パラメータTに適合 |

#### fail()メソッド

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| exception | \Exception | Yes | 失敗時に待機側にスローする例外 | Exceptionのインスタンス |

#### waitForNotificationAsync()メソッド

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| notifiers | Awaitable&lt;void&gt; | Yes | 通知を発行する処理を含むAwaitable | WaitHandleであること |

### 入力データソース

- プログラムから直接呼び出し（API）

## 出力仕様

### 出力データ

#### waitForNotificationAsync()メソッド

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | Awaitable&lt;T&gt; | succeed()で設定された結果値、またはfail()で設定された例外 |

### 出力先

- 呼び出し元プログラムへの戻り値

## 処理フロー

### 処理シーケンス

```
【パターン1: 待機前に通知（succeed/fail first）】
1. succeed()またはfail()が呼び出される
   └─ $conditionがnullの場合、結果/例外を含むasyncブロックを作成
2. waitForNotificationAsync()が呼び出される
   └─ $conditionが既に設定済みのため、即座にawaitして結果を返却

【パターン2: 通知前に待機（wait first）】
1. waitForNotificationAsync()が呼び出される
   └─ $conditionがnullの場合、ConditionWaitHandle::createで待機用ハンドルを作成
   └─ awaitして通知を待機
2. succeed()またはfail()が呼び出される
   └─ $conditionがConditionWaitHandleの場合、succeed/failメソッドを呼び出し
   └─ 待機中のタスクが再開され、結果を受け取る
```

### フローチャート

```mermaid
flowchart TD
    subgraph "succeed()の処理"
        A1[succeed開始] --> B1{$condition is null?}
        B1 -->|Yes| C1[asyncブロックで結果をラップ]
        B1 -->|No| D1{ConditionWaitHandle?}
        D1 -->|Yes| E1[WaitHandleのsucceedを呼び出し]
        D1 -->|No| F1[invariant違反: 二重通知]
    end

    subgraph "waitForNotificationAsync()の処理"
        A2[wait開始] --> B2{$condition is null?}
        B2 -->|Yes| C2[ConditionWaitHandle::create]
        B2 -->|No| D2[既存の$conditionを使用]
        C2 --> E2[await $condition]
        D2 --> E2
        E2 --> F2[結果を返却]
    end
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 単一通知 | succeed()またはfail()は一度だけ呼び出し可能 | 常時 |
| BR-02 | 通知順序非依存 | 通知が待機前でも後でも正しく動作する | 常時 |
| BR-03 | notifiers要件 | $notifiersは通知が発行される前に完了してはならない | waitForNotificationAsync呼び出し時 |
| BR-04 | 例外伝播 | fail()で設定した例外は待機側でスローされる | fail()使用時 |

### 計算ロジック

**状態遷移**：
```
初期状態: $condition = null
↓
[succeed/fail first]
通知後: $condition = async { return $result; } または async { throw $exception; }
↓
[wait first]
待機中: $condition = ConditionWaitHandle::create($notifiers)
↓
[通知]
$condition->succeed($result) または $condition->fail($exception)
```

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

該当なし（メモリ上での状態管理のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| InvariantViolation | 実行時エラー | succeed()またはfail()を2回以上呼び出した | 呼び出しは1回のみに制限する |
| Exception | ユーザー例外 | fail()で設定された例外 | 待機側でcatchして処理 |

### リトライ仕様

本機能自体にリトライ機構は組み込まれていない。

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

該当なし

## パフォーマンス要件

- 待機・通知のオーバーヘッドは最小限（ConditionWaitHandleの直接利用と同等）
- 通知が待機前に発生した場合、追加のコンテキストスイッチは発生しない

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

該当なし（ライブラリ内部機能のため）

## 備考

- Conditionインスタンスは使い捨て（1回の通知-待機サイクルのみ対応）
- `ConditionNode`クラスがConditionを継承し、リンクリスト構造を追加している
- $notifiersパラメータは、通知を発行する処理が含まれていることを保証するためのもの

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Condition.php | `src/async/Condition.php` | クラス定義とプロパティ（17-18行目） |

**読解のコツ**: `?Awaitable<T>`という型は、初期状態ではnull、通知後または待機開始後にAwaitableが設定されることを示す。

**主要なプロパティ**:
- **18行目**: `private ?Awaitable<T> $condition = null` - 通知結果または待機ハンドルを保持

#### Step 2: 成功通知メカニズムを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Condition.php | `src/async/Condition.php` | succeed()メソッド（23-36行目） |

**主要処理フロー**:
- **24-27行目**: `$condition === null`の場合、結果をasyncブロックでラップ
- **29-31行目**: 既存の$conditionがConditionWaitHandleかチェック
- **34行目**: ConditionWaitHandleのsucceed()を呼び出して通知

#### Step 3: 失敗通知メカニズムを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Condition.php | `src/async/Condition.php` | fail()メソッド（41-53行目） |

**主要処理フロー**:
- **42-45行目**: `$condition === null`の場合、例外をスローするasyncブロックを作成
- **47-49行目**: 既存の$conditionがConditionWaitHandleかチェック
- **51行目**: ConditionWaitHandleのfail()を呼び出して例外を伝播

#### Step 4: 待機メカニズムを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Condition.php | `src/async/Condition.php` | waitForNotificationAsync()メソッド（66-73行目） |

**主要処理フロー**:
- **69-71行目**: `$condition === null`の場合、ConditionWaitHandleを作成
- **72行目**: $conditionをawaitして結果を返却

#### Step 5: 派生クラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | ConditionNode.php | `src/async/ConditionNode.php` | リンクリスト構造の追加 |

**主要処理フロー**:
- **17行目**: `private ?ConditionNode<T> $next` - 次ノードへのポインタ
- **19-23行目**: `addNext()` - 新しいノードを追加
- **25-27行目**: `getNext()` - 次ノードを取得

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

```
Condition<T>
    |
    +-- succeed($result)
    |       |
    |       +-- [null時] async { return $result; }
    |       +-- [WaitHandle時] ConditionWaitHandle::succeed($result)
    |
    +-- fail($exception)
    |       |
    |       +-- [null時] async { throw $exception; }
    |       +-- [WaitHandle時] ConditionWaitHandle::fail($exception)
    |
    +-- waitForNotificationAsync($notifiers)
            |
            +-- [null時] ConditionWaitHandle::create($notifiers)
            +-- await $this->condition
```

### データフロー図

```
[パターン1: succeed/fail first]

succeed($result)                  waitForNotificationAsync($notifiers)
      |                                     |
      v                                     v
$condition = async {              await $condition (即座に完了)
  return $result;                           |
}                                           v
                                     結果を返却


[パターン2: wait first]

waitForNotificationAsync($notifiers)        succeed($result)
      |                                           |
      v                                           v
$condition = ConditionWaitHandle    $condition->succeed($result)
::create($notifiers)                              |
      |                                           v
      v                                    待機タスク再開
await $condition (待機中)                         |
      |<------------------------------------------+
      v
結果を返却
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Condition.php | `src/async/Condition.php` | ソース | Conditionクラスの実装 |
| ConditionNode.php | `src/async/ConditionNode.php` | ソース | リンクリスト対応のCondition派生クラス |
| Semaphore.php | `src/async/Semaphore.php` | ソース | Conditionを利用する同期プリミティブ |
| BasePoll.php | `src/async/BasePoll.php` | ソース | ConditionNodeを利用するPoll基底クラス |
| ConditionTest.php | `tests/async/ConditionTest.php` | テスト | Conditionの単体テスト |
