Files
hakorune/docs/archive/phases/phase-106-156/phase114_fileio_trait_extension.md
nyash-codex d4f90976da refactor(joinir): Phase 244 - ConditionLoweringBox trait unification
Unify condition lowering logic across Pattern 2/4 with trait-based API.

New infrastructure:
- condition_lowering_box.rs: ConditionLoweringBox trait + ConditionContext (293 lines)
- ExprLowerer implements ConditionLoweringBox trait (+51 lines)

Pattern migrations:
- Pattern 2 (loop_with_break_minimal.rs): Use trait API
- Pattern 4 (loop_with_continue_minimal.rs): Use trait API

Benefits:
- Unified condition lowering interface
- Extensible for future lowering strategies
- Clean API boundary between patterns and lowering logic
- Zero code duplication

Test results: 911/911 PASS (+2 new tests)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-11 02:35:31 +09:00

7.4 KiB
Raw Blame History

Phase 114: FileIo trait 拡張 & メタデータ統一

目標

FsApi 側に揃った情報exists / metadata / canonicalizeを、FileIo trait 経由で一貫して扱えるようにする。 FileHandleBox 内部の is_file/is_dir/size などをすべて FileIo::stat() の上に乗せる。 .hako 側 APIPhase 113 で公開したメソッド群)は変更しない(内部実装だけきれい化)。

FileIo trait 設計FsApi との分離stateless vs stateful

FsApi (Ring0) - Stateless OS抽象

pub trait FsApi {
    fn exists(&self, path: &Path) -> bool;
    fn metadata(&self, path: &Path) -> Result<FsMetadata>;
    fn canonicalize(&self, path: &Path) -> Result<PathBuf>;
    fn read_to_string(&self, path: &Path) -> Result<String>;
    fn write_all(&self, path: &Path, data: &[u8]) -> Result<()>;
    fn append_all(&self, path: &Path, data: &[u8]) -> Result<()>;
}
  • Role: OS ファイルシステムの直接抽象化
  • State: なし(パス引数で毎回指定)
  • Usage: Ring0Context 経由でアクセス

FileIo (Ring1) - Stateful ハンドル抽象

pub struct FileStat {
    pub is_file: bool,
    pub is_dir: bool,
    pub size: u64,
}

pub trait FileIo: Send + Sync {
    fn caps(&self) -> FileCaps;
    fn open(&self, path: &str) -> FileResult<()>;
    fn read(&self) -> FileResult<String>;
    fn write(&self, text: &str) -> FileResult<()>;
    fn close(&self) -> FileResult<()>;
    fn as_any(&self) -> &dyn std::any::Any;

    // Phase 114: Metadata operations
    fn exists(&self) -> bool;
    fn stat(&self) -> FileResult<FileStat>;
    fn canonicalize(&self) -> FileResult<String>;
}
  • Role: 現在開いているファイルハンドルに対する操作
  • State: ありopen() で path を内部保持)
  • Usage: FileHandleBox 経由でアクセス

設計原則

  1. FsApi = Stateless: パスを毎回引数で受け取る
  2. FileIo = Stateful: open() で path を保持、以降は引数不要
  3. 分離理由:
    • FsApi: OS レイヤーの直接操作(低レベル)
    • FileIo: ハンドルベースの高レベル API.hako からアクセス)

Ring0FsFileIo/NoFsFileIo の実装詳細

Ring0FsFileIo (Default プロファイル)

pub struct Ring0FsFileIo {
    ring0: Arc<Ring0Context>,
    path: RwLock<Option<String>>,  // open() で設定
    mode: RwLock<Option<String>>,  // "r", "w", "a"
}

impl FileIo for Ring0FsFileIo {
    fn exists(&self) -> bool {
        // path が設定されていれば ring0.fs.exists() を呼ぶ
        // path が None なら false
    }

    fn stat(&self) -> FileResult<FileStat> {
        // path が設定されていれば ring0.fs.metadata() を呼ぶ
        // FileStat に変換して返す
    }

    fn canonicalize(&self) -> FileResult<String> {
        // path が設定されていれば ring0.fs.canonicalize() を呼ぶ
        // PathBuf を String に変換して返す
    }
}

NoFsFileIo (NoFs プロファイル)

pub struct NoFsFileIo;

impl FileIo for NoFsFileIo {
    fn exists(&self) -> bool {
        // NoFs プロファイルでは常に false
        false
    }

