diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index e2985be1..f08a2122 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -212,6 +212,13 @@ - Ring1-core(StringBox/ArrayBox/MapBox/FileBox/ConsoleBox 等)と ring1-optional/selfhost/user_plugin を 4 層に分類し、「core_required は静的必須セット、optional と user は PluginHost の上に載る」設計を言語化済み。 - `docs/development/current/main/ring0-inventory.md` に println!/eprintln! や fs/time/thread を含む Ring0 候補呼び出し、Box/プラグイン/カーネル実装数の調査結果をまとめ、Phase 88/90 で代表パスを Ring0Context に移行済み(残りは Phase 91+ の段階移行対象)。 - Phase 87–95 で CoreBoxId/CoreMethodId/CoreServices/PluginHost/Adapter/Service API の実装とテストが完了し、Box 名・メソッド名と core_required Box の初期化は `src/runtime/core_box_ids.rs` と `src/runtime/core_services.rs` に集約された。今後の ring0/ring1-core 変更はこの SSOT に対してのみ行えばよい状態になっている。 + - **Phase 95.5: Ring0 統合完了**(2025-12-03) + - ✅ ConsoleService が Ring0Context に直結(println → Ring0Context.log.info, print → Ring0Context.io.stdout_write) + - ✅ StringService が純粋関数化(Box 状態不要) + - ✅ #[allow(dead_code)] 削減: 6箇所 → 4箇所(2削減) + - ✅ ログ経路統一: Ring0 → Ring1-Core → 実行パス + - **設計原則確立**: Ring0 直結型(ConsoleService)と純粋関数型(StringService)の2パターン + - **次のステップ**: Phase 96 で ArrayService/MapService 実装(状態管理必要)、代表パス拡大(5-10箇所) 12. **Phase 86: BoxFactory Priority 正常化** ✅ **完了**(2025-12-02) - **目的**: BoxFactory のデフォルトポリシーを `BuiltinFirst` から `StrictPluginFirst` に変更し、プラグイン版 Box が正常に使用できるよう正常化。 diff --git a/docs/development/current/main/core_boxes_design.md b/docs/development/current/main/core_boxes_design.md index 0ae9ef70..d9a28cf6 100644 --- a/docs/development/current/main/core_boxes_design.md +++ b/docs/development/current/main/core_boxes_design.md @@ -668,3 +668,219 @@ host.core.console.println("[selfhost] PluginHost initialized successfully"); - MapService 実装(get, set, has, size) - 代表パス拡大(selfhost 以外の箇所にも展開) - StringService 拡張(substring, concat, replace 等) + +--- + +## 12. Phase 95.5: Ring0 統合完了(2025-12-03) + +### 12.1 実装成果 + +- ✅ **ConsoleService Ring0 直結**: Box を保持せず Ring0Context に直結 +- ✅ **StringService 純粋関数化**: Box 状態不要な設計確立 +- ✅ **#[allow(dead_code)] 削減**: 6箇所 → 4箇所(2削減) +- ✅ **ログ経路統一**: Ring0 → Ring1-Core → 実行パス + +### 12.2 ConsoleService 設計 + +**Ring0 直結設計**: +```rust +pub struct ConsoleBoxAdapter; + +impl ConsoleBoxAdapter { + pub fn new() -> Self { + Self + } +} + +impl ConsoleService for ConsoleBoxAdapter { + fn println(&self, msg: &str) { + // Ring0Context 経由でログ出力(自動改行) + use crate::runtime::ring0::get_global_ring0; + let ring0 = get_global_ring0(); + ring0.log.info(msg); + } + + fn print(&self, msg: &str) { + // Ring0Context 経由で stdout 出力(改行なし) + use crate::runtime::ring0::get_global_ring0; + let ring0 = get_global_ring0(); + ring0.io.stdout_write(msg.as_bytes()).ok(); + } +} +``` + +**利点**: +- OS 抽象化レイヤー完全活用 +- テスト容易性向上(Ring0 をモック可能) +- Box レイヤーをスキップして効率化 +- ログ経路統一(全てのコンソール出力が Ring0 経由) + +**設計原則**: +- ConsoleService は OS API (Ring0) の thin wrapper +- println() → Ring0Context.log.info()(ログレベル付き、自動改行) +- print() → Ring0Context.io.stdout_write()(改行なし、生出力) + +### 12.3 StringService 設計 + +**純粋関数設計**: +```rust +pub struct StringBoxAdapter; + +impl StringBoxAdapter { + pub fn new() -> Self { + Self + } +} + +impl StringService for StringBoxAdapter { + fn len(&self, s: &str) -> i64 { + // 純粋関数として実装(Box 状態不要) + s.chars().count() as i64 + } +} +``` + +**利点**: +- Box インスタンス不要(メモリ効率向上) +- 純粋関数として再現性保証 +- テスト容易性(状態を持たない) + +**Phase 96 以降の拡張**: +- substring(s, start, end) → 純粋関数 +- concat(a, b) → 純粋関数 +- replace(s, from, to) → 純粋関数 + +### 12.4 PluginHost 初期化変更 + +**Before** (Phase 95): +```rust +// StringBox +let string_box = registry + .create_box("StringBox", &[]) + .map_err(|e| CoreInitError::MissingService { + box_id: CoreBoxId::String, + message: format!("StringBox creation failed: {}", e), + })?; +let string_service = Arc::new(StringBoxAdapter::new(string_box)); + +// ConsoleBox +let console_box = registry + .create_box("ConsoleBox", &[]) + .map_err(|e| CoreInitError::MissingService { + box_id: CoreBoxId::Console, + message: format!("ConsoleBox creation failed: {}", e), + })?; +let console_service = Arc::new(ConsoleBoxAdapter::new(console_box)); +``` + +**After** (Phase 95.5): +```rust +// StringBox (純粋関数化、存在チェックのみ) +if !registry.has_type("StringBox") { + return Err(CoreInitError::MissingService { + box_id: CoreBoxId::String, + message: "StringBox not found in registry".to_string(), + }); +} +let string_service = Arc::new(StringBoxAdapter::new()); + +// ConsoleBox (Ring0 直結、存在チェックのみ) +if !registry.has_type("ConsoleBox") { + return Err(CoreInitError::MissingService { + box_id: CoreBoxId::Console, + message: "ConsoleBox not found in registry".to_string(), + }); +} +let console_service = Arc::new(ConsoleBoxAdapter::new()); +``` + +**変更点**: +- Box インスタンス生成不要(存在チェックのみ) +- エラーメッセージ簡略化 +- メモリ効率向上 + +### 12.5 テスト更新 + +**Ring0 初期化ヘルパー**: +```rust +#[cfg(test)] +fn ensure_ring0_initialized() { + use crate::runtime::ring0::{default_ring0, GLOBAL_RING0}; + use std::sync::Arc; + + // 既に初期化済みなら何もしない + if GLOBAL_RING0.get().is_none() { + GLOBAL_RING0.set(Arc::new(default_ring0())).ok(); + } +} +``` + +**テスト例**: +```rust +#[test] +fn test_console_service_ring0_integration() { + // Ring0 初期化(安全な初期化) + ensure_ring0_initialized(); + + // ConsoleService 経由で出力(Ring0 使用) + let adapter = ConsoleBoxAdapter::new(); + adapter.println("Test message from Ring0"); + adapter.print("No newline"); + + // panic しないことを確認 +} +``` + +### 12.6 削減統計 + +| 項目 | Before | After | 削減 | +|------|--------|-------|------| +| #[allow(dead_code)] | 6箇所 | 4箇所 | 2削減 | +| inner フィールド | 6個 | 4個 | 2削減 | +| Box 依存 | 6箇所 | 4箇所 | 2削減 | + +**残存 Adapter**: +- IntegerBoxAdapter: Phase 96 以降で実装方針決定 +- BoolBoxAdapter: Phase 96 以降で実装方針決定 +- ArrayBoxAdapter: Phase 96 以降で実装方針決定 +- MapBoxAdapter: Phase 96 以降で実装方針決定 + +### 12.7 設計原則確立 + +**2つの設計パターン**: + +1. **Ring0 直結型**(ConsoleService) + - OS API の thin wrapper + - Box 状態不要 + - Ring0Context 経由でシステムコール + +2. **純粋関数型**(StringService) + - 副作用なし + - Box 状態不要 + - 入力のみから出力を決定 + +**Phase 96 実装方針**: +- ArrayService: 状態管理が必要 → Box 保持型 +- MapService: 状態管理が必要 → Box 保持型 +- IntegerService: 純粋関数で足りる → 純粋関数型 +- BoolService: 純粋関数で足りる → 純粋関数型 + +### 12.8 実装ファイル + +1. `src/runtime/core_services.rs` + - ConsoleBoxAdapter: Ring0 直結実装 + - StringBoxAdapter: 純粋関数化 + - 他4 Adapter: コメント追加 + - テスト: Ring0 統合テスト追加 + +2. `src/runtime/plugin_host.rs` + - StringBox 初期化: 存在チェックのみ + - ConsoleBox 初期化: 存在チェックのみ + - テスト: エラーメッセージ更新 + +### 12.9 次のステップ(Phase 96) + +- ArrayService/MapService 実装(状態管理が必要) +- IntegerService/BoolService 実装(純粋関数で実装) +- 代表パス拡大(5-10箇所) +- #[allow(dead_code)] 完全撲滅 diff --git a/src/runtime/core_services.rs b/src/runtime/core_services.rs index 4492320c..a8cb2649 100644 --- a/src/runtime/core_services.rs +++ b/src/runtime/core_services.rs @@ -106,25 +106,30 @@ impl CoreServices { // ============================================================================ /// StringBox → StringService Adapter -pub struct StringBoxAdapter { - #[allow(dead_code)] - inner: Box, -} +/// +/// Phase 95.5: 純粋関数設計 +/// - Box を保持せず、純粋関数として実装 +/// - len(s) → s.chars().count() (UTF-8 文字数) +/// - Phase 96 以降で substring(), concat() など追加予定 +pub struct StringBoxAdapter; impl StringBoxAdapter { - pub fn new(box_instance: Box) -> Self { - Self { inner: box_instance } + pub fn new() -> Self { + Self } } impl StringService for StringBoxAdapter { fn len(&self, s: &str) -> i64 { - // Phase 95: 文字列長を返す(UTF-8 バイト数ではなく文字数) + // Phase 95.5: 文字列長を返す(UTF-8 バイト数ではなく文字数) s.chars().count() as i64 } } /// IntegerBox → IntegerService Adapter +/// +/// Phase 95.5: inner フィールドは #[allow(dead_code)] のまま保持 +/// Phase 96 以降で実装時に、Box 状態が必要か純粋関数で足りるか判断 pub struct IntegerBoxAdapter { #[allow(dead_code)] inner: Box, @@ -137,10 +142,13 @@ impl IntegerBoxAdapter { } impl IntegerService for IntegerBoxAdapter { - // Phase 95 以降で実装 + // Phase 96 以降で実装 } /// BoolBox → BoolService Adapter +/// +/// Phase 95.5: inner フィールドは #[allow(dead_code)] のまま保持 +/// Phase 96 以降で実装時に、Box 状態が必要か純粋関数で足りるか判断 pub struct BoolBoxAdapter { #[allow(dead_code)] inner: Box, @@ -153,10 +161,13 @@ impl BoolBoxAdapter { } impl BoolService for BoolBoxAdapter { - // Phase 95 以降で実装 + // Phase 96 以降で実装 } /// ArrayBox → ArrayService Adapter +/// +/// Phase 95.5: inner フィールドは #[allow(dead_code)] のまま保持 +/// Phase 96 以降で実装時に、Box 状態が必要か純粋関数で足りるか判断 pub struct ArrayBoxAdapter { #[allow(dead_code)] inner: Box, @@ -169,10 +180,13 @@ impl ArrayBoxAdapter { } impl ArrayService for ArrayBoxAdapter { - // Phase 95 以降で実装 + // Phase 96 以降で実装 } /// MapBox → MapService Adapter +/// +/// Phase 95.5: inner フィールドは #[allow(dead_code)] のまま保持 +/// Phase 96 以降で実装時に、Box 状態が必要か純粋関数で足りるか判断 pub struct MapBoxAdapter { #[allow(dead_code)] inner: Box, @@ -185,31 +199,36 @@ impl MapBoxAdapter { } impl MapService for MapBoxAdapter { - // Phase 95 以降で実装 + // Phase 96 以降で実装 } /// ConsoleBox → ConsoleService Adapter -pub struct ConsoleBoxAdapter { - #[allow(dead_code)] - inner: Box, -} +/// +/// Phase 95.5: Ring0 直結設計 +/// - Box を保持せず、Ring0Context に直結 +/// - println() → Ring0Context.log.info() +/// - print() → Ring0Context.io.stdout_write() +pub struct ConsoleBoxAdapter; impl ConsoleBoxAdapter { - pub fn new(box_instance: Box) -> Self { - Self { inner: box_instance } + pub fn new() -> Self { + Self } } impl ConsoleService for ConsoleBoxAdapter { fn println(&self, msg: &str) { - // Phase 95: ConsoleBox の println 機能を使用 - // ConsoleBox は直接 println! を呼ぶだけなので、ここでも同様に実装 - println!("{}", msg); + // Phase 95.5: Ring0Context 経由でログ出力(自動改行) + use crate::runtime::ring0::get_global_ring0; + let ring0 = get_global_ring0(); + ring0.log.info(msg); } fn print(&self, msg: &str) { - // Phase 95: ConsoleBox の print 機能を使用 - print!("{}", msg); + // Phase 95.5: Ring0Context 経由で stdout 出力(改行なし) + use crate::runtime::ring0::get_global_ring0; + let ring0 = get_global_ring0(); + ring0.io.stdout_write(msg.as_bytes()).ok(); } } @@ -236,36 +255,46 @@ mod tests { assert!(required.contains(&CoreBoxId::Console)); } + // Phase 95.5: Ring0 初期化ヘルパー(テスト用) + #[cfg(test)] + fn ensure_ring0_initialized() { + use crate::runtime::ring0::{default_ring0, GLOBAL_RING0}; + use std::sync::Arc; + + // 既に初期化済みなら何もしない + if GLOBAL_RING0.get().is_none() { + GLOBAL_RING0.set(Arc::new(default_ring0())).ok(); + } + } + #[test] fn test_console_service_println() { - use crate::boxes::console_box::ConsoleBox; + // Phase 95.5: Ring0 初期化(安全な初期化) + ensure_ring0_initialized(); - let console_box = Box::new(ConsoleBox::new()) as Box; - let adapter = ConsoleBoxAdapter::new(console_box); + let adapter = ConsoleBoxAdapter::new(); - // Phase 95: println を呼び出し(panic しないことを確認) - adapter.println("Test message"); + // Phase 95.5: println を呼び出し(Ring0 経由、panic しないことを確認) + adapter.println("Test message from Ring0"); // 実際の出力検証は Phase 96 以降 } #[test] fn test_console_service_print() { - use crate::boxes::console_box::ConsoleBox; + // Phase 95.5: Ring0 初期化(安全な初期化) + ensure_ring0_initialized(); - let console_box = Box::new(ConsoleBox::new()) as Box; - let adapter = ConsoleBoxAdapter::new(console_box); + let adapter = ConsoleBoxAdapter::new(); - // Phase 95: print を呼び出し(panic しないことを確認) - adapter.print("Test message"); + // Phase 95.5: print を呼び出し(Ring0 経由、panic しないことを確認) + adapter.print("No newline"); // 実際の出力検証は Phase 96 以降 } #[test] fn test_string_service_len() { - use crate::boxes::string_box::StringBox; - - let string_box = Box::new(StringBox::new("Hello")) as Box; - let adapter = StringBoxAdapter::new(string_box); + // Phase 95.5: 純粋関数なので Ring0 不要 + let adapter = StringBoxAdapter::new(); // Phase 95: len を呼び出し let length = adapter.len("Hello"); @@ -275,4 +304,17 @@ mod tests { let length_utf8 = adapter.len("こんにちは"); assert_eq!(length_utf8, 5); // 5文字(バイト数は15) } + + #[test] + fn test_console_service_ring0_integration() { + // Phase 95.5: Ring0 初期化(安全な初期化) + ensure_ring0_initialized(); + + // ConsoleService 経由で出力(Ring0 使用) + let adapter = ConsoleBoxAdapter::new(); + adapter.println("Test message from Ring0"); + adapter.print("No newline"); + + // panic しないことを確認 + } } diff --git a/src/runtime/plugin_host.rs b/src/runtime/plugin_host.rs index 55c33bb8..51593de5 100644 --- a/src/runtime/plugin_host.rs +++ b/src/runtime/plugin_host.rs @@ -100,14 +100,14 @@ impl PluginHost { // Phase 94: 各 core_required Box を取得して Adapter に変換 - // StringBox - let string_box = registry - .create_box("StringBox", &[]) - .map_err(|e| CoreInitError::MissingService { + // StringBox (Phase 95.5: 純粋関数化、存在チェックのみ) + if !registry.has_type("StringBox") { + return Err(CoreInitError::MissingService { box_id: CoreBoxId::String, - message: format!("StringBox creation failed: {}", e), - })?; - let string_service = Arc::new(StringBoxAdapter::new(string_box)); + message: "StringBox not found in registry".to_string(), + }); + } + let string_service = Arc::new(StringBoxAdapter::new()); // IntegerBox let integer_box = registry @@ -145,14 +145,14 @@ impl PluginHost { })?; let map_service = Arc::new(MapBoxAdapter::new(map_box)); - // ConsoleBox - let console_box = registry - .create_box("ConsoleBox", &[]) - .map_err(|e| CoreInitError::MissingService { + // ConsoleBox (Phase 95.5: Ring0 直結、存在チェックのみ) + if !registry.has_type("ConsoleBox") { + return Err(CoreInitError::MissingService { box_id: CoreBoxId::Console, - message: format!("ConsoleBox creation failed: {}", e), - })?; - let console_service = Arc::new(ConsoleBoxAdapter::new(console_box)); + message: "ConsoleBox not found in registry".to_string(), + }); + } + let console_service = Arc::new(ConsoleBoxAdapter::new()); // Phase 94: 実際の Adapter を使用して CoreServices を構築 let core = CoreServices { @@ -277,7 +277,7 @@ mod tests { #[test] fn test_with_core_from_registry_missing_box() { - // Phase 94: registry が空の場合はエラーを返すことを確認 + // Phase 95.5: registry が空の場合はエラーを返すことを確認 use crate::runtime::ring0::default_ring0; let ring0 = Arc::new(default_ring0()); let registry = UnifiedBoxRegistry::new(); @@ -285,13 +285,13 @@ mod tests { let result = PluginHost::with_core_from_registry(ring0, ®istry); assert!(result.is_err()); - // Phase 94: エラーメッセージに "creation failed" または "Unknown Box type" が含まれることを確認 + // Phase 95.5: エラーメッセージに "not found in registry" が含まれることを確認 if let Err(e) = result { let msg = format!("{}", e); eprintln!("Error message: {}", msg); // デバッグ出力 assert!( - msg.contains("creation failed") || msg.contains("Unknown Box type"), - "Error message should contain 'creation failed' or 'Unknown Box type', got: {}", + msg.contains("not found in registry") || msg.contains("creation failed") || msg.contains("Unknown Box type"), + "Error message should contain 'not found in registry', 'creation failed' or 'Unknown Box type', got: {}", msg ); }