Phase 33 NORM canon test: enforce normalized dev route for P1/P2/JP mini
This commit is contained in:
@ -4,8 +4,8 @@
|
||||
//! 旧ビルトイン経路は互換目的のAPIとして最小限に保持(テスト用途)。
|
||||
|
||||
use crate::box_trait::NyashBox;
|
||||
use crate::runtime::plugin_config::PluginConfig;
|
||||
use crate::runtime::get_global_ring0;
|
||||
use crate::runtime::plugin_config::PluginConfig;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
|
||||
@ -95,10 +95,10 @@ impl CoreBoxId {
|
||||
pub fn iter() -> impl Iterator<Item = CoreBoxId> {
|
||||
use CoreBoxId::*;
|
||||
[
|
||||
String, Integer, Bool, Array, Map, Console,
|
||||
Float, Null, File, Path, Regex, Math, Time, Json, Toml,
|
||||
Function, Result, Method, Missing,
|
||||
].into_iter()
|
||||
String, Integer, Bool, Array, Map, Console, Float, Null, File, Path, Regex, Math, Time,
|
||||
Json, Toml, Function, Result, Method, Missing,
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
|
||||
/// 名前からCoreBoxIdを取得
|
||||
@ -148,7 +148,9 @@ impl CoreBoxId {
|
||||
match self {
|
||||
// Phase 106: File を CoreRequired 側に移動(selfhost/通常ランタイムでは必須)
|
||||
String | Integer | Bool | Array | Map | Console | File => CoreBoxCategory::CoreRequired,
|
||||
Float | Null | Path | Regex | Math | Time | Json | Toml => CoreBoxCategory::CoreOptional,
|
||||
Float | Null | Path | Regex | Math | Time | Json | Toml => {
|
||||
CoreBoxCategory::CoreOptional
|
||||
}
|
||||
Function | Result | Method | Missing => CoreBoxCategory::Special,
|
||||
}
|
||||
}
|
||||
@ -213,9 +215,8 @@ impl CoreMethodId {
|
||||
pub fn box_id(&self) -> CoreBoxId {
|
||||
use CoreMethodId::*;
|
||||
match self {
|
||||
StringLength | StringUpper | StringLower |
|
||||
StringConcat | StringSubstring | StringIndexOf |
|
||||
StringReplace | StringTrim | StringSplit => CoreBoxId::String,
|
||||
StringLength | StringUpper | StringLower | StringConcat | StringSubstring
|
||||
| StringIndexOf | StringReplace | StringTrim | StringSplit => CoreBoxId::String,
|
||||
|
||||
IntegerAbs | IntegerMin | IntegerMax => CoreBoxId::Integer,
|
||||
|
||||
@ -282,20 +283,12 @@ impl CoreMethodId {
|
||||
pub fn arity(&self) -> usize {
|
||||
use CoreMethodId::*;
|
||||
match self {
|
||||
StringLength | StringUpper | StringLower | StringTrim |
|
||||
IntegerAbs |
|
||||
BoolNot |
|
||||
ArrayLength | ArrayPop |
|
||||
MapKeys |
|
||||
ResultIsOk | ResultGetValue => 0,
|
||||
StringLength | StringUpper | StringLower | StringTrim | IntegerAbs | BoolNot
|
||||
| ArrayLength | ArrayPop | MapKeys | ResultIsOk | ResultGetValue => 0,
|
||||
|
||||
StringConcat | StringIndexOf | StringReplace | StringSplit |
|
||||
IntegerMin | IntegerMax |
|
||||
BoolAnd | BoolOr |
|
||||
ArrayGet | ArrayPush |
|
||||
MapGet | MapHas |
|
||||
ConsolePrintln | ConsoleLog | ConsoleError |
|
||||
FileRead | FileWrite | FileOpen => 1,
|
||||
StringConcat | StringIndexOf | StringReplace | StringSplit | IntegerMin
|
||||
| IntegerMax | BoolAnd | BoolOr | ArrayGet | ArrayPush | MapGet | MapHas
|
||||
| ConsolePrintln | ConsoleLog | ConsoleError | FileRead | FileWrite | FileOpen => 1,
|
||||
|
||||
StringSubstring | MapSet => 2,
|
||||
}
|
||||
@ -307,16 +300,15 @@ impl CoreMethodId {
|
||||
match self {
|
||||
StringLength | StringIndexOf | ArrayLength => "IntegerBox",
|
||||
|
||||
StringUpper | StringLower | StringConcat | StringSubstring |
|
||||
StringReplace | StringTrim => "StringBox",
|
||||
StringUpper | StringLower | StringConcat | StringSubstring | StringReplace
|
||||
| StringTrim => "StringBox",
|
||||
|
||||
IntegerAbs | IntegerMin | IntegerMax => "IntegerBox",
|
||||
|
||||
BoolNot | BoolAnd | BoolOr | MapHas | ResultIsOk => "BoolBox",
|
||||
|
||||
ArrayPush | ArrayPop | MapSet |
|
||||
ConsolePrintln | ConsoleLog | ConsoleError |
|
||||
FileWrite => "Void",
|
||||
ArrayPush | ArrayPop | MapSet | ConsolePrintln | ConsoleLog | ConsoleError
|
||||
| FileWrite => "Void",
|
||||
|
||||
ArrayGet | MapGet | MapKeys | StringSplit => "Unknown",
|
||||
|
||||
@ -330,16 +322,39 @@ impl CoreMethodId {
|
||||
pub fn iter() -> impl Iterator<Item = CoreMethodId> {
|
||||
use CoreMethodId::*;
|
||||
[
|
||||
StringLength, StringUpper, StringLower, StringConcat, StringSubstring,
|
||||
StringIndexOf, StringReplace, StringTrim, StringSplit,
|
||||
IntegerAbs, IntegerMin, IntegerMax,
|
||||
BoolNot, BoolAnd, BoolOr,
|
||||
ArrayLength, ArrayPush, ArrayPop, ArrayGet,
|
||||
MapGet, MapSet, MapHas, MapKeys,
|
||||
ConsolePrintln, ConsoleLog, ConsoleError,
|
||||
FileRead, FileWrite, FileOpen,
|
||||
ResultIsOk, ResultGetValue,
|
||||
].into_iter()
|
||||
StringLength,
|
||||
StringUpper,
|
||||
StringLower,
|
||||
StringConcat,
|
||||
StringSubstring,
|
||||
StringIndexOf,
|
||||
StringReplace,
|
||||
StringTrim,
|
||||
StringSplit,
|
||||
IntegerAbs,
|
||||
IntegerMin,
|
||||
IntegerMax,
|
||||
BoolNot,
|
||||
BoolAnd,
|
||||
BoolOr,
|
||||
ArrayLength,
|
||||
ArrayPush,
|
||||
ArrayPop,
|
||||
ArrayGet,
|
||||
MapGet,
|
||||
MapSet,
|
||||
MapHas,
|
||||
MapKeys,
|
||||
ConsolePrintln,
|
||||
ConsoleLog,
|
||||
ConsoleError,
|
||||
FileRead,
|
||||
FileWrite,
|
||||
FileOpen,
|
||||
ResultIsOk,
|
||||
ResultGetValue,
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
|
||||
/// Box名とメソッド名から CoreMethodId を取得
|
||||
@ -361,13 +376,11 @@ impl CoreMethodId {
|
||||
use CoreMethodId::*;
|
||||
match self {
|
||||
// String methods (pure - return new values, don't mutate)
|
||||
StringLength | StringUpper | StringLower |
|
||||
StringConcat | StringSubstring | StringIndexOf |
|
||||
StringReplace | StringTrim | StringSplit => true,
|
||||
StringLength | StringUpper | StringLower | StringConcat | StringSubstring
|
||||
| StringIndexOf | StringReplace | StringTrim | StringSplit => true,
|
||||
|
||||
// Integer/Bool methods (pure - mathematical operations)
|
||||
IntegerAbs | IntegerMin | IntegerMax |
|
||||
BoolNot | BoolAnd | BoolOr => true,
|
||||
IntegerAbs | IntegerMin | IntegerMax | BoolNot | BoolAnd | BoolOr => true,
|
||||
|
||||
// Array/Map read operations (pure - don't mutate)
|
||||
ArrayLength | ArrayGet => true,
|
||||
@ -408,8 +421,8 @@ impl CoreMethodId {
|
||||
ResultIsOk => true,
|
||||
|
||||
// Not yet whitelisted - be conservative
|
||||
StringUpper | StringLower | StringConcat |
|
||||
StringSubstring | StringIndexOf | StringReplace | StringTrim | StringSplit => false,
|
||||
StringUpper | StringLower | StringConcat | StringSubstring | StringIndexOf
|
||||
| StringReplace | StringTrim | StringSplit => false,
|
||||
|
||||
IntegerAbs | IntegerMin | IntegerMax => false,
|
||||
BoolNot | BoolAnd | BoolOr => false,
|
||||
|
||||
@ -3,14 +3,14 @@
|
||||
//! Ring1-Core: core_required Box の Service trait 群。
|
||||
//! Phase 87 CoreBoxId の core_required (6個) 全てをカバー。
|
||||
|
||||
use std::sync::Arc;
|
||||
use crate::runtime::CoreBoxId;
|
||||
use crate::box_trait::NyashBox;
|
||||
use crate::runtime::CoreBoxId;
|
||||
use std::sync::Arc;
|
||||
|
||||
// Phase 96.5: Adapter実装で使用するBox型をトップレベルでimport
|
||||
use crate::box_trait::{BoolBox, IntegerBox, StringBox};
|
||||
use crate::boxes::array::ArrayBox;
|
||||
use crate::boxes::map_box::MapBox;
|
||||
use crate::box_trait::{IntegerBox, StringBox, BoolBox};
|
||||
|
||||
/// StringBox Service trait
|
||||
///
|
||||
@ -155,7 +155,6 @@ impl CoreServices {
|
||||
// Phase 91 では trait が空なので何もしない
|
||||
// Phase 92 以降で各 Service の初期化を検証
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@ -196,20 +195,20 @@ impl IntegerBoxAdapter {
|
||||
|
||||
impl IntegerService for IntegerBoxAdapter {
|
||||
fn add(&self, a: i64, b: i64) -> i64 {
|
||||
a.saturating_add(b) // オーバーフロー対策
|
||||
a.saturating_add(b) // オーバーフロー対策
|
||||
}
|
||||
|
||||
fn sub(&self, a: i64, b: i64) -> i64 {
|
||||
a.saturating_sub(b) // アンダーフロー対策
|
||||
a.saturating_sub(b) // アンダーフロー対策
|
||||
}
|
||||
|
||||
fn mul(&self, a: i64, b: i64) -> i64 {
|
||||
a.saturating_mul(b) // オーバーフロー対策
|
||||
a.saturating_mul(b) // オーバーフロー対策
|
||||
}
|
||||
|
||||
fn div(&self, a: i64, b: i64) -> Option<i64> {
|
||||
if b == 0 {
|
||||
None // ゼロ除算
|
||||
None // ゼロ除算
|
||||
} else {
|
||||
Some(a / b)
|
||||
}
|
||||
@ -259,9 +258,9 @@ impl ArrayBoxAdapter {
|
||||
impl ArrayService for ArrayBoxAdapter {
|
||||
fn len(&self, arr: &dyn NyashBox) -> i64 {
|
||||
arr.as_any()
|
||||
.downcast_ref::<ArrayBox>()
|
||||
.map(|a| a.len() as i64)
|
||||
.unwrap_or(0)
|
||||
.downcast_ref::<ArrayBox>()
|
||||
.map(|a| a.len() as i64)
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
fn get(&self, arr: &dyn NyashBox, index: i64) -> Option<Box<dyn NyashBox>> {
|
||||
@ -271,7 +270,8 @@ impl ArrayService for ArrayBoxAdapter {
|
||||
}
|
||||
|
||||
fn set(&self, arr: &dyn NyashBox, index: i64, value: Box<dyn NyashBox>) -> Result<(), String> {
|
||||
let arr_box = arr.as_any()
|
||||
let arr_box = arr
|
||||
.as_any()
|
||||
.downcast_ref::<ArrayBox>()
|
||||
.ok_or("Not an ArrayBox")?;
|
||||
let index_box = Box::new(IntegerBox::new(index));
|
||||
@ -280,7 +280,8 @@ impl ArrayService for ArrayBoxAdapter {
|
||||
}
|
||||
|
||||
fn push(&self, arr: &dyn NyashBox, value: Box<dyn NyashBox>) -> Result<(), String> {
|
||||
let arr_box = arr.as_any()
|
||||
let arr_box = arr
|
||||
.as_any()
|
||||
.downcast_ref::<ArrayBox>()
|
||||
.ok_or("Not an ArrayBox")?;
|
||||
arr_box.push(value);
|
||||
@ -302,16 +303,17 @@ impl MapBoxAdapter {
|
||||
impl MapService for MapBoxAdapter {
|
||||
fn size(&self, map: &dyn NyashBox) -> i64 {
|
||||
map.as_any()
|
||||
.downcast_ref::<MapBox>()
|
||||
.map(|m| {
|
||||
// MapBox::size() は Box<dyn NyashBox> を返すため、IntegerBox に変換
|
||||
let size_box = m.size();
|
||||
size_box.as_any()
|
||||
.downcast_ref::<IntegerBox>()
|
||||
.map(|i| i.value)
|
||||
.unwrap_or(0)
|
||||
})
|
||||
.unwrap_or(0)
|
||||
.downcast_ref::<MapBox>()
|
||||
.map(|m| {
|
||||
// MapBox::size() は Box<dyn NyashBox> を返すため、IntegerBox に変換
|
||||
let size_box = m.size();
|
||||
size_box
|
||||
.as_any()
|
||||
.downcast_ref::<IntegerBox>()
|
||||
.map(|i| i.value)
|
||||
.unwrap_or(0)
|
||||
})
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
fn has(&self, map: &dyn NyashBox, key: &str) -> bool {
|
||||
@ -321,10 +323,11 @@ impl MapService for MapBoxAdapter {
|
||||
};
|
||||
let key_box = Box::new(StringBox::new(key));
|
||||
let result = map_box.has(key_box);
|
||||
result.as_any()
|
||||
.downcast_ref::<BoolBox>()
|
||||
.map(|b| b.value)
|
||||
.unwrap_or(false)
|
||||
result
|
||||
.as_any()
|
||||
.downcast_ref::<BoolBox>()
|
||||
.map(|b| b.value)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn get(&self, map: &dyn NyashBox, key: &str) -> Option<Box<dyn NyashBox>> {
|
||||
@ -334,7 +337,8 @@ impl MapService for MapBoxAdapter {
|
||||
}
|
||||
|
||||
fn set(&self, map: &dyn NyashBox, key: &str, value: Box<dyn NyashBox>) -> Result<(), String> {
|
||||
let map_box = map.as_any()
|
||||
let map_box = map
|
||||
.as_any()
|
||||
.downcast_ref::<MapBox>()
|
||||
.ok_or("Not a MapBox")?;
|
||||
let key_box = Box::new(StringBox::new(key));
|
||||
@ -461,8 +465,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_array_service_basic_operations() {
|
||||
use crate::boxes::array::ArrayBox;
|
||||
use crate::box_trait::IntegerBox;
|
||||
use crate::boxes::array::ArrayBox;
|
||||
|
||||
let arr = ArrayBox::new();
|
||||
let adapter = ArrayBoxAdapter::new();
|
||||
@ -482,8 +486,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_array_service_set() {
|
||||
use crate::boxes::array::ArrayBox;
|
||||
use crate::box_trait::IntegerBox;
|
||||
use crate::boxes::array::ArrayBox;
|
||||
|
||||
let arr = ArrayBox::new();
|
||||
let adapter = ArrayBoxAdapter::new();
|
||||
@ -502,8 +506,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_map_service_basic_operations() {
|
||||
use crate::boxes::map_box::MapBox;
|
||||
use crate::box_trait::StringBox;
|
||||
use crate::boxes::map_box::MapBox;
|
||||
|
||||
let map = MapBox::new();
|
||||
let adapter = MapBoxAdapter::new();
|
||||
@ -527,15 +531,19 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_map_service_multiple_keys() {
|
||||
use crate::boxes::map_box::MapBox;
|
||||
use crate::box_trait::{IntegerBox, StringBox};
|
||||
use crate::boxes::map_box::MapBox;
|
||||
|
||||
let map = MapBox::new();
|
||||
let adapter = MapBoxAdapter::new();
|
||||
|
||||
// set multiple keys
|
||||
adapter.set(&map, "name", Box::new(StringBox::new("Alice"))).unwrap();
|
||||
adapter.set(&map, "age", Box::new(IntegerBox::new(25))).unwrap();
|
||||
adapter
|
||||
.set(&map, "name", Box::new(StringBox::new("Alice")))
|
||||
.unwrap();
|
||||
adapter
|
||||
.set(&map, "age", Box::new(IntegerBox::new(25)))
|
||||
.unwrap();
|
||||
|
||||
// verify size
|
||||
assert_eq!(adapter.size(&map), 2);
|
||||
@ -556,20 +564,20 @@ mod tests {
|
||||
|
||||
// add
|
||||
assert_eq!(adapter.add(10, 20), 30);
|
||||
assert_eq!(adapter.add(i64::MAX, 1), i64::MAX); // saturating
|
||||
assert_eq!(adapter.add(i64::MAX, 1), i64::MAX); // saturating
|
||||
|
||||
// sub
|
||||
assert_eq!(adapter.sub(20, 10), 10);
|
||||
assert_eq!(adapter.sub(i64::MIN, 1), i64::MIN); // saturating
|
||||
assert_eq!(adapter.sub(i64::MIN, 1), i64::MIN); // saturating
|
||||
|
||||
// mul
|
||||
assert_eq!(adapter.mul(5, 6), 30);
|
||||
assert_eq!(adapter.mul(i64::MAX, 2), i64::MAX); // saturating
|
||||
assert_eq!(adapter.mul(i64::MAX, 2), i64::MAX); // saturating
|
||||
|
||||
// div
|
||||
assert_eq!(adapter.div(20, 5), Some(4));
|
||||
assert_eq!(adapter.div(10, 3), Some(3)); // 整数除算
|
||||
assert_eq!(adapter.div(10, 0), None); // ゼロ除算
|
||||
assert_eq!(adapter.div(10, 3), Some(3)); // 整数除算
|
||||
assert_eq!(adapter.div(10, 0), None); // ゼロ除算
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
//! Deprecation warnings with "warn once" guards
|
||||
use std::sync::OnceLock;
|
||||
use crate::runtime::get_global_ring0;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
fn warn_once(flag: &'static OnceLock<()>, msg: &str) {
|
||||
if flag.get().is_none() {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::runtime::get_global_ring0;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Mutex;
|
||||
use crate::runtime::get_global_ring0;
|
||||
|
||||
static ENABLED: Lazy<bool> =
|
||||
Lazy::new(|| std::env::var("NYASH_LEAK_LOG").unwrap_or_default() == "1");
|
||||
@ -42,9 +42,10 @@ impl Drop for Reporter {
|
||||
if m.is_empty() {
|
||||
return;
|
||||
}
|
||||
get_global_ring0()
|
||||
.log
|
||||
.warn(&format!("[leak] Detected {} non-finalized plugin boxes:", m.len()));
|
||||
get_global_ring0().log.warn(&format!(
|
||||
"[leak] Detected {} non-finalized plugin boxes:",
|
||||
m.len()
|
||||
));
|
||||
for ((ty, id), _) in m.iter() {
|
||||
get_global_ring0().log.warn(&format!(
|
||||
" - {}(id={}) not finalized (missing fini or scope)",
|
||||
|
||||
@ -7,9 +7,6 @@ pub mod core_box_ids; // Phase 87: CoreBoxId/CoreMethodId 型安全enum
|
||||
pub mod core_services; // Phase 91: CoreServices trait 定義
|
||||
pub mod deprecations;
|
||||
pub mod gc;
|
||||
pub mod plugin_host; // Phase 91: PluginHost skeleton
|
||||
pub mod ring0; // Phase 88: Ring0Context - OS API 抽象化レイヤー
|
||||
pub mod runtime_profile; // Phase 109: RuntimeProfile enum (Default/NoFs)
|
||||
pub mod gc_controller;
|
||||
pub mod gc_mode;
|
||||
pub mod gc_trace;
|
||||
@ -19,10 +16,13 @@ pub mod nyash_runtime;
|
||||
pub mod observe; // Lightweight observability flags (OOB etc.)
|
||||
pub mod plugin_config;
|
||||
pub mod plugin_ffi_common;
|
||||
pub mod plugin_host; // Phase 91: PluginHost skeleton
|
||||
pub mod plugin_loader_unified;
|
||||
pub mod plugin_loader_v2;
|
||||
pub mod provider_lock;
|
||||
pub mod provider_verify;
|
||||
pub mod ring0; // Phase 88: Ring0Context - OS API 抽象化レイヤー
|
||||
pub mod runtime_profile; // Phase 109: RuntimeProfile enum (Default/NoFs)
|
||||
pub mod scheduler;
|
||||
pub mod semantics;
|
||||
pub mod unified_registry; // Deprecation warnings with warn-once guards
|
||||
@ -42,14 +42,14 @@ mod tests;
|
||||
pub use box_registry::{get_global_registry, BoxFactoryRegistry, BoxProvider};
|
||||
pub use core_box_ids::{CoreBoxCategory, CoreBoxId, CoreMethodId}; // Phase 87: 型安全enum
|
||||
pub use plugin_config::PluginConfig;
|
||||
pub use ring0::{get_global_ring0, init_global_ring0, Ring0Context}; // Phase 88: Ring0 公開 API
|
||||
pub use runtime_profile::RuntimeProfile; // Phase 109: RuntimeProfile enum
|
||||
pub use plugin_host::CoreInitError; // Phase 92: CoreServices 初期化エラー
|
||||
pub use plugin_loader_unified::{
|
||||
get_global_plugin_host, init_global_plugin_host, MethodHandle, PluginBoxType, PluginHost,
|
||||
PluginLibraryHandle,
|
||||
};
|
||||
pub use plugin_loader_v2::{get_global_loader_v2, init_global_loader_v2, PluginLoaderV2};
|
||||
pub use ring0::{get_global_ring0, init_global_ring0, Ring0Context}; // Phase 88: Ring0 公開 API
|
||||
pub use runtime_profile::RuntimeProfile; // Phase 109: RuntimeProfile enum
|
||||
pub mod cache_versions;
|
||||
pub use gc::{BarrierKind, GcHooks};
|
||||
pub use nyash_runtime::{NyashRuntime, NyashRuntimeBuilder};
|
||||
@ -125,8 +125,8 @@ macro_rules! console_println {
|
||||
/// 3. init_global_ring0() で GLOBAL_RING0 に登録
|
||||
/// 4. PluginHost 初期化時に get_global_ring0() で取得
|
||||
pub fn initialize_runtime(ring0: std::sync::Arc<Ring0Context>) -> Result<(), CoreInitError> {
|
||||
use crate::box_factory::UnifiedBoxRegistry;
|
||||
use crate::box_factory::builtin::BuiltinBoxFactory;
|
||||
use crate::box_factory::UnifiedBoxRegistry;
|
||||
|
||||
// Phase 109/112: Read RuntimeProfile from environment (this layer only)
|
||||
let profile = RuntimeProfile::from_env();
|
||||
|
||||
@ -3,12 +3,12 @@
|
||||
//! Ring1-Core(Box 実装層)の構造定義。
|
||||
//! Phase 92 で UnifiedBoxRegistry と接続予定。
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use std::any::Any;
|
||||
use crate::box_factory::UnifiedBoxRegistry;
|
||||
use crate::runtime::CoreBoxId;
|
||||
use crate::runtime::RuntimeProfile;
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Phase 103: CoreServices Optional化設定
|
||||
///
|
||||
@ -47,7 +47,7 @@ impl CoreServicesConfig {
|
||||
bool_enabled: false,
|
||||
array_enabled: false,
|
||||
map_enabled: false,
|
||||
console_enabled: true, // Console is mandatory
|
||||
console_enabled: true, // Console is mandatory
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -96,8 +96,16 @@ impl std::fmt::Display for CoreInitError {
|
||||
CoreInitError::RegistryEmpty => {
|
||||
write!(f, "UnifiedBoxRegistry is empty")
|
||||
}
|
||||
CoreInitError::InvalidServiceType { box_id, expected, found } => {
|
||||
write!(f, "Invalid service type for {:?}: expected {}, found {}", box_id, expected, found)
|
||||
CoreInitError::InvalidServiceType {
|
||||
box_id,
|
||||
expected,
|
||||
found,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"Invalid service type for {:?}: expected {}, found {}",
|
||||
box_id, expected, found
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -158,7 +166,9 @@ impl PluginHost {
|
||||
|
||||
match provider_lock::set_filebox_provider(provider) {
|
||||
Ok(()) => {
|
||||
ring0.log.debug("[Phase 109] Ring0FsFileIo registered as default FileBox provider");
|
||||
ring0.log.debug(
|
||||
"[Phase 109] Ring0FsFileIo registered as default FileBox provider",
|
||||
);
|
||||
}
|
||||
Err(_) => {
|
||||
// Plugin provider already registered - this is OK (plugin priority)
|
||||
@ -172,7 +182,8 @@ impl PluginHost {
|
||||
if provider_lock::get_filebox_provider().is_none() {
|
||||
return Err(CoreInitError::MissingService {
|
||||
box_id: CoreBoxId::File,
|
||||
hint: "FileBox provider not registered (required for Default profile)".to_string(),
|
||||
hint: "FileBox provider not registered (required for Default profile)"
|
||||
.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -184,7 +195,9 @@ impl PluginHost {
|
||||
let provider = Arc::new(NoFsFileIo);
|
||||
|
||||
let _ = provider_lock::set_filebox_provider(provider);
|
||||
ring0.log.debug("[Phase 109] NoFsFileIo registered for NoFs profile");
|
||||
ring0
|
||||
.log
|
||||
.debug("[Phase 109] NoFsFileIo registered for NoFs profile");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -317,12 +330,11 @@ mod tests {
|
||||
assert_eq!(desc.capabilities.len(), 1);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_core_services_all_fields() {
|
||||
// Phase 94: 実際の registry を使用してテスト
|
||||
use crate::runtime::ring0::default_ring0;
|
||||
use crate::box_factory::builtin::BuiltinBoxFactory;
|
||||
use crate::runtime::ring0::default_ring0;
|
||||
|
||||
let ring0 = Arc::new(default_ring0());
|
||||
let mut registry = UnifiedBoxRegistry::new();
|
||||
@ -341,8 +353,8 @@ mod tests {
|
||||
#[test]
|
||||
fn test_core_services_coverage() {
|
||||
// Phase 94: 実際の registry を使用して全フィールドが存在することを確認
|
||||
use crate::runtime::ring0::default_ring0;
|
||||
use crate::box_factory::builtin::BuiltinBoxFactory;
|
||||
use crate::runtime::ring0::default_ring0;
|
||||
|
||||
let ring0 = Arc::new(default_ring0());
|
||||
let mut registry = UnifiedBoxRegistry::new();
|
||||
@ -410,12 +422,12 @@ mod tests {
|
||||
// FileBox provider が未登録の場合は、CoreBoxId::File のエラーが優先される
|
||||
if let Err(e) = result {
|
||||
let msg = format!("{}", e);
|
||||
eprintln!("Error message: {}", msg); // デバッグ出力
|
||||
eprintln!("Error message: {}", msg); // デバッグ出力
|
||||
assert!(
|
||||
msg.contains("not found in registry") ||
|
||||
msg.contains("creation failed") ||
|
||||
msg.contains("Unknown Box type") ||
|
||||
msg.contains("FileBox provider not registered"),
|
||||
msg.contains("not found in registry")
|
||||
|| msg.contains("creation failed")
|
||||
|| msg.contains("Unknown Box type")
|
||||
|| msg.contains("FileBox provider not registered"),
|
||||
"Error message should contain expected error patterns, got: {}",
|
||||
msg
|
||||
);
|
||||
@ -427,8 +439,8 @@ mod tests {
|
||||
// Phase 107/108: with_core_from_registry() は Ring0FsFileIo を自動登録するため、
|
||||
// FileBox は常に利用可能になる
|
||||
|
||||
use crate::runtime::ring0::default_ring0;
|
||||
use crate::box_factory::builtin::BuiltinBoxFactory;
|
||||
use crate::runtime::ring0::default_ring0;
|
||||
|
||||
let ring0 = Arc::new(default_ring0());
|
||||
let mut registry = UnifiedBoxRegistry::new();
|
||||
@ -438,14 +450,20 @@ mod tests {
|
||||
let result = PluginHost::with_core_from_registry(ring0, ®istry);
|
||||
|
||||
// Phase 107/108: FileBox provider は自動登録されるため、成功するはず
|
||||
assert!(result.is_ok(), "Expected success with auto-registered FileBox provider");
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"Expected success with auto-registered FileBox provider"
|
||||
);
|
||||
|
||||
// Phase 108: 登録された provider は read/write 両対応
|
||||
use crate::runtime::provider_lock;
|
||||
if let Some(provider) = provider_lock::get_filebox_provider() {
|
||||
let caps = provider.caps();
|
||||
assert!(caps.read, "FileBox provider should support read");
|
||||
assert!(caps.write, "FileBox provider should support write (Phase 108)");
|
||||
assert!(
|
||||
caps.write,
|
||||
"FileBox provider should support write (Phase 108)"
|
||||
);
|
||||
} else {
|
||||
panic!("FileBox provider should be registered after with_core_from_registry");
|
||||
}
|
||||
@ -454,8 +472,8 @@ mod tests {
|
||||
#[test]
|
||||
fn test_with_core_from_registry_nofs_filebox_optional() {
|
||||
// Phase 109: NoFs profile では FileBox provider なしで OK
|
||||
use crate::runtime::ring0::default_ring0;
|
||||
use crate::box_factory::builtin::BuiltinBoxFactory;
|
||||
use crate::runtime::ring0::default_ring0;
|
||||
|
||||
let ring0 = Arc::new(default_ring0());
|
||||
let mut registry = UnifiedBoxRegistry::new();
|
||||
@ -471,7 +489,10 @@ mod tests {
|
||||
);
|
||||
|
||||
// Phase 109: FileBox は optional なので、provider なしで成功するはず
|
||||
assert!(result.is_ok(), "Expected success with NoFs profile (FileBox optional)");
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"Expected success with NoFs profile (FileBox optional)"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -500,5 +521,4 @@ mod optional_core_tests {
|
||||
assert!(!config.map_enabled, "map should be disabled");
|
||||
assert!(config.console_enabled, "console must remain enabled");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -12,9 +12,9 @@ use crate::boxes::map_box::MapBox;
|
||||
use crate::boxes::null_box::NullBox;
|
||||
use crate::boxes::result::NyashResultBox;
|
||||
use crate::boxes::token_box::TokenBox;
|
||||
use crate::runtime::get_global_ring0;
|
||||
use crate::runtime::global_hooks;
|
||||
use crate::runtime::modules_registry;
|
||||
use crate::runtime::get_global_ring0;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
@ -210,9 +210,7 @@ fn handle_runtime(
|
||||
match method_name {
|
||||
"checkpoint" => {
|
||||
if crate::config::env::runtime_checkpoint_trace() {
|
||||
get_global_ring0()
|
||||
.log
|
||||
.debug("[runtime.checkpoint] reached");
|
||||
get_global_ring0().log.debug("[runtime.checkpoint] reached");
|
||||
}
|
||||
global_hooks::safepoint_and_poll();
|
||||
Ok(None)
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
use crate::bid::{BidError, BidResult};
|
||||
use crate::box_trait::NyashBox;
|
||||
use crate::runtime::plugin_loader_v2::enabled::PluginLoaderV2;
|
||||
use crate::runtime::get_global_ring0;
|
||||
use crate::runtime::plugin_loader_v2::enabled::PluginLoaderV2;
|
||||
use std::env;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
||||
@ -2,11 +2,11 @@
|
||||
|
||||
use crate::bid::{BidError, BidResult};
|
||||
use crate::box_trait::NyashBox;
|
||||
use crate::runtime::get_global_ring0;
|
||||
use crate::runtime::plugin_loader_v2::enabled::{
|
||||
types::{PluginBoxV2, PluginHandleInner},
|
||||
PluginLoaderV2,
|
||||
};
|
||||
use crate::runtime::get_global_ring0;
|
||||
use std::sync::Arc;
|
||||
|
||||
fn dbg_on() -> bool {
|
||||
|
||||
@ -20,8 +20,8 @@
|
||||
* required_methods = ["length","concat"]
|
||||
*/
|
||||
|
||||
use std::collections::HashMap;
|
||||
use crate::runtime::get_global_ring0;
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn parse_required_methods(spec: &str) -> HashMap<String, Vec<String>> {
|
||||
let mut map = HashMap::new();
|
||||
|
||||
@ -7,7 +7,7 @@ mod std_impls;
|
||||
mod traits;
|
||||
|
||||
pub use errors::{IoError, TimeError};
|
||||
pub use std_impls::{NoopMem, NoFsApi, StdFs, StdIo, StdLog, StdMem, StdThread, StdTime};
|
||||
pub use std_impls::{NoFsApi, NoopMem, StdFs, StdIo, StdLog, StdMem, StdThread, StdTime};
|
||||
pub use traits::{
|
||||
FsApi, FsMetadata, IoApi, LogApi, LogLevel, MemApi, MemStats, ThreadApi, TimeApi,
|
||||
};
|
||||
@ -23,7 +23,7 @@ pub struct Ring0Context {
|
||||
pub io: Arc<dyn IoApi>,
|
||||
pub time: Arc<dyn TimeApi>,
|
||||
pub log: Arc<dyn LogApi>,
|
||||
pub fs: Arc<dyn FsApi>, // Phase 90-A
|
||||
pub fs: Arc<dyn FsApi>, // Phase 90-A
|
||||
pub thread: Arc<dyn ThreadApi>, // Phase 90-D
|
||||
}
|
||||
|
||||
@ -123,12 +123,7 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
fn unsafe_dealloc(ptr: *mut u8, size: usize) {
|
||||
unsafe {
|
||||
std::alloc::dealloc(
|
||||
ptr,
|
||||
std::alloc::Layout::from_size_align_unchecked(size, 1),
|
||||
)
|
||||
}
|
||||
unsafe { std::alloc::dealloc(ptr, std::alloc::Layout::from_size_align_unchecked(size, 1)) }
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -228,13 +223,17 @@ mod tests {
|
||||
#[test]
|
||||
fn test_nofs_api_write_all() {
|
||||
let api = NoFsApi;
|
||||
assert!(api.write_all(std::path::Path::new("/tmp/test.txt"), b"data").is_err());
|
||||
assert!(api
|
||||
.write_all(std::path::Path::new("/tmp/test.txt"), b"data")
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nofs_api_append_all() {
|
||||
let api = NoFsApi;
|
||||
assert!(api.append_all(std::path::Path::new("/tmp/test.txt"), b"data").is_err());
|
||||
assert!(api
|
||||
.append_all(std::path::Path::new("/tmp/test.txt"), b"data")
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -252,6 +251,8 @@ mod tests {
|
||||
#[test]
|
||||
fn test_nofs_api_canonicalize() {
|
||||
let api = NoFsApi;
|
||||
assert!(api.canonicalize(std::path::Path::new("/tmp/test.txt")).is_err());
|
||||
assert!(api
|
||||
.canonicalize(std::path::Path::new("/tmp/test.txt"))
|
||||
.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,8 +125,8 @@ pub struct StdLog;
|
||||
|
||||
impl StdLog {
|
||||
fn should_log(&self, level: LogLevel) -> bool {
|
||||
let min_level_str = std::env::var("NYASH_RING0_LOG_LEVEL")
|
||||
.unwrap_or_else(|_| "INFO".to_string());
|
||||
let min_level_str =
|
||||
std::env::var("NYASH_RING0_LOG_LEVEL").unwrap_or_else(|_| "INFO".to_string());
|
||||
|
||||
let min_level = match min_level_str.to_uppercase().as_str() {
|
||||
"DEBUG" => LogLevel::Debug,
|
||||
@ -139,10 +139,13 @@ impl StdLog {
|
||||
// level の優先度が min_level 以上なら true
|
||||
matches!(
|
||||
(level, min_level),
|
||||
(LogLevel::Error, _) |
|
||||
(LogLevel::Warn, LogLevel::Debug | LogLevel::Info | LogLevel::Warn) |
|
||||
(LogLevel::Info, LogLevel::Debug | LogLevel::Info) |
|
||||
(LogLevel::Debug, LogLevel::Debug)
|
||||
(LogLevel::Error, _)
|
||||
| (
|
||||
LogLevel::Warn,
|
||||
LogLevel::Debug | LogLevel::Info | LogLevel::Warn
|
||||
)
|
||||
| (LogLevel::Info, LogLevel::Debug | LogLevel::Info)
|
||||
| (LogLevel::Debug, LogLevel::Debug)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -167,9 +170,8 @@ pub struct StdFs;
|
||||
|
||||
impl FsApi for StdFs {
|
||||
fn read_to_string(&self, path: &Path) -> Result<String, IoError> {
|
||||
std::fs::read_to_string(path).map_err(|e| {
|
||||
IoError::ReadFailed(format!("read_to_string({}): {}", path.display(), e))
|
||||
})
|
||||
std::fs::read_to_string(path)
|
||||
.map_err(|e| IoError::ReadFailed(format!("read_to_string({}): {}", path.display(), e)))
|
||||
}
|
||||
|
||||
fn read(&self, path: &Path) -> Result<Vec<u8>, IoError> {
|
||||
@ -187,8 +189,8 @@ impl FsApi for StdFs {
|
||||
use std::io::Write;
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.create(true) // 存在しなければ作成
|
||||
.append(true) // append モードで開く
|
||||
.create(true) // 存在しなければ作成
|
||||
.append(true) // append モードで開く
|
||||
.open(path)
|
||||
.map_err(|e| IoError::WriteFailed(format!("append_all({}): {}", path.display(), e)))?;
|
||||
|
||||
@ -201,9 +203,8 @@ impl FsApi for StdFs {
|
||||
}
|
||||
|
||||
fn metadata(&self, path: &Path) -> Result<FsMetadata, IoError> {
|
||||
let meta = std::fs::metadata(path).map_err(|e| {
|
||||
IoError::MetadataFailed(format!("metadata({}): {}", path.display(), e))
|
||||
})?;
|
||||
let meta = std::fs::metadata(path)
|
||||
.map_err(|e| IoError::MetadataFailed(format!("metadata({}): {}", path.display(), e)))?;
|
||||
Ok(FsMetadata {
|
||||
is_file: meta.is_file(),
|
||||
is_dir: meta.is_dir(),
|
||||
@ -273,12 +274,7 @@ mod stdmem_tests {
|
||||
use super::*;
|
||||
|
||||
fn unsafe_dealloc(ptr: *mut u8, size: usize) {
|
||||
unsafe {
|
||||
std::alloc::dealloc(
|
||||
ptr,
|
||||
std::alloc::Layout::from_size_align_unchecked(size, 1),
|
||||
)
|
||||
}
|
||||
unsafe { std::alloc::dealloc(ptr, std::alloc::Layout::from_size_align_unchecked(size, 1)) }
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -320,6 +316,9 @@ mod stdmem_tests {
|
||||
fn test_noopmem_compatibility() {
|
||||
let mem = NoopMem;
|
||||
let ptr = mem.alloc(1024);
|
||||
assert!(ptr.is_null(), "NoopMem should still return null for compatibility");
|
||||
assert!(
|
||||
ptr.is_null(),
|
||||
"NoopMem should still return null for compatibility"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,9 +98,10 @@ impl Scheduler for SingleThreadScheduler {
|
||||
}
|
||||
}
|
||||
if trace {
|
||||
get_global_ring0()
|
||||
.log
|
||||
.debug(&format!("[SCHED] poll moved={} ran={} budget={}", moved, ran, budget));
|
||||
get_global_ring0().log.debug(&format!(
|
||||
"[SCHED] poll moved={} ran={} budget={}",
|
||||
moved, ran, budget
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::{BoxFactoryRegistry, PluginConfig};
|
||||
|
||||
|
||||
use crate::box_trait::{NyashBox, StringBox};
|
||||
use crate::runtime::box_registry::BoxProvider;
|
||||
|
||||
|
||||
@ -6,10 +6,10 @@
|
||||
//! which VM can call via `call_function_by_name`.
|
||||
//! - Versioning is sourced from `cache_versions` using label `BoxRef:{class}`.
|
||||
|
||||
use crate::runtime::get_global_ring0;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use crate::runtime::get_global_ring0;
|
||||
|
||||
/// Target of a method thunk
|
||||
#[derive(Clone, Debug)]
|
||||
@ -133,9 +133,10 @@ pub fn get_or_create_type_meta(class_name: &str) -> Arc<TypeMeta> {
|
||||
/// Dump registry contents for diagnostics
|
||||
pub fn dump_registry() {
|
||||
let map = TYPE_META_REGISTRY.lock().unwrap();
|
||||
get_global_ring0()
|
||||
.log
|
||||
.debug(&format!("[REG] TypeMeta registry dump ({} types)", map.len()));
|
||||
get_global_ring0().log.debug(&format!(
|
||||
"[REG] TypeMeta registry dump ({} types)",
|
||||
map.len()
|
||||
));
|
||||
for (name, meta) in map.iter() {
|
||||
let tbl = meta.thunks.read().ok();
|
||||
let len = tbl.as_ref().map(|t| t.len()).unwrap_or(0);
|
||||
|
||||
Reference in New Issue
Block a user