Files
hakorune/src/runner/modes/common_util/provider_registry.rs
nyash-codex 6055d53eff feat(phase21.5/22.1): MirBuilder JsonFrag refactor + FileBox ring-1 + registry tests
Phase 21.5 (AOT/LLVM Optimization Prep)
- FileBox ring-1 (core-ro) provider: priority=-100, always available, no panic path
  - src/runner/modes/common_util/provider_registry.rs: CoreRoFileProviderFactory
  - Auto-registers at startup, eliminates fallback panic structurally
- StringBox fast path prototypes (length/size optimization)
- Performance benchmarks (C/Python/Hako comparison baseline)

Phase 22.1 (JsonFrag Unification)
- JsonFrag.last_index_of_from() for backward search (VM fallback)
- Replace hand-written lastIndexOf in lower_loop_sum_bc_box.hako
- SentinelExtractorBox for Break/Continue pattern extraction

MirBuilder Refactor (Box → JsonFrag Migration)
- 20+ lower_*_box.hako: Box-heavy → JsonFrag text assembly
- MirBuilderMinBox: lightweight using set for dev env
- Registry-only fast path with [registry:*] tag observation
- pattern_util_box.hako: enhanced pattern matching

Dev Environment & Testing
- Dev toggles: SMOKES_DEV_PREINCLUDE=1 (point-enable), HAKO_MIR_BUILDER_SKIP_LOOPS=1
- phase2160: registry opt-in tests (array/map get/set/push/len) - content verification
- phase2034: rc-dependent → token grep (grep -F based validation)
- run_quick.sh: fast smoke testing harness
- ENV documentation: docs/ENV_VARS.md

Test Results
 quick phase2034: ALL GREEN (MirBuilder internal patterns)
 registry phase2160: ALL GREEN (array/map get/set/push/len)
 rc-dependent tests → content token verification complete
 PREINCLUDE policy: default OFF, point-enable only where needed

Technical Notes
- No INCLUDE by default (maintain minimalism)
- FAIL_FAST=0 in Bring-up contexts only (explicit dev toggles)
- Tag-based route observation ([mirbuilder/min:*], [registry:*])
- MIR structure validation (not just rc parity)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 19:42:42 +09:00

147 lines
6.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.

