feat(phase94): Box→Service conversion with actual registry integration
Phase 94完全達成 - UnifiedBoxRegistryから実際のBoxを取得してServiceに変換 ### 実装成果 - ✅ 6個のAdapter実装(StringBox/Integer/Bool/Array/Map/Console) - ✅ Dummy実装完全削除(38行削減) - ✅ Fail-Fast原則徹底(フォールバック削除) - ✅ テスト7/7 PASS(100%) ### 変更ファイル - src/runtime/core_services.rs: 6個のAdapter実装(+93行) - src/runtime/plugin_host.rs: 実際のBox取得ロジック(+54行)、Dummy削除(-17行) - src/runtime/mod.rs: フォールバック削除(-8行) ### 技術的成果 - Box<dyn NyashBox>を直接保持(型安全性確保) - registry.create_box()で実際のBoxインスタンス取得 - BuiltinBoxFactory登録でcore_required Boxes提供 ### 次のステップ Phase 95: Service traitメソッド実装(Console/String/Array/Map) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
# Core Boxes 設計ドキュメント(Phase 87 完了版)
|
# Core Boxes 設計ドキュメント(Phase 87–94 完了版)
|
||||||
|
|
||||||
Phase 87 で実装された CoreBoxId/CoreMethodId の完全仕様。
|
Phase 87 で実装された CoreBoxId/CoreMethodId と、Phase 91–94 で統合された CoreServices/PluginHost/Adapter の仕様。
|
||||||
|
|
||||||
**目的**: Box名・メソッド名のハードコードを型安全な enum に箱化することで、以下を実現:
|
**目的**: Box名・メソッド名のハードコードを型安全な enum に箱化することで、以下を実現:
|
||||||
- ✅ コンパイル時検証(タイポ撲滅)
|
- ✅ コンパイル時検証(タイポ撲滅)
|
||||||
@ -8,7 +8,10 @@ Phase 87 で実装された CoreBoxId/CoreMethodId の完全仕様。
|
|||||||
- ✅ SSOT(Single Source of Truth)確立
|
- ✅ SSOT(Single Source of Truth)確立
|
||||||
- ✅ 保守性向上
|
- ✅ 保守性向上
|
||||||
|
|
||||||
**実装状況**: ✅ Phase 87 完了(2025-12-02)
|
**実装状況**:
|
||||||
|
- ✅ Phase 87: CoreBoxId/CoreMethodId 実装
|
||||||
|
- ✅ Phase 91: CoreServices/PluginHost skeleton
|
||||||
|
- ✅ Phase 94: Box → Service Adapter 実装と Dummy 削除
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -546,4 +549,3 @@ NYASH_USE_PLUGIN_HOST=1 ./target/release/nyash apps/tests/selfhost_min.hako
|
|||||||
2. `src/runtime/core_services.rs`: CoreServices::dummy() ヘルパー
|
2. `src/runtime/core_services.rs`: CoreServices::dummy() ヘルパー
|
||||||
3. `src/runtime/mod.rs`: initialize_runtime() 実装(環境変数制御)
|
3. `src/runtime/mod.rs`: initialize_runtime() 実装(環境変数制御)
|
||||||
4. `src/runner/selfhost.rs`: PluginHost 初期化追加
|
4. `src/runner/selfhost.rs`: PluginHost 初期化追加
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use crate::runtime::CoreBoxId;
|
use crate::runtime::CoreBoxId;
|
||||||
|
use crate::box_trait::NyashBox;
|
||||||
|
|
||||||
/// StringBox Service trait
|
/// StringBox Service trait
|
||||||
pub trait StringService: Send + Sync {
|
pub trait StringService: Send + Sync {
|
||||||
@ -80,20 +81,108 @@ impl CoreServices {
|
|||||||
// Phase 92 以降で各 Service の初期化を検証
|
// Phase 92 以降で各 Service の初期化を検証
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Phase 93: ダミー実装(Phase 94 で削除予定)
|
}
|
||||||
pub fn dummy() -> Self {
|
|
||||||
use crate::runtime::plugin_host::*;
|
// ============================================================================
|
||||||
Self {
|
// Phase 94: Adapter Pattern - Box → Service 変換
|
||||||
string: Arc::new(DummyStringService),
|
// ============================================================================
|
||||||
integer: Arc::new(DummyIntegerService),
|
|
||||||
bool: Arc::new(DummyBoolService),
|
/// StringBox → StringService Adapter
|
||||||
array: Arc::new(DummyArrayService),
|
pub struct StringBoxAdapter {
|
||||||
map: Arc::new(DummyMapService),
|
#[allow(dead_code)]
|
||||||
console: Arc::new(DummyConsoleService),
|
inner: Box<dyn NyashBox>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StringBoxAdapter {
|
||||||
|
pub fn new(box_instance: Box<dyn NyashBox>) -> Self {
|
||||||
|
Self { inner: box_instance }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StringService for StringBoxAdapter {
|
||||||
|
// Phase 95 以降で実装
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IntegerBox → IntegerService Adapter
|
||||||
|
pub struct IntegerBoxAdapter {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
inner: Box<dyn NyashBox>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntegerBoxAdapter {
|
||||||
|
pub fn new(box_instance: Box<dyn NyashBox>) -> Self {
|
||||||
|
Self { inner: box_instance }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IntegerService for IntegerBoxAdapter {
|
||||||
|
// Phase 95 以降で実装
|
||||||
|
}
|
||||||
|
|
||||||
|
/// BoolBox → BoolService Adapter
|
||||||
|
pub struct BoolBoxAdapter {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
inner: Box<dyn NyashBox>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BoolBoxAdapter {
|
||||||
|
pub fn new(box_instance: Box<dyn NyashBox>) -> Self {
|
||||||
|
Self { inner: box_instance }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BoolService for BoolBoxAdapter {
|
||||||
|
// Phase 95 以降で実装
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ArrayBox → ArrayService Adapter
|
||||||
|
pub struct ArrayBoxAdapter {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
inner: Box<dyn NyashBox>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArrayBoxAdapter {
|
||||||
|
pub fn new(box_instance: Box<dyn NyashBox>) -> Self {
|
||||||
|
Self { inner: box_instance }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArrayService for ArrayBoxAdapter {
|
||||||
|
// Phase 95 以降で実装
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MapBox → MapService Adapter
|
||||||
|
pub struct MapBoxAdapter {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
inner: Box<dyn NyashBox>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MapBoxAdapter {
|
||||||
|
pub fn new(box_instance: Box<dyn NyashBox>) -> Self {
|
||||||
|
Self { inner: box_instance }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MapService for MapBoxAdapter {
|
||||||
|
// Phase 95 以降で実装
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ConsoleBox → ConsoleService Adapter
|
||||||
|
pub struct ConsoleBoxAdapter {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
inner: Box<dyn NyashBox>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConsoleBoxAdapter {
|
||||||
|
pub fn new(box_instance: Box<dyn NyashBox>) -> Self {
|
||||||
|
Self { inner: box_instance }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConsoleService for ConsoleBoxAdapter {
|
||||||
|
// Phase 95 以降で実装
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@ -59,31 +59,20 @@ 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 93: 実装完了)
|
/// Runtime 初期化(Phase 94: Fail-Fast 実装完了)
|
||||||
///
|
///
|
||||||
/// 環境変数 NYASH_USE_PLUGIN_HOST=1 で PluginHost を有効化。
|
/// Phase 94: フォールバック削除 - 常に実際の Box を使用
|
||||||
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;
|
||||||
|
use crate::box_factory::builtin::BuiltinBoxFactory;
|
||||||
|
|
||||||
let registry = UnifiedBoxRegistry::with_env_policy();
|
let mut registry = UnifiedBoxRegistry::with_env_policy();
|
||||||
|
|
||||||
// Phase 93: 環境変数で有効化(段階的展開)
|
// Phase 94: BuiltinBoxFactory を登録して core_required Boxes を提供
|
||||||
let use_plugin_host = std::env::var("NYASH_USE_PLUGIN_HOST")
|
registry.register(std::sync::Arc::new(BuiltinBoxFactory::new()));
|
||||||
.ok()
|
|
||||||
.and_then(|v| if v == "1" { Some(()) } else { None })
|
|
||||||
.is_some();
|
|
||||||
|
|
||||||
if use_plugin_host {
|
// Phase 94: 常に実際の Box → Service 変換を使用(Fail-Fast原則)
|
||||||
let plugin_host = plugin_host::PluginHost::with_core_from_registry(ring0, ®istry)?;
|
let plugin_host = plugin_host::PluginHost::with_core_from_registry(ring0, ®istry)?;
|
||||||
plugin_host.ensure_core_initialized();
|
plugin_host.ensure_core_initialized();
|
||||||
Ok(plugin_host)
|
Ok(plugin_host)
|
||||||
} else {
|
|
||||||
// フォールバック(Phase 94 で削除予定)
|
|
||||||
let core = core_services::CoreServices::dummy();
|
|
||||||
Ok(plugin_host::PluginHost {
|
|
||||||
ring0,
|
|
||||||
core,
|
|
||||||
optional: std::collections::HashMap::new(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -90,33 +90,77 @@ impl PluginHost {
|
|||||||
|
|
||||||
/// UnifiedBoxRegistry から core_required Box を取得して CoreServices を初期化
|
/// UnifiedBoxRegistry から core_required Box を取得して CoreServices を初期化
|
||||||
///
|
///
|
||||||
/// Phase 93: ダミー Service 実装(存在確認のみ)
|
/// Phase 94: 実際の Box → Service 変換実装
|
||||||
/// 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: 各 core_required Box が registry に存在するか確認
|
use crate::runtime::core_services::*;
|
||||||
for id in CoreServices::required_ids() {
|
|
||||||
let box_name = id.name();
|
|
||||||
|
|
||||||
// Phase 93: has_type() で存在確認
|
// Phase 94: 各 core_required Box を取得して Adapter に変換
|
||||||
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 を構築
|
// 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));
|
||||||
|
|
||||||
|
// IntegerBox
|
||||||
|
let integer_box = registry
|
||||||
|
.create_box("IntegerBox", &[])
|
||||||
|
.map_err(|e| CoreInitError::MissingService {
|
||||||
|
box_id: CoreBoxId::Integer,
|
||||||
|
message: format!("IntegerBox creation failed: {}", e),
|
||||||
|
})?;
|
||||||
|
let integer_service = Arc::new(IntegerBoxAdapter::new(integer_box));
|
||||||
|
|
||||||
|
// BoolBox
|
||||||
|
let bool_box = registry
|
||||||
|
.create_box("BoolBox", &[])
|
||||||
|
.map_err(|e| CoreInitError::MissingService {
|
||||||
|
box_id: CoreBoxId::Bool,
|
||||||
|
message: format!("BoolBox creation failed: {}", e),
|
||||||
|
})?;
|
||||||
|
let bool_service = Arc::new(BoolBoxAdapter::new(bool_box));
|
||||||
|
|
||||||
|
// ArrayBox
|
||||||
|
let array_box = registry
|
||||||
|
.create_box("ArrayBox", &[])
|
||||||
|
.map_err(|e| CoreInitError::MissingService {
|
||||||
|
box_id: CoreBoxId::Array,
|
||||||
|
message: format!("ArrayBox creation failed: {}", e),
|
||||||
|
})?;
|
||||||
|
let array_service = Arc::new(ArrayBoxAdapter::new(array_box));
|
||||||
|
|
||||||
|
// MapBox
|
||||||
|
let map_box = registry
|
||||||
|
.create_box("MapBox", &[])
|
||||||
|
.map_err(|e| CoreInitError::MissingService {
|
||||||
|
box_id: CoreBoxId::Map,
|
||||||
|
message: format!("MapBox creation failed: {}", e),
|
||||||
|
})?;
|
||||||
|
let map_service = Arc::new(MapBoxAdapter::new(map_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));
|
||||||
|
|
||||||
|
// Phase 94: 実際の Adapter を使用して CoreServices を構築
|
||||||
let core = CoreServices {
|
let core = CoreServices {
|
||||||
string: Arc::new(DummyStringService),
|
string: string_service,
|
||||||
integer: Arc::new(DummyIntegerService),
|
integer: integer_service,
|
||||||
bool: Arc::new(DummyBoolService),
|
bool: bool_service,
|
||||||
array: Arc::new(DummyArrayService),
|
array: array_service,
|
||||||
map: Arc::new(DummyMapService),
|
map: map_service,
|
||||||
console: Arc::new(DummyConsoleService),
|
console: console_service,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(PluginHost {
|
Ok(PluginHost {
|
||||||
@ -132,25 +176,6 @@ 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::*;
|
||||||
@ -176,38 +201,42 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_core_services_all_fields() {
|
fn test_core_services_all_fields() {
|
||||||
let services = CoreServices {
|
// Phase 94: 実際の registry を使用してテスト
|
||||||
string: Arc::new(DummyStringService),
|
use crate::runtime::ring0::default_ring0;
|
||||||
integer: Arc::new(DummyIntegerService),
|
use crate::box_factory::builtin::BuiltinBoxFactory;
|
||||||
bool: Arc::new(DummyBoolService),
|
|
||||||
array: Arc::new(DummyArrayService),
|
let ring0 = Arc::new(default_ring0());
|
||||||
map: Arc::new(DummyMapService),
|
let mut registry = UnifiedBoxRegistry::new();
|
||||||
console: Arc::new(DummyConsoleService),
|
registry.register(Arc::new(BuiltinBoxFactory::new()));
|
||||||
};
|
|
||||||
services.ensure_initialized();
|
let plugin_host = PluginHost::with_core_from_registry(ring0, ®istry)
|
||||||
// panic しないことを確認(Phase 92 で検証ロジック追加予定)
|
.expect("CoreServices should be initialized with builtin boxes");
|
||||||
|
|
||||||
|
plugin_host.ensure_core_initialized();
|
||||||
|
// panic しないことを確認
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_core_services_coverage() {
|
fn test_core_services_coverage() {
|
||||||
// Phase 87 CoreBoxId の core_required (6個) 全てをカバーすることを検証
|
// Phase 94: 実際の registry を使用して全フィールドが存在することを確認
|
||||||
let services = CoreServices {
|
use crate::runtime::ring0::default_ring0;
|
||||||
string: Arc::new(DummyStringService),
|
use crate::box_factory::builtin::BuiltinBoxFactory;
|
||||||
integer: Arc::new(DummyIntegerService),
|
|
||||||
bool: Arc::new(DummyBoolService),
|
let ring0 = Arc::new(default_ring0());
|
||||||
array: Arc::new(DummyArrayService),
|
let mut registry = UnifiedBoxRegistry::new();
|
||||||
map: Arc::new(DummyMapService),
|
registry.register(Arc::new(BuiltinBoxFactory::new()));
|
||||||
console: Arc::new(DummyConsoleService),
|
|
||||||
};
|
let plugin_host = PluginHost::with_core_from_registry(ring0, ®istry)
|
||||||
|
.expect("CoreServices should be initialized");
|
||||||
|
|
||||||
// Phase 87 core_required (6個) と一致することを確認
|
// Phase 87 core_required (6個) と一致することを確認
|
||||||
// String, Integer, Bool, Array, Map, Console
|
// String, Integer, Bool, Array, Map, Console
|
||||||
let _string = &services.string;
|
let _string = &plugin_host.core.string;
|
||||||
let _integer = &services.integer;
|
let _integer = &plugin_host.core.integer;
|
||||||
let _bool = &services.bool;
|
let _bool = &plugin_host.core.bool;
|
||||||
let _array = &services.array;
|
let _array = &plugin_host.core.array;
|
||||||
let _map = &services.map;
|
let _map = &plugin_host.core.map;
|
||||||
let _console = &services.console;
|
let _console = &plugin_host.core.console;
|
||||||
|
|
||||||
// 全フィールドが存在することを確認
|
// 全フィールドが存在することを確認
|
||||||
}
|
}
|
||||||
@ -247,7 +276,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_with_core_from_registry_missing_box() {
|
fn test_with_core_from_registry_missing_box() {
|
||||||
// Phase 93: registry が空の場合はエラーを返すことを確認
|
// Phase 94: registry が空の場合はエラーを返すことを確認
|
||||||
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();
|
||||||
@ -255,10 +284,15 @@ mod tests {
|
|||||||
let result = PluginHost::with_core_from_registry(ring0, ®istry);
|
let result = PluginHost::with_core_from_registry(ring0, ®istry);
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
|
||||||
// エラーメッセージに "not found" が含まれることを確認
|
// Phase 94: エラーメッセージに "creation failed" または "Unknown Box type" が含まれることを確認
|
||||||
if let Err(e) = result {
|
if let Err(e) = result {
|
||||||
let msg = format!("{}", e);
|
let msg = format!("{}", e);
|
||||||
assert!(msg.contains("not found"));
|
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
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user