Files
hakorune/src/box_factory/mod.rs
Tomoaki a2b89fae7e phase15: update CLAUDE.md and sync with current progress
- Update phase indicator to Phase 15 (Self-Hosting)
- Update documentation links to Phase 15 resources
- Reflect completion of R1-R5 tasks and ongoing work
- Fix CURRENT_TASK.md location to root directory

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-05 13:29:17 +09:00

232 lines
8.0 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!
* Unified Box Factory Architecture
*
* Phase 9.78: 統合BoxFactoryアーキテクチャ
* すべてのBox生成ビルトイン、ユーザー定義、プラグインを統一的に扱う
*
* Design principles:
* - "Everything is Box" 哲学の実装レベルでの体現
* - birth/finiライフサイクルの明確な責務分離
* - 保守性と拡張性の劇的向上
*/
use crate::box_trait::NyashBox;
use crate::interpreter::RuntimeError;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
/// Unified interface for all Box creation
pub trait BoxFactory: Send + Sync {
/// Create a new Box instance with given arguments
fn create_box(
&self,
name: &str,
args: &[Box<dyn NyashBox>],
) -> Result<Box<dyn NyashBox>, RuntimeError>;
/// Check if this factory is currently available
fn is_available(&self) -> bool {
true
}
/// Get list of Box types this factory can create
fn box_types(&self) -> Vec<&str>;
/// Check if this factory supports birth/fini lifecycle
fn supports_birth(&self) -> bool {
true
}
/// Identify builtin factory to enforce reserved-name protections
fn is_builtin_factory(&self) -> bool {
false
}
}
/// Registry that manages all BoxFactory implementations
pub struct UnifiedBoxRegistry {
/// Ordered list of factories (priority: builtin > user > plugin)
pub factories: Vec<Arc<dyn BoxFactory>>,
/// Quick lookup cache for performance
type_cache: RwLock<HashMap<String, usize>>, // maps type name to factory index
}
impl UnifiedBoxRegistry {
/// Create a new empty registry
pub fn new() -> Self {
Self {
factories: Vec::new(),
type_cache: RwLock::new(HashMap::new()),
}
}
/// Register a new factory
pub fn register(&mut self, factory: Arc<dyn BoxFactory>) {
// Get all types this factory can create
let types = factory.box_types();
let factory_index = self.factories.len();
// Update cache
let mut cache = self.type_cache.write().unwrap();
// Reserved core types that must remain builtin-owned
fn is_reserved_type(name: &str) -> bool {
matches!(
name,
// Core value types
"StringBox" | "IntegerBox" | "BoolBox" | "FloatBox" | "NullBox"
// Core containers and result
| "ArrayBox" | "MapBox" | "ResultBox"
// Core method indirection
| "MethodBox"
)
}
for type_name in types {
// Enforce reserved names: only builtin factory may claim them
if is_reserved_type(type_name) && !factory.is_builtin_factory() {
eprintln!(
"[UnifiedBoxRegistry] ❌ Rejecting registration of reserved type '{}' by non-builtin factory #{}",
type_name, factory_index
);
continue;
}
// First registered factory wins (priority order)
let entry = cache.entry(type_name.to_string());
use std::collections::hash_map::Entry;
match entry {
Entry::Occupied(existing) => {
// Collision: type already claimed by earlier factory
eprintln!("[UnifiedBoxRegistry] ⚠️ Duplicate registration for '{}': keeping factory #{}, ignoring later factory #{}",
existing.key(), existing.get(), factory_index);
}
Entry::Vacant(v) => {
v.insert(factory_index);
}
}
}
self.factories.push(factory);
}
/// Create a Box using the unified interface
pub fn create_box(
&self,
name: &str,
args: &[Box<dyn NyashBox>],
) -> Result<Box<dyn NyashBox>, RuntimeError> {
// Prefer plugin-builtins when enabled and provider is available in v2 registry
if std::env::var("NYASH_USE_PLUGIN_BUILTINS").ok().as_deref() == Some("1") {
use crate::runtime::{get_global_registry, BoxProvider};
// Allowlist types for override: env NYASH_PLUGIN_OVERRIDE_TYPES="ArrayBox,MapBox" (default: ArrayBox,MapBox)
let allow: Vec<String> = if let Ok(list) = std::env::var("NYASH_PLUGIN_OVERRIDE_TYPES") {
list.split(',').map(|s| s.trim().to_string()).filter(|s| !s.is_empty()).collect()
} else {
vec!["ArrayBox".into(), "MapBox".into()]
};
if allow.iter().any(|t| t == name) {
let v2 = get_global_registry();
if let Some(provider) = v2.get_provider(name) {
if let BoxProvider::Plugin(_lib) = provider {
return v2.create_box(name, args)
.map_err(|e| RuntimeError::InvalidOperation { message: format!("Plugin Box creation failed: {}", e) });
}
}
}
}
// Check cache first
let cache = self.type_cache.read().unwrap();
if let Some(&factory_index) = cache.get(name) {
if let Some(factory) = self.factories.get(factory_index) {
if factory.is_available() {
return factory.create_box(name, args);
}
}
}
drop(cache);
// Linear search through all factories
for factory in &self.factories {
if !factory.is_available() {
continue;
}
// For factories that advertise types, check if they support this type
let box_types = factory.box_types();
if !box_types.is_empty() && !box_types.contains(&name) {
continue;
}
// Try to create the box (factories with empty box_types() will always be tried)
match factory.create_box(name, args) {
Ok(boxed) => return Ok(boxed),
Err(_) => continue, // Try next factory
}
}
// Final fallback: if v2 plugin registry has a provider for this name, try it once
{
let v2 = crate::runtime::get_global_registry();
if let Some(_prov) = v2.get_provider(name) {
if let Ok(b) = v2.create_box(name, args) {
return Ok(b);
}
}
}
Err(RuntimeError::InvalidOperation {
message: format!("Unknown Box type: {}", name),
})
}
/// Check whether a type name is known to the registry
pub fn has_type(&self, name: &str) -> bool {
// Check cache first
{
let cache = self.type_cache.read().unwrap();
if let Some(&idx) = cache.get(name) {
if let Some(factory) = self.factories.get(idx) {
if factory.is_available() { return true; }
}
}
}
// Fallback: scan factories that can enumerate types
for factory in &self.factories {
if !factory.is_available() { continue; }
let types = factory.box_types();
if !types.is_empty() && types.contains(&name) { return true; }
}
false
}
/// Get all available Box types
pub fn available_types(&self) -> Vec<String> {
let mut types = Vec::new();
for factory in &self.factories {
if factory.is_available() {
for type_name in factory.box_types() {
types.push(type_name.to_string());
}
}
}
types.sort();
types.dedup();
types
}
}
/// Re-export submodules
pub mod user_defined;
pub mod plugin;
pub mod builtin;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_registry_creation() {
let registry = UnifiedBoxRegistry::new();
assert_eq!(registry.available_types().len(), 0);
}
}