    fn stat(&self) -> FileResult<FileStat> {
        // Unsupported エラーを返す
        Err(FileError::Unsupported("..."))
    }

    fn canonicalize(&self) -> FileResult<String> {
        // Unsupported エラーを返す
        Err(FileError::Unsupported("..."))
    }
}

FileHandleBox の metadata_internal() 統一設計

Before Phase 114

// Ring0FsFileIo.metadata() を直接ダウンキャスト
fn metadata_internal(&self) -> Result<FsMetadata, String> {
    self.io.as_ref()
        .ok_or_else(|| "FileHandleBox not open".to_string())?
        .as_any()
        .downcast_ref::<Ring0FsFileIo>()
        .ok_or_else(|| "FileIo is not Ring0FsFileIo".to_string())?
        .metadata()  // Ring0FsFileIo 専用メソッド
}

問題点:

  • Ring0FsFileIo 依存downcast 必要)
  • FileIo trait を経由していない
  • NoFsFileIo では動作しない

After Phase 114

// FileIo::stat() を使用trait 経由)
fn metadata_internal(&self) -> Result<FileStat, String> {
    let io = self.io.as_ref()
        .ok_or_else(|| "FileHandleBox is not open".to_string())?;

    io.stat()  // FileIo trait 経由
        .map_err(|e| format!("Metadata failed: {}", e))
}

// 他のメソッドも metadata_internal() の上に統一
fn size(&self) -> Result<u64, String> {
    self.metadata_internal().map(|meta| meta.size)
}

fn is_file(&self) -> Result<bool, String> {
    self.metadata_internal().map(|meta| meta.is_file)
}

fn is_dir(&self) -> Result<bool, String> {
    self.metadata_internal().map(|meta| meta.is_dir)
}

改善点:

  • FileIo trait 経由で統一
  • downcast 不要
  • NoFsFileIo でも正しくエラーを返す

Profile 別動作

Default プロファイルRing0FsFileIo

メソッド 動作
exists() ファイルが存在すれば true、存在しないか path 未設定なら false
stat() FileStat { is_file, is_dir, size } を返す。path 未設定なら Err
canonicalize() 絶対パスを返す。path 未設定なら Err

NoFs プロファイルNoFsFileIo

メソッド 動作
exists() 常に false
stat() Err(FileError::Unsupported("..."))
canonicalize() Err(FileError::Unsupported("..."))

テスト結果

Ring0FsFileIo テストDefault プロファイル)

✅ test_ring0_fs_fileio_stat_default_profile
✅ test_ring0_fs_fileio_exists_default_profile
✅ test_ring0_fs_fileio_canonicalize_default_profile
✅ test_ring0_fs_fileio_stat_without_open
✅ test_ring0_fs_fileio_canonicalize_without_open

NoFsFileIo テスト

✅ test_nofs_fileio_exists (常に false)
✅ test_nofs_fileio_stat_error (Unsupported エラー)
✅ test_nofs_fileio_canonicalize_error (Unsupported エラー)

FileHandleBox テスト

✅ test_filehandlebox_metadata_internal_default (stat() 経由で FileStat 取得)
✅ test_filehandlebox_metadata_internal_not_open (エラー確認)
✅ test_filehandlebox_ny_size_uses_stat (ny_size() が stat() 経由)
✅ test_filehandlebox_exists_uses_fileio (exists() が FileIo::exists() 経由)
✅ test_filehandlebox_is_file_is_dir_via_stat (is_file/is_dir が stat() 経由)

実装成果

統計

  • 修正ファイル: 4ファイル
    • src/boxes/file/provider.rs
    • src/providers/ring1/file/ring0_fs_fileio.rs
    • src/providers/ring1/file/nofs_fileio.rs
    • src/boxes/file/handle_box.rs
    • src/providers/ring1/file/core_ro.rs
  • 追加行: 約 +150 行
  • 削除行: 約 -20 行
  • 新規テスト: 11個

技術的成果

  1. FileIo trait 拡張: exists/stat/canonicalize 正式追加
  2. 統一設計: FileHandleBox 内部が metadata_internal() に統一
  3. Profile 対応: Default/NoFs 両プロファイルで正しく動作
  4. 後方互換性: .hako 側 API は変更なし(内部実装のみ統一)

次のステップ

  • Phase 115: PathBox 実装パス操作専用Box
  • Phase 116: ディレクトリ操作mkdir/rmdir/readdir

関連ドキュメント