Phase 33 NORM canon test: enforce normalized dev route for P1/P2/JP mini

This commit is contained in:
nyash-codex
2025-12-11 20:54:33 +09:00
parent 59a985b7fa
commit af6f95cd4b
170 changed files with 4423 additions and 1897 deletions

View File

@ -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};

View File

@ -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,

View File

@ -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]

View File

@ -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() {

View File

@ -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)",

View File

@ -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();

View File

@ -3,12 +3,12 @@
//! Ring1-CoreBox 実装層)の構造定義。
//! 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, &registry);
// 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");
}
}

View File

@ -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)

View File

@ -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;

View File

@ -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 {

View File

@ -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();

View File

@ -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());
}
}

View File

@ -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"
);
}
}

View File

@ -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
));
}
}
}

View File

@ -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;

View File

@ -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);