//! Provider registry: selects concrete providers for core resources (e.g. FileBox).
//! SSOT (Single Source of Truth) for provider selection via ProviderFactory registration.
use std::sync::{Arc, Mutex, OnceLock};
use crate::boxes::file::provider::FileIo;
use crate::boxes::file::core_ro::CoreRoFileIo;
#[allow(dead_code)]
pub enum FileBoxMode { Auto, CoreRo, PluginOnly }
/// Factory for creating FileIo providers
pub trait ProviderFactory: Send + Sync {
fn box_name(&self) -> &str;
fn create_provider(&self) -> Arc<dyn FileIo>;
fn is_available(&self) -> bool;
fn priority(&self) -> i32 {
0 // Default priority (higher = preferred)
}
}
/// Global registry of provider factories
static PROVIDER_FACTORIES: OnceLock<Mutex<Vec<Arc<dyn ProviderFactory>>>> = OnceLock::new();
/// Register a provider factory (called by builtin/dynamic loaders)
pub fn register_provider_factory(factory: Arc<dyn ProviderFactory>) {
let registry = PROVIDER_FACTORIES.get_or_init(|| Mutex::new(Vec::new()));
registry.lock().unwrap().push(factory);
}
/// Builtin ring1 FileBox provider (corero) — always available, lowest priority
struct CoreRoFileProviderFactory;
impl ProviderFactory for CoreRoFileProviderFactory {
fn box_name(&self) -> &str { "FileBox" }
fn create_provider(&self) -> Arc<dyn FileIo> { Arc::new(CoreRoFileIo::new()) }
fn is_available(&self) -> bool { true }
fn priority(&self) -> i32 { -100 } // ring1: lower than any plugin/provider
}
/// Ensure ring1 (corero) provider is present in the registry
fn ensure_builtin_file_provider_registered() {
let reg = PROVIDER_FACTORIES.get_or_init(|| Mutex::new(Vec::new()));
let mut guard = reg.lock().unwrap();
// If at least one FileBox provider exists, we still keep ring1 present for safety; avoid duplicates by checking any corero present by priority
let has_core_ro = guard.iter().any(|f| f.box_name() == "FileBox" && f.priority() <= -100);
if !has_core_ro {
guard.push(Arc::new(CoreRoFileProviderFactory));
}
}
/// Read FileBox mode from environment variables
#[allow(dead_code)]
pub fn read_filebox_mode_from_env() -> FileBoxMode {
match std::env::var("NYASH_FILEBOX_MODE").unwrap_or_else(|_| "auto".to_string()).as_str() {
"core-ro" => FileBoxMode::CoreRo,
"plugin-only" => FileBoxMode::PluginOnly,
_ => {
if std::env::var("NYASH_DISABLE_PLUGINS").as_deref() == Ok("1") {
FileBoxMode::CoreRo
} else { FileBoxMode::Auto }
}
}
}
/// Select provider based on mode and registered factories (SSOT)
#[allow(dead_code)]
pub fn select_file_provider(mode: FileBoxMode) -> Arc<dyn FileIo> {
let quiet_pipe = crate::config::env::env_bool("NYASH_JSON_ONLY");
// Always ensure ring1 (corero) exists before inspecting registry
ensure_builtin_file_provider_registered();
let registry = PROVIDER_FACTORIES.get();
match mode {
FileBoxMode::Auto => {
// Try: dynamic/builtin (by priority) → core-ro fallback
if let Some(reg) = registry {
let mut factories: Vec<_> = reg.lock().unwrap()
.iter()
.filter(|f| f.box_name() == "FileBox" && f.is_available())
.cloned()
.collect();
// Sort by priority (descending)
factories.sort_by(|a, b| b.priority().cmp(&a.priority()));
if let Some(factory) = factories.first() {
if !quiet_pipe {
eprintln!("[provider-registry] FileBox: using registered provider (priority={})", factory.priority());
}
return factory.create_provider();
}
}
// Fallback policy
// Allow a narrow, explicit carveout:
// - When JSONonly pipeline is active (quiet structured I/O), or
// - When NYASH_FILEBOX_ALLOW_FALLBACK=1 is set,
// always use corero provider even if FailFast is ON.
let allow_fb_override =
crate::config::env::env_bool("NYASH_JSON_ONLY") ||
crate::config::env::env_bool("NYASH_FILEBOX_ALLOW_FALLBACK");
if crate::config::env::fail_fast() && !allow_fb_override {
eprintln!("[failfast/provider/filebox:auto-fallback-blocked]");
panic!("Fail-Fast: FileBox provider fallback is disabled (NYASH_FAIL_FAST=0 or NYASH_FILEBOX_ALLOW_FALLBACK=1 to override)");
} else {
if !quiet_pipe {
eprintln!(
"[provider-registry] FileBox: using core-ro fallback{}",
if allow_fb_override { " (override)" } else { "" }
);
}
Arc::new(CoreRoFileIo::new())
}
}
FileBoxMode::PluginOnly => {
// Try only registered providers, Fail-Fast if none available
if let Some(reg) = registry {
let mut factories: Vec<_> = reg.lock().unwrap()
.iter()
.filter(|f| f.box_name() == "FileBox" && f.is_available())
.cloned()
.collect();
factories.sort_by(|a, b| b.priority().cmp(&a.priority()));
if let Some(factory) = factories.first() {
if !quiet_pipe {
eprintln!("[provider-registry] FileBox: using plugin-only provider (priority={})", factory.priority());
}
return factory.create_provider();
}
}
panic!("FileBox plugin-only mode: no provider registered. Set NYASH_FILEBOX_MODE=auto or NYASH_FILEBOX_MODE=core-ro to use fallback.");
}
FileBoxMode::CoreRo => {
// Always use core-ro, ignore registry
if !quiet_pipe {
eprintln!("[provider-registry] FileBox: using core-ro (forced)");
}
Arc::new(CoreRoFileIo::new())
}
}
}