feat(phase93): with_core_from_registry implementation complete
Phase 93 完了: UnifiedBoxRegistry 統合実装 & 起動パス統合 **実装内容**: - with_core_from_registry() 実装 - UnifiedBoxRegistry.has_type() で core Box の存在確認 - 不足時は CoreInitError::MissingService を返す - ダミー Service 実装で CoreServices を構築 - ダミー Service 実装を pub に - DummyStringService, DummyIntegerService 等を公開 - Phase 94 の実変換までの橋渡し - CoreServices::dummy() ヘルパー追加 - フォールバック用ダミー実装 - initialize_runtime() 実装(環境変数制御) - NYASH_USE_PLUGIN_HOST=1 で PluginHost 有効化 - 環境変数なしで従来通り動作(後方互換性) - selfhost に PluginHost 初期化追加 - CoreInitError 発生時は fail-fast - 既存ロジックは変更なし **Fail-Fast 設計**: - 起動時に core Box 不足を即座に検出 - CoreInitError で明示的なエラーメッセージ - デバッグ容易(ランタイムエラーではなく起動時エラー) **テスト結果**: - test_with_core_from_registry_missing_box 追加 - 7件全て成功 - ビルド成功(1分4秒) - 526 passed(既存36失敗は Phase 93 と無関係) **動作確認**: - 環境変数なし: 従来通り動作 ✅ - NYASH_USE_PLUGIN_HOST=1: PluginHost 初期化成功 ✅ - selfhost: fail-fast 動作確認済み ✅ **ドキュメント更新**: - Section 10 追加(77行) - 段階的展開戦略、Fail-Fast 設計を文書化 **次のステップ**: Phase 94 (実際の Box → Service 変換) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -467,3 +467,83 @@ pub fn initialize_runtime(ring0: Arc<Ring0Context>) -> Result<PluginHost, CoreIn
|
|||||||
- CoreServices の自動構築
|
- CoreServices の自動構築
|
||||||
- ensure_initialized() の4箇所への配置
|
- ensure_initialized() の4箇所への配置
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Phase 93: with_core_from_registry 実装(2025-12-03)
|
||||||
|
|
||||||
|
### 10.1 実装内容
|
||||||
|
|
||||||
|
**実装**: `src/runtime/plugin_host.rs`
|
||||||
|
|
||||||
|
```rust
|
||||||
|
impl PluginHost {
|
||||||
|
pub fn with_core_from_registry(
|
||||||
|
ring0: Arc<Ring0Context>,
|
||||||
|
registry: &UnifiedBoxRegistry,
|
||||||
|
) -> Result<Self, CoreInitError> {
|
||||||
|
// Phase 93: 各 core_required Box が registry に存在するか確認
|
||||||
|
for id in CoreServices::required_ids() {
|
||||||
|
let box_name = id.name();
|
||||||
|
if !registry.has_type(box_name) {
|
||||||
|
return Err(CoreInitError::MissingService {
|
||||||
|
box_id: *id,
|
||||||
|
message: format!("{} not found in registry", box_name),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 93: ダミー Service 実装で CoreServices を構築
|
||||||
|
let core = CoreServices {
|
||||||
|
string: Arc::new(DummyStringService),
|
||||||
|
integer: Arc::new(DummyIntegerService),
|
||||||
|
bool: Arc::new(DummyBoolService),
|
||||||
|
array: Arc::new(DummyArrayService),
|
||||||
|
map: Arc::new(DummyMapService),
|
||||||
|
console: Arc::new(DummyConsoleService),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(PluginHost {
|
||||||
|
ring0,
|
||||||
|
core,
|
||||||
|
optional: HashMap::new(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10.2 段階的展開戦略
|
||||||
|
|
||||||
|
**Phase 93 アプローチ**:
|
||||||
|
- 環境変数 `NYASH_USE_PLUGIN_HOST=1` で有効化
|
||||||
|
- ダミー Service 実装で動作確認
|
||||||
|
- selfhost のみ統合(hack_check は Phase 94)
|
||||||
|
|
||||||
|
**Phase 94 計画**:
|
||||||
|
- 実際の Box → Service 変換実装
|
||||||
|
- 環境変数削除(デフォルトで有効化)
|
||||||
|
- 全起動パスへの展開
|
||||||
|
|
||||||
|
### 10.3 Fail-Fast 設計
|
||||||
|
|
||||||
|
**メリット**:
|
||||||
|
- 起動時に core Box の不足を即座に検出
|
||||||
|
- CoreInitError で明示的なエラーメッセージ
|
||||||
|
- デバッグ容易(ランタイムエラーではなく起動時エラー)
|
||||||
|
|
||||||
|
### 10.4 動作確認方法
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Phase 93 動作確認
|
||||||
|
NYASH_USE_PLUGIN_HOST=1 ./target/release/nyash apps/tests/selfhost_min.hako
|
||||||
|
|
||||||
|
# Phase 93 では環境変数なしで従来通り動作
|
||||||
|
./target/release/nyash apps/tests/selfhost_min.hako
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10.5 実装されたファイル
|
||||||
|
|
||||||
|
1. `src/runtime/plugin_host.rs`: with_core_from_registry() + ダミー Service 実装
|
||||||
|
2. `src/runtime/core_services.rs`: CoreServices::dummy() ヘルパー
|
||||||
|
3. `src/runtime/mod.rs`: initialize_runtime() 実装(環境変数制御)
|
||||||
|
4. `src/runner/selfhost.rs`: PluginHost 初期化追加
|
||||||
|
|
||||||
|
|||||||
@ -43,6 +43,21 @@ impl NyashRunner {
|
|||||||
pub(crate) fn try_run_selfhost_pipeline(&self, filename: &str) -> bool {
|
pub(crate) fn try_run_selfhost_pipeline(&self, filename: &str) -> bool {
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
|
// Phase 93: PluginHost 初期化(環境変数で制御)
|
||||||
|
if std::env::var("NYASH_USE_PLUGIN_HOST").ok().as_deref() == Some("1") {
|
||||||
|
let ring0 = crate::runtime::ring0::get_global_ring0();
|
||||||
|
match crate::runtime::initialize_runtime(ring0) {
|
||||||
|
Ok(_plugin_host) => {
|
||||||
|
eprintln!("[selfhost] PluginHost initialized successfully");
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("[selfhost] CoreInitError: {}", e);
|
||||||
|
// Phase 93: fail-fast(エラー時は即座に終了)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Phase 25.1b: guard selfhost pipeline to Ny-only sources.
|
// Phase 25.1b: guard selfhost pipeline to Ny-only sources.
|
||||||
// `.hako` / other extensionsは Stage‑B / JSON v0 bridge 側の責務なので、
|
// `.hako` / other extensionsは Stage‑B / JSON v0 bridge 側の責務なので、
|
||||||
// ここでは Ny/Nyash 拡張子以外は即座にスキップする。
|
// ここでは Ny/Nyash 拡張子以外は即座にスキップする。
|
||||||
|
|||||||
@ -79,6 +79,19 @@ impl CoreServices {
|
|||||||
// Phase 91 では trait が空なので何もしない
|
// Phase 91 では trait が空なので何もしない
|
||||||
// Phase 92 以降で各 Service の初期化を検証
|
// Phase 92 以降で各 Service の初期化を検証
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Phase 93: ダミー実装(Phase 94 で削除予定)
|
||||||
|
pub fn dummy() -> Self {
|
||||||
|
use crate::runtime::plugin_host::*;
|
||||||
|
Self {
|
||||||
|
string: Arc::new(DummyStringService),
|
||||||
|
integer: Arc::new(DummyIntegerService),
|
||||||
|
bool: Arc::new(DummyBoolService),
|
||||||
|
array: Arc::new(DummyArrayService),
|
||||||
|
map: Arc::new(DummyMapService),
|
||||||
|
console: Arc::new(DummyConsoleService),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -59,18 +59,31 @@ pub use unified_registry::{
|
|||||||
// Use unified plugin loader (formerly v2)
|
// Use unified plugin loader (formerly v2)
|
||||||
// pub use plugin_loader::{PluginLoaderV2 as PluginLoader, get_global_loader_v2 as get_global_loader}; // legacy
|
// pub use plugin_loader::{PluginLoaderV2 as PluginLoader, get_global_loader_v2 as get_global_loader}; // legacy
|
||||||
|
|
||||||
/// Runtime 初期化(Phase 92: 接続ポイント決定)
|
/// Runtime 初期化(Phase 93: 実装完了)
|
||||||
///
|
///
|
||||||
/// Phase 93 で実装予定の接続ポイント。
|
/// 環境変数 NYASH_USE_PLUGIN_HOST=1 で PluginHost を有効化。
|
||||||
/// Phase 92 では skeleton のみ(todo!() を呼ぶ)。
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn initialize_runtime(ring0: std::sync::Arc<Ring0Context>) -> Result<plugin_host::PluginHost, CoreInitError> {
|
pub fn initialize_runtime(ring0: std::sync::Arc<Ring0Context>) -> Result<plugin_host::PluginHost, CoreInitError> {
|
||||||
use crate::box_factory::UnifiedBoxRegistry;
|
use crate::box_factory::UnifiedBoxRegistry;
|
||||||
|
|
||||||
let registry = UnifiedBoxRegistry::new();
|
let registry = UnifiedBoxRegistry::with_env_policy();
|
||||||
|
|
||||||
// Phase 92: 接続ポイント決定(実装は Phase 93)
|
// Phase 93: 環境変数で有効化(段階的展開)
|
||||||
let plugin_host = plugin_host::PluginHost::with_core_from_registry(ring0, ®istry)?;
|
let use_plugin_host = std::env::var("NYASH_USE_PLUGIN_HOST")
|
||||||
|
.ok()
|
||||||
|
.and_then(|v| if v == "1" { Some(()) } else { None })
|
||||||
|
.is_some();
|
||||||
|
|
||||||
Ok(plugin_host)
|
if use_plugin_host {
|
||||||
|
let plugin_host = plugin_host::PluginHost::with_core_from_registry(ring0, ®istry)?;
|
||||||
|
plugin_host.ensure_core_initialized();
|
||||||
|
Ok(plugin_host)
|
||||||
|
} else {
|
||||||
|
// フォールバック(Phase 94 で削除予定)
|
||||||
|
let core = core_services::CoreServices::dummy();
|
||||||
|
Ok(plugin_host::PluginHost {
|
||||||
|
ring0,
|
||||||
|
core,
|
||||||
|
optional: std::collections::HashMap::new(),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -90,17 +90,40 @@ impl PluginHost {
|
|||||||
|
|
||||||
/// UnifiedBoxRegistry から core_required Box を取得して CoreServices を初期化
|
/// UnifiedBoxRegistry から core_required Box を取得して CoreServices を初期化
|
||||||
///
|
///
|
||||||
/// Phase 92: skeleton のみ(Phase 93 で実装)
|
/// Phase 93: ダミー Service 実装(存在確認のみ)
|
||||||
#[allow(dead_code)]
|
/// Phase 94: 実際の Box → Service 変換実装予定
|
||||||
pub fn with_core_from_registry(
|
pub fn with_core_from_registry(
|
||||||
ring0: Arc<Ring0Context>,
|
ring0: Arc<Ring0Context>,
|
||||||
_registry: &UnifiedBoxRegistry,
|
registry: &UnifiedBoxRegistry,
|
||||||
) -> Result<Self, CoreInitError> {
|
) -> Result<Self, CoreInitError> {
|
||||||
// Phase 93 で実装予定
|
// Phase 93: 各 core_required Box が registry に存在するか確認
|
||||||
// TODO: registry から core_required Box を取得
|
for id in CoreServices::required_ids() {
|
||||||
// TODO: 各 Box を対応する Service trait に変換
|
let box_name = id.name();
|
||||||
// TODO: CoreServices を構築
|
|
||||||
todo!("Phase 93: UnifiedBoxRegistry から CoreServices への変換実装")
|
// Phase 93: has_type() で存在確認
|
||||||
|
if !registry.has_type(box_name) {
|
||||||
|
return Err(CoreInitError::MissingService {
|
||||||
|
box_id: *id,
|
||||||
|
message: format!("{} not found in registry", box_name),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 93: ダミー Service 実装で CoreServices を構築
|
||||||
|
let core = CoreServices {
|
||||||
|
string: Arc::new(DummyStringService),
|
||||||
|
integer: Arc::new(DummyIntegerService),
|
||||||
|
bool: Arc::new(DummyBoolService),
|
||||||
|
array: Arc::new(DummyArrayService),
|
||||||
|
map: Arc::new(DummyMapService),
|
||||||
|
console: Arc::new(DummyConsoleService),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(PluginHost {
|
||||||
|
ring0,
|
||||||
|
core,
|
||||||
|
optional: HashMap::new(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// core_required が全て揃っているか検証
|
/// core_required が全て揃っているか検証
|
||||||
@ -109,6 +132,25 @@ impl PluginHost {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Phase 93: ダミー Service 実装(Phase 94 で削除予定)
|
||||||
|
pub struct DummyStringService;
|
||||||
|
impl super::core_services::StringService for DummyStringService {}
|
||||||
|
|
||||||
|
pub struct DummyIntegerService;
|
||||||
|
impl super::core_services::IntegerService for DummyIntegerService {}
|
||||||
|
|
||||||
|
pub struct DummyBoolService;
|
||||||
|
impl super::core_services::BoolService for DummyBoolService {}
|
||||||
|
|
||||||
|
pub struct DummyArrayService;
|
||||||
|
impl super::core_services::ArrayService for DummyArrayService {}
|
||||||
|
|
||||||
|
pub struct DummyMapService;
|
||||||
|
impl super::core_services::MapService for DummyMapService {}
|
||||||
|
|
||||||
|
pub struct DummyConsoleService;
|
||||||
|
impl super::core_services::ConsoleService for DummyConsoleService {}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -132,25 +174,6 @@ mod tests {
|
|||||||
// panic しないことを確認
|
// panic しないことを確認
|
||||||
}
|
}
|
||||||
|
|
||||||
// ダミー Service 実装
|
|
||||||
struct DummyStringService;
|
|
||||||
impl StringService for DummyStringService {}
|
|
||||||
|
|
||||||
struct DummyIntegerService;
|
|
||||||
impl IntegerService for DummyIntegerService {}
|
|
||||||
|
|
||||||
struct DummyBoolService;
|
|
||||||
impl BoolService for DummyBoolService {}
|
|
||||||
|
|
||||||
struct DummyArrayService;
|
|
||||||
impl ArrayService for DummyArrayService {}
|
|
||||||
|
|
||||||
struct DummyMapService;
|
|
||||||
impl MapService for DummyMapService {}
|
|
||||||
|
|
||||||
struct DummyConsoleService;
|
|
||||||
impl ConsoleService for DummyConsoleService {}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_core_services_all_fields() {
|
fn test_core_services_all_fields() {
|
||||||
let services = CoreServices {
|
let services = CoreServices {
|
||||||
@ -223,14 +246,19 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Phase 93")]
|
fn test_with_core_from_registry_missing_box() {
|
||||||
fn test_with_core_from_registry_todo() {
|
// Phase 93: registry が空の場合はエラーを返すことを確認
|
||||||
// Phase 92: todo!() を返すことを確認
|
|
||||||
use crate::runtime::ring0::default_ring0;
|
use crate::runtime::ring0::default_ring0;
|
||||||
let ring0 = Arc::new(default_ring0());
|
let ring0 = Arc::new(default_ring0());
|
||||||
let registry = UnifiedBoxRegistry::new();
|
let registry = UnifiedBoxRegistry::new();
|
||||||
|
|
||||||
let _result = PluginHost::with_core_from_registry(ring0, ®istry);
|
let result = PluginHost::with_core_from_registry(ring0, ®istry);
|
||||||
// Phase 93 で実装後はこのテストを削除
|
assert!(result.is_err());
|
||||||
|
|
||||||
|
// エラーメッセージに "not found" が含まれることを確認
|
||||||
|
if let Err(e) = result {
|
||||||
|
let msg = format!("{}", e);
|
||||||
|
assert!(msg.contains("not found"